diff options
Diffstat (limited to 'advtrains_interlocking/route_ui.lua')
-rw-r--r-- | advtrains_interlocking/route_ui.lua | 254 |
1 files changed, 218 insertions, 36 deletions
diff --git a/advtrains_interlocking/route_ui.lua b/advtrains_interlocking/route_ui.lua index 1999941..9ecc947 100644 --- a/advtrains_interlocking/route_ui.lua +++ b/advtrains_interlocking/route_ui.lua @@ -1,8 +1,12 @@ -- route_ui.lua -- User interface for showing and editing routes +-- Get current translator +local S = advtrains.interlocking.translate + local atil = advtrains.interlocking local ildb = atil.db +local F = advtrains.formspec -- TODO duplicate local lntrans = { "A", "B" } @@ -10,12 +14,13 @@ local function sigd_to_string(sigd) return minetest.pos_to_string(sigd.p).." / "..lntrans[sigd.s] end +-- indexed by pname +local sel_rpartcache = {} - -function atil.show_route_edit_form(pname, sigd, routeid) +function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx) if not minetest.check_player_privs(pname, {train_operator=true, interlocking=true}) then - minetest.chat_send_player(pname, "Insufficient privileges to use this!") + minetest.chat_send_player(pname, S("Insufficient privileges to use this!")) return end @@ -24,80 +29,171 @@ function atil.show_route_edit_form(pname, sigd, routeid) local route = tcbs.routes[routeid] if not route then return end - local form = "size[9,10]label[0.5,0.2;Route overview]" - form = form.."field[0.8,1.2;6.5,1;name;Route name;"..minetest.formspec_escape(route.name).."]" - form = form.."button[7.0,0.9;1.5,1;setname;Set]" + local form = "size[9,11]label[0.5,0.2;"..S("Route overview").."]" + form = form.."field[0.8,1.2;6.5,1;name;"..S("Route name")..";"..minetest.formspec_escape(route.name).."]" + form = form.."button[7.0,0.9;1.5,1;setname;"..S("Set").."]" -- construct textlist for route information local tab = {} - local function itab(t) + local tabref = {} + local function itab(rseg, t, rty, rpara) tab[#tab+1] = minetest.formspec_escape(string.gsub(t, ",", " ")) + tabref[#tab] = { [rty] = true, param = rpara, seg = rseg, idx = #tab } end - itab("TCB "..sigd_to_string(sigd).." ("..tcbs.signal_name..") Route #"..routeid) + itab(1, "("..(tcbs.signal_name or "+")..") Route #"..routeid, "signal", sigd) -- this code is partially copy-pasted from routesetting.lua -- we start at the tc designated by signal local c_sigd = sigd local i = 1 - local c_tcbs, c_ts_id, c_ts, c_rseg, c_lckp + local c_tcbs, c_ts_id, c_ts, c_rseg while c_sigd and i<=#route do c_tcbs = ildb.get_tcbs(c_sigd) if not c_tcbs then - itab("-!- No TCBS at "..sigd_to_string(c_sigd)..". Please reconfigure route!") + itab(i, "-!- "..S("TCB at @1 is missing", sigd_to_string(c_sigd)), "err", nil) break end c_ts_id = c_tcbs.ts_id if not c_ts_id then - itab("-!- No track section adjacent to "..sigd_to_string(c_sigd)..". Please reconfigure route!") + itab(i, "-!- "..S("Track section after @1 missing", sigd_to_string(c_sigd)), "err", nil) break end c_ts = ildb.get_ts(c_ts_id) c_rseg = route[i] - c_lckp = {} - itab(""..i.." Entry "..sigd_to_string(c_sigd).." -> Sec. "..(c_ts and c_ts.name or "-").." -> Exit "..(c_rseg.next and sigd_to_string(c_rseg.next) or "END")) + local signame = "-" + if c_tcbs and c_tcbs.signal then signame = c_tcbs.signal_name or "o" end + itab(i, ""..i.." "..sigd_to_string(c_sigd).." ("..signame..")", "signal", c_sigd) + itab(i, "= "..(c_ts and c_ts.name or c_ts_id).." ="..(c_rseg.call_on and " [CO]" or ""), "section", c_ts_id) if c_rseg.locks then for pts, state in pairs(c_rseg.locks) do - local pos = minetest.string_to_pos(pts) - itab(" Lock: "..pts.." -> "..state) + local pos = advtrains.decode_pos(pts) + itab(i, "L "..pts.." -> "..state, "lock", pos) if not advtrains.is_passive(pos) then - itab("-!- No passive component at "..pts..". Please reconfigure route!") + itab(i, "-!- "..S("Turnout/component missing at @1", minetest.pos_to_string(pos)), "err", nil) break end end end + -- sanity check, is section at next the same as the current? + local nvar = c_rseg.next + if nvar then + local re_tcbs = ildb.get_tcbs({p = nvar.p, s = (nvar.s==1) and 2 or 1}) + if not re_tcbs then + itab(i, "-!- "..S("TCB at @1 is missing", minetest.pos_to_string(nvar.p)), "err", nil) + break + elseif not re_tcbs.ts_id then + itab(i, "-!- "..S("TCB at @1 is not assigned to previous track section", minetest.pos_to_string(nvar.p)), "err", nil) + break + elseif re_tcbs.ts_id~=c_ts_id then + itab(i, "-!- "..S("TCB at @1 has different section than previous TCB", minetest.pos_to_string(nvar.p)), "err", nil) + break + end + end -- advance - c_sigd = c_rseg.next + c_sigd = nvar i = i + 1 end if c_sigd then local e_tcbs = ildb.get_tcbs(c_sigd) - itab("Route end: "..sigd_to_string(c_sigd).." ("..(e_tcbs and e_tcbs.signal_name or "-")..")") + local signame = "-" + if e_tcbs and e_tcbs.signal then signame = e_tcbs.signal_name or "o" end + itab(i, "E "..sigd_to_string(c_sigd).." ("..signame..")", "end", c_sigd) + else + itab(i, "E (none)", "end", nil) + end + + itab(i, S("(More Options)"), "advanced", nil) + + if not sel_rpartidx then sel_rpartidx = 1 end + form = form.."textlist[0.5,2;3.5,3.9;routelog;"..table.concat(tab, ",")..";"..(sel_rpartidx or 1)..";false]" + + -- to the right of rtelog, controls are displayed for the thing in focus + -- What is in focus is determined by the parameter sel_rpartidx + + local sel_rpart = tabref[sel_rpartidx] + --atdebug("sel rpart",sel_rpart) + + if sel_rpart and sel_rpart.signal then + -- get TCBS here and rseg selected + local s_tcbs = ildb.get_tcbs(sel_rpart.param) + local rseg = route[sel_rpart.seg] + -- main aspect list + local signalpos = s_tcbs and s_tcbs.signal + if signalpos and rseg then + form = form..F.label(4.5, 2, S("Signal Aspect:")) + local ndef = signalpos and advtrains.ndb.get_ndef(signalpos) + if ndef and ndef.advtrains and ndef.advtrains.main_aspects then + local entries = { S("<Default Aspect>") } + local sel = 1 + for i, mae in ipairs(ndef.advtrains.main_aspects) do + entries[i+1] = mae.description + if mae.name == rseg.main_aspect then + sel = i+1 + end + end + form = form..F.dropdown(4.5, 3.0, 4, "sa_main_aspect", entries, sel, true) + end + -- checkbox for assign distant signal + local assign_dst = rseg.assign_dst + if assign_dst == nil then + assign_dst = (sel_rpart.seg~=1) -- special behavior when assign_dst is nil (and not false): + -- defaults to false for the very first signal and true for all others (= minimal user configuration overhead) + -- Note: on save, the value will be fixed at either false or true + end + form = form..string.format("checkbox[4.5,4.0;sa_distant;"..S("Announce distant signal")..";%s]", assign_dst) + else + form = form..F.label(4.5, 2, S("No Signal at this TCB")) + end + elseif sel_rpart and sel_rpart.section then + local rseg = route[sel_rpart.seg] + if rseg then + form = form..F.label(4.5, 2, S("Section Options:")) + -- checkbox for call-on + form = form..string.format("checkbox[4.5,4.0;se_callon;"..S("Call-on (section may be occupied)")..";%s]", rseg.call_on) + end + elseif sel_rpart and sel_rpart.advanced then + form = form..F.label(4.5, 2, S("Advanced Options:")) + -- checkbox for call-on + form = form..string.format("checkbox[4.5,4.0;ad_use_rscache;"..S("Auto lock turnouts")..";%s]", route.use_rscache) + elseif sel_rpart and sel_rpart.err then + form = form.."textarea[4.5,2.5;4,4;errorta;"..S("Error:")..";"..tab[sel_rpartidx].."]" else - itab("Route ends on dead-end") + form = form..F.label(4.5, 2, S("<< Select a route part to edit options")) end - form = form.."textlist[0.5,2;7.75,3.9;rtelog;"..table.concat(tab, ",").."]" + form = form.."button[0.5,6;1,1;prev;<<<]" + form = form.."button[1.5,6;1,1;back;"..routeid.."/"..#tcbs.routes.."]" + form = form.."button[2.5,6;1,1;next;>>>]" + - form = form.."button[0.5,6;3,1;back;<<< Back to signal]" - form = form.."button[4.5,6;2,1;aspect;Signal Aspect]" - form = form.."button[6.5,6;2,1;delete;Delete Route]" + --if route.smartroute_generated or route.default_autoworking then + -- form = form.."button[3.5,6;2,1;noautogen;Clr Autogen]" + --end + form = form.."button[5.5,6;3,1;delete;"..S("Delete Route").."]" + form = form.."button[0.5,7;3,1;back;"..S("Back to signal").."]" + form = form.."button[3.5,7;2,1;clone;"..S("Clone Route").."]" + form = form.."button[5.5,7;3,1;newfrom;"..S("New From Route").."]" --atdebug(route.ars) form = form.."style[ars;font=mono]" - form = form.."textarea[0.8,7.3;5,3;ars;ARS Rule List;"..atil.ars_to_text(route.ars).."]" - form = form.."button[5.5,7.23;3,1;savears;Save ARS List]" + form = form.."textarea[0.8,8.3;5,3;ars;"..S("ARS Rule List")..";"..atil.ars_to_text(route.ars).."]" + form = form.."button[5.5,8.23;3,1;savears;"..S("Save ARS List").."]" - minetest.show_formspec(pname, "at_il_routeedit_"..minetest.pos_to_string(sigd.p).."_"..sigd.s.."_"..routeid, form) - + local formname = "at_il_routeedit_"..minetest.pos_to_string(sigd.p).."_"..sigd.s.."_"..routeid + minetest.show_formspec(pname, formname, form) + -- record selected entry from routelog for receive fields callback + sel_rpartcache[pname] = sel_rpart end minetest.register_on_player_receive_fields(function(player, formname, fields) local pname = player:get_player_name() + -- retreive sel_rpart from the cache in any case and clear it out + local sel_rpart = sel_rpartcache[pname] if not minetest.check_player_privs(pname, {train_operator=true, interlocking=true}) then return end @@ -118,26 +214,93 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) local route = tcbs.routes[routeid] if not route then return end + if fields.prev then + atil.show_route_edit_form(pname, sigd, routeid - 1) + return + end + if fields.next then + atil.show_route_edit_form(pname, sigd, routeid + 1) + return + end + if fields.setname and fields.name then route.name = fields.name end - if fields.aspect then - local suppasp = advtrains.interlocking.signal_get_supported_aspects(tcbs.signal) - - local callback = function(pname, asp) - route.aspect = asp - advtrains.interlocking.show_route_edit_form(pname, sigd, routeid) + if fields.sa_main_aspect and sel_rpart and sel_rpart.signal then + local idx = tonumber(fields.sa_main_aspect) + -- get TCBS here and rseg selected + local s_tcbs = ildb.get_tcbs(sel_rpart.param) + local rseg = route[sel_rpart.seg] + -- main aspect list + local signalpos = s_tcbs and s_tcbs.signal + if rseg then + rseg.main_aspect = nil + if idx > 1 then + local ndef = signalpos and advtrains.ndb.get_ndef(signalpos) + if ndef and ndef.advtrains and ndef.advtrains.main_aspects then + rseg.main_aspect = ndef.advtrains.main_aspects[idx - 1].name + end + end end - - advtrains.interlocking.show_signal_aspect_selector(pname, suppasp, route.name, callback, route.aspect or advtrains.interlocking.GENERIC_FREE) - return end + if fields.sa_distant and sel_rpart and sel_rpart.signal then + local rseg = route[sel_rpart.seg] + if rseg then + rseg.assign_dst = minetest.is_yes(fields.sa_distant) + end + end + if fields.se_callon and sel_rpart and sel_rpart.section then + local rseg = route[sel_rpart.seg] + if rseg then + rseg.call_on = minetest.is_yes(fields.se_callon) + -- reshow form to update CO marker + atil.show_route_edit_form(pname, sigd, routeid, sel_rpart.idx) + return + end + end + if fields.ad_use_rscache then + route.use_rscache = minetest.is_yes(fields.ad_use_rscache) + end + + --if fields.noautogen then + -- route.smartroute_generated = nil + -- route.default_autoworking = nil + -- -- reshow form for the button to disappear + -- atil.show_route_edit_form(pname, sigd, routeid, sel_rpart and sel_rpart.idx) + -- return + --end + if fields.delete then -- if something set the route in the meantime, make sure this doesn't break. atil.route.update_route(sigd, tcbs, nil, true) table.remove(tcbs.routes, routeid) advtrains.interlocking.show_signalling_form(sigd, pname) + -- cleanup + sel_rpartcache[pname] = nil + return + end + + if fields.clone then + -- if something set the route in the meantime, make sure this doesn't break. + atil.route.update_route(sigd, tcbs, nil, true) + local rcopy = table.copy(route) + rcopy.name = route.name.."_copy" + rcopy.smartroute_generated = nil + table.insert(tcbs.routes, routeid+1, rcopy) + advtrains.interlocking.show_signalling_form(sigd, pname) + -- cleanup + sel_rpartcache[pname] = nil + return + end + + if fields.newfrom then + advtrains.interlocking.init_route_prog(pname, sigd, route) + minetest.close_formspec(pname, formname) + tcbs.ars_ignore_next = nil + -- cleanup + sel_rpartcache[pname] = nil + return end if fields.ars and fields.savears then @@ -147,6 +310,25 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) if fields.back then advtrains.interlocking.show_signalling_form(sigd, pname) + -- cleanup + sel_rpartcache[pname] = nil + return + end + + -- if an entry was selected in the textlist (and its not the current one) update the form + if fields.routelog then + local prev_idx = sel_rpart and sel_rpart.idx or 1 + local tev = minetest.explode_textlist_event(fields.routelog) + local new_idx = tev and tev.index + if new_idx and new_idx ~= prev_idx then + atil.show_route_edit_form(pname, sigd, routeid, new_idx) + return + end + end + + if fields.quit then + -- cleanup + sel_rpartcache[pname] = nil end end |