diff --git a/lcdlib/init.lua b/lcdlib/init.lua index ef14d6f..ead84c6 100644 --- a/lcdlib/init.lua +++ b/lcdlib/init.lua @@ -182,10 +182,15 @@ function lcdlib.make_multiline_texture(font_name, text, width, height, local lines = {} local textheight = 0 local y, w, h + h = get_font(font_name).height for num, line in pairs(split_lines(text, maxlines)) do - w, h = lcdlib.get_text_size(font_name, line) - lines[num] = { text = line, width = w, height = h, } + if line:byte(1) == 60 then -- '<' + lines[num] = { text = line:sub(2,-1), width = width - 4, height = h, } + else + w, h = lcdlib.get_text_size(font_name, line) + lines[num] = { text = line, width = w, height = h, } + end textheight = textheight + h end diff --git a/releasenotes.md b/releasenotes.md index 0e2f7c3..072ad0c 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -2,6 +2,17 @@ +## V1.16.4 (2018-09-26) + + +### Additions +- Stopwatch function to SmartLine Controller added +- Display supports now left oriented text outputs via prefix '<' + +### Fixes +- Owner bugfix for the SmartLine Controller + + ## V1.16.3 (2018-09-26) diff --git a/smartline/icta/controller.lua b/smartline/icta/controller.lua index dd3720e..e7a86f0 100644 --- a/smartline/icta/controller.lua +++ b/smartline/icta/controller.lua @@ -39,7 +39,7 @@ local function integer(s, min, max) return min end -local sOUTPUT = "Edit commands" +local sOUTPUT = "Edit commands (see help)" local Cache = {} local FS_DATA = gen_table(smartline.NUM_RULES, {}) @@ -71,6 +71,22 @@ end -- env.blocked[1] = false -- end +-- -- Callback variant +-- if env.blocked[1] == false and env.ticks % == 0 then +-- env.result[1], env.blocked[1] = +-- if env.blocked[1] then +-- env.timer[1] = env.ticks + +-- end +-- env.conditions[1] = env.blocked[1] +-- else +-- env.conditions[1] = false +-- end +-- if env.blocked[1] and env.timer[1] == env.ticks then +-- +-- env.blocked[1] = false +-- end + + -- cyclic execution local TemplCyc = [[ -- Rule # @@ -109,6 +125,24 @@ if env.blocked[#] and env.timer[#] == env.ticks then end ]] +-- event based execution of callback function +local TemplEvtClbk = [[ +-- Rule # +if env.blocked[#] == false and env.event then + env.result[#], env.blocked[#] = %s(env, %s) + if env.blocked[#] then + env.timer[#] = env.ticks + %s + end + env.condition[#] = env.blocked[#] +else + env.condition[#] = false +end +if env.blocked[#] and env.timer[#] == env.ticks then + %s + env.blocked[#] = false +end +]] + -- generate the Lua code from the NUM_RULES rules local function generate(pos, meta, environ) local fs_data = minetest.deserialize(meta:get_string("fs_data")) or FS_DATA @@ -124,7 +158,12 @@ local function generate(pos, meta, environ) -- add rule number local s if cycle == 0 then -- event? - s = string.format(TemplEvt, cond, result, after, actn) + if result then + s = string.format(TemplEvt, cond, result, after, actn) + else -- callback function + local data = dump(fs_data[idx].cond) + s = string.format(TemplEvtClbk, cond, data, after, actn) + end else -- cyclic s = string.format(TemplCyc, cycle, cond, result, after, actn) end @@ -216,7 +255,8 @@ local function start_controller(pos, meta) if compile(pos, meta, number) then meta:set_int("state", tubelib.RUNNING) minetest.get_node_timer(pos):start(1) - meta:set_string("formspec", smartline.formspecOutput(meta)) + local fs_data = minetest.deserialize(meta:get_string("fs_data")) or FS_DATA + meta:set_string("formspec", smartline.formspecRules(meta, fs_data, sOUTPUT)) meta:set_string("infotext", "Controller "..number..": running") return true end @@ -280,7 +320,9 @@ local function on_receive_fields(pos, formname, fields, player) if not player or not player:is_player() then return end - local readonly = player:get_player_name() ~= owner + if player:get_player_name() ~= owner then + return + end --print("fields", dump(fields)) if fields.quit then -- cancel button @@ -290,18 +332,14 @@ local function on_receive_fields(pos, formname, fields, player) meta:set_string("notes", fields.notes) end if fields.go then - if not readonly then - local fs_data = minetest.deserialize(meta:get_string("fs_data")) or FS_DATA - local output = smartline.edit_command(fs_data, fields.cmnd) - stop_controller(pos, meta) - meta:set_string("formspec", smartline.formspecRules(meta, fs_data, output)) - meta:set_string("fs_data", minetest.serialize(fs_data)) - end + local fs_data = minetest.deserialize(meta:get_string("fs_data")) or FS_DATA + local output = smartline.edit_command(fs_data, fields.cmnd) + stop_controller(pos, meta) + meta:set_string("formspec", smartline.formspecRules(meta, fs_data, output)) + meta:set_string("fs_data", minetest.serialize(fs_data)) end if fields._type_ == "main" then - if not readonly then - smartline.store_main_form_data(meta, fields) - end + smartline.store_main_form_data(meta, fields) local key = smartline.main_form_button_pressed(fields) if key then -- store data before going into sub-menu @@ -438,9 +476,10 @@ minetest.register_craft({ local function set_input(pos, own_number, rmt_number, val) if rmt_number then if Cache[own_number] and Cache[own_number].env.input then - Cache[own_number].env.input[rmt_number] = val - -- only two events per second local t = minetest.get_us_time() + Cache[own_number].env.input[rmt_number] = val + Cache[own_number].env.last_event = t + -- only two events per second if not Cache[own_number].last_event or Cache[own_number].last_event < t then minetest.after(0.01, on_timer, pos, -1) Cache[own_number].last_event = t + 500000 -- add 500 ms @@ -453,10 +492,11 @@ tubelib.register_node("smartline:controller2", {}, { on_recv_message = function(pos, topic, payload) local meta = minetest.get_meta(pos) local number = meta:get_string("number") + local state = meta:get_int("state") - if topic == "on" then + if state == tubelib.RUNNING and topic == "on" then set_input(pos, number, payload, topic) - elseif topic == "off" then + elseif state == tubelib.RUNNING and topic == "off" then set_input(pos, number, payload, topic) elseif topic == "state" then local state = meta:get_int("state") diff --git a/smartline/icta/stopwatch.lua b/smartline/icta/stopwatch.lua new file mode 100644 index 0000000..67d18fd --- /dev/null +++ b/smartline/icta/stopwatch.lua @@ -0,0 +1,130 @@ +--[[ + + ICTA Controller + =============== + + Part of the SmartLine mod + + Copyright (C) 2018 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + stopwatch.lua + Start/stop the watch with an on/off commands. + The player name clicking the stop is stored in addition. + +]]-- + +local sl = smartline + +local function retrieve_clicker_name(number) + local pos = tubelib.get_node_info(number).pos + if pos then + local meta = minetest.get_meta(pos) + return meta:get_string("clicker_name") or "" + end + return "" +end + +-- env = { +-- event = , +-- last_event = -- last event time +-- ticks = , +-- timer = gen_table(8, 0), +-- blocked = gen_table(8, false), +-- result = gen_table(8, false), +-- condition = gen_table(8, false), +-- input = , -- node number is key +-- number = , +-- owner = , +-- }, +-- +-- return cond_result, trigger_action +function smartline.stopwatch(env, data) + if env.input[data.number] == "on" then + env.time = env.last_event + if not env.highscore then + env.highscore = 99999 + end + return nil, false + else + local time = (env.last_event - env.time) / 1000000 + local name = retrieve_clicker_name(data.number) + env.highscore = math.min(time, env.highscore) + local s1 = string.format("%2.1f s", time) + local s2 = string.format("%2.1f s", env.highscore) + env.stopwatch_result = {s1, s2, name} + return nil, true + end +end + +smartline.icta_register_condition("stopwatch", { + title = "stopwatch", + formspec = { + { + type = "numbers", + name = "number", + label = "Switch number", + default = "", + }, + { + type = "label", + name = "lbl", + label = "Hint: Stop the time between switching on\nand switching off of the connected switch.", + }, + }, + code = function(data, environ) + return "smartline.stopwatch" + end, + button = function(data, environ) + return 'stopwatch('..sl.fmt_number(data.number)..')' + end, +}) + +smartline.icta_register_action("stopwatch", { + title = "stopwatch", + formspec = { + { + type = "numbers", + name = "number", + label = "Display number", + default = "", + }, + { + type = "textlist", + name = "row", + label = "Display line", + choices = "1,2,3,4,5,6,7,8,9", + default = "1", + }, + { + type = "ascii", + name = "text", + label = "label", + default = "", + }, + { + type = "textlist", + name = "type", + label = "type", + choices = "time,highscore,name", + default = "time", + }, + { + type = "label", + name = "lbl", + label = "Hint: Display number for the output\nof time, highscore and player name.", + }, + }, + button = function(data, environ) + return "lcd("..sl.fmt_number(data.number)..","..data.row..","..data.type..')' + end, + code = function(data, environ) + local idx = ({time=1, highscore= 2, name=3})[data.type] + local s1 = string.format('local payload = {row = %s, str = "%s "..env.stopwatch_result['..idx..']}', data.row, smartline.escape(data.text)) + local s2 = string.format('tubelib.send_message("%s", "%s", nil, "row", payload)', data.number, environ.owner) + return s1.."\n\t"..s2 + end, +}) diff --git a/smartline/init.lua b/smartline/init.lua index 723cbfc..32b13fb 100644 --- a/smartline/init.lua +++ b/smartline/init.lua @@ -33,3 +33,4 @@ dofile(MP.."/icta/commands.lua") dofile(MP.."/icta/edit.lua") dofile(MP.."/icta/battery.lua") dofile(MP.."/icta/balancer.lua") +dofile(MP.."/icta/stopwatch.lua")