Add WIP digistuff touchscreen exporting

This commit is contained in:
luk3yx 2020-10-21 18:37:38 +13:00
parent 3c52ddff9b
commit c01a5fa734
6 changed files with 161 additions and 30 deletions

View File

@ -22,6 +22,8 @@ default (dynamically loaded when required).
if you plan to import them again. if you plan to import them again.
- The ability to load existing formspecs (provided they are version 2 or - The ability to load existing formspecs (provided they are version 2 or
above). above).
- The ability to export to (but not import from) digistuff touchscreen
formspecs.
## Limitations ## Limitations

111
digistuff_ts.lua Normal file
View File

@ -0,0 +1,111 @@
--
-- Formspec AST to digistuff touchscreen converter
--
-- Copyright © 2020 by luk3yx.
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU Affero General Public License as
-- published by the Free Software Foundation, either version 3 of the
-- License, or (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU Affero General Public License for more details.
--
-- You should have received a copy of the GNU Affero General Public License
-- along with this program. If not, see <https://www.gnu.org/licenses/>.
--
local basic_types = {}
for _, t in ipairs({'image', 'field', 'pwdfield', 'textarea', 'label',
'vertlabel', 'button', 'button_exit'}) do
basic_types[t] = true
end
local function export(tree, backport_func)
tree = formspec_ast.flatten(tree)
-- Modify box nodes before calling backport_func() to fix alignment
for node in formspec_ast.find(tree, 'box') do
-- Boxes can be partially emulated with images.
node.type = 'image'
node.texture_name = 'halo.png^[colorize:' .. node.color
node.color = nil
end
if backport_func then
tree = backport_func(tree)
end
local fs_v2 = (tree.formspec_version or 1) >= 2
tree.formspec_version = nil
if tree[1] and tree[1].type == 'size' then
table.remove(tree, 1)
end
for _, node in ipairs(tree) do
if node.type == 'dropdown' or node.type == 'textlist' then
node.selected_id, node.selected_idx = node.selected_idx, nil
node.choices, node.item = node.item, nil
-- Later versions of the digustuff mod require a height field even
-- for formspec version 1 (breaking dropdowns on older clients).
node.h = node.h or 0.81
elseif node.type == 'image_button' or
node.type == 'image_button_exit' then
node.image, node.texture_name = node.texture_name, nil
elseif not basic_types[node.type] then
return nil, 'Unsupported node type: ' .. node.type
end
if not node.command then
node.command = 'add' .. node.type
end
node.type = nil
for _, i in ipairs({"x", "y", "w", "h"}) do
if node[i] then
node[i:upper()] = node[i]
node[i] = nil
end
end
end
table.insert(tree, 1, {command = 'clear'})
table.insert(tree, 2, {command = 'realcoordinates', enabled = fs_v2})
return tree
end
local function very_basic_dump(obj)
local obj_type = type(obj)
if obj_type == 'string' then
return ('%q'):format(obj)
elseif obj_type ~= 'table' then
return tostring(obj)
end
local t = {}
for k, v in pairs(obj) do
if type(k) ~= 'string' or not k:match('^[A-Za-z_]+$') then
k = '[' .. very_basic_dump(k) .. ']'
end
local line = k .. ' = ' .. very_basic_dump(v)
if k == 'command' then
table.insert(t, 1, line)
else
table.insert(t, line)
end
end
return '{' .. table.concat(t, ', ') .. '}'
end
local function export_string(...)
local res, err = export(...)
if not res then
return nil, err
end
for k, v in ipairs(res) do
res[k] = very_basic_dump(v)
end
return '{' .. table.concat(res, ',\n') .. '}'
end
return export, export_string

View File

@ -74,7 +74,7 @@ fixers.item_image = fixers.image
function fixers.button(elem) function fixers.button(elem)
elem.type = 'image_' .. elem.type elem.type = 'image_' .. elem.type
elem.texture_name = '' elem.texture_name = 'blank.png'
return fixers.image_button(elem) return fixers.image_button(elem)
end end
fixers.button_exit = fixers.button fixers.button_exit = fixers.button

View File

@ -4,7 +4,7 @@
<meta http-equiv="content-type" content="text/html;charset=utf-8" /> <meta http-equiv="content-type" content="text/html;charset=utf-8" />
<link rel="stylesheet" type="text/css" href="style.css" /> <link rel="stylesheet" type="text/css" href="style.css" />
<script src="https://unpkg.com/fengari-web/dist/fengari-web.js"></script> <script src="https://unpkg.com/fengari-web/dist/fengari-web.js"></script>
<script type="application/lua" src="index.lua?rev=3"></script> <script type="application/lua" src="index.lua?rev=4"></script>
<style> <style>
body { body {
background: #8CBAFA; background: #8CBAFA;

View File

@ -18,9 +18,11 @@
-- --
-- Load the renderer -- Load the renderer
dofile('renderer.lua?rev=3') dofile('renderer.lua?rev=4')
local formspec_escape = formspec_ast.formspec_escape local formspec_escape = formspec_ast.formspec_escape
local _, digistuff_ts_export = dofile('digistuff_ts.lua?rev=4')
-- Show the properties list -- Show the properties list
local properties_elem local properties_elem
local function get_properties_list(list_name) local function get_properties_list(list_name)
@ -132,10 +134,10 @@ local function show_properties(elem, node)
local formspec = draw_elements_list(elem) .. local formspec = draw_elements_list(elem) ..
'label[0.25,2.5;Properties for ' .. formspec_escape(node.type) .. ']' 'label[0.25,2.5;Properties for ' .. formspec_escape(node.type) .. ']'
local y = 3.5 local y = 3.5
for k, v in pairs(node) do for k_, v in pairs(node) do
if k == 'type' or k == '_transient' then goto continue end if k_ == 'type' or k_ == '_transient' then goto continue end
local k = k local k = k_
local value_type = type(v) local value_type = type(v)
if k == 'opt' or k == 'props' then if k == 'opt' or k == 'props' then
assert(value_type == 'table') assert(value_type == 'table')
@ -143,7 +145,8 @@ local function show_properties(elem, node)
formspec_escape(get_property_name(k)) .. ' (map)]' formspec_escape(get_property_name(k)) .. ' (map)]'
y = y + 0.1 y = y + 0.1
local i = 0 local i = 0
for prop, value in pairs(v) do for prop_, value in pairs(v) do
local prop = prop_
i = i + 1 i = i + 1
formspec = formspec .. 'label[0.4,' .. y + 0.3 .. ';•]' .. formspec = formspec .. 'label[0.4,' .. y + 0.3 .. ';•]' ..
'field[0.7,' .. y .. ';1.95,0.6;' .. 'field[0.7,' .. y .. ';1.95,0.6;' ..
@ -157,7 +160,6 @@ local function show_properties(elem, node)
formspec_escape('map-' .. i .. ':' .. k) .. ';X]' formspec_escape('map-' .. i .. ':' .. k) .. ';X]'
y = y + 0.8 y = y + 0.8
local prop = prop
callbacks['map-' .. i .. ':' .. k] = function() callbacks['map-' .. i .. ':' .. k] = function()
node[k] = get_properties_map(k) node[k] = get_properties_map(k)
node[k][prop] = nil node[k][prop] = nil
@ -416,7 +418,7 @@ local load_save_opts = {}
local function show_load_save_dialog() local function show_load_save_dialog()
local callbacks = {} local callbacks = {}
local formspec = [[ local formspec = [[
formspec_version[2]size[6,9.5]button[0,0;1,0.6;back;] formspec_version[2]size[6,10.75]button[0,0;1,0.6;back;]
label[1.25,0.3;Load / save formspec] label[1.25,0.3;Load / save formspec]
checkbox[0.25,1.3;use_v1;Use formspec version 1;]] .. checkbox[0.25,1.3;use_v1;Use formspec version 1;]] ..
(load_save_opts.use_v1 and 'true' or 'false') .. [[] (load_save_opts.use_v1 and 'true' or 'false') .. [[]
@ -431,6 +433,8 @@ local function show_load_save_dialog()
label[0.75,5.8;handled automatically.] label[0.75,5.8;handled automatically.]
button[0.25,7;5.5,1;load;Load formspec] button[0.25,7;5.5,1;load;Load formspec]
button[0.25,8.25;5.5,1;save;Save formspec] button[0.25,8.25;5.5,1;save;Save formspec]
button[0.25,9.5;5.5,1;digistuff_ts;WIP]] .. '\n' ..
[[Export to digistuff touchscreen]
]] ]]
local function get_options() local function get_options()
local elems = element_dialog.firstChild.firstChild.children local elems = element_dialog.firstChild.firstChild.children
@ -481,26 +485,35 @@ local function show_load_save_dialog()
}) })
end end
function callbacks.save() local function save_dialog(res, err)
get_options()
local tree = renderer.elem_to_ast(element_dialog_base)
local res, err = renderer.export(tree, load_save_opts)
element_dialog.innerHTML = '' element_dialog.innerHTML = ''
local fs = 'formspec_version[2]size[6,9.5]button[0,0;1,0.6;back;←]' .. local label, msg
'label[1.25,0.3;Save formspec]textarea[0.25,1.25;5.5,8;result;'
if res then if res then
fs = fs .. label, msg = 'Formspec exported successfully.', res
'Formspec exported successfully.;' .. formspec_escape(res)
else else
fs = fs .. label, msg = 'Error exporting formspec!', err
'Error exporting formspec!;' .. formspec_escape(err)
end end
fs = fs .. ']' local fs = 'formspec_version[2]size[6,9.5]button[0,0;1,0.6;back;←]' ..
'label[1.25,0.3;Save formspec]textarea[0.25,1.25;5.5,8;result;' ..
label .. ';' .. formspec_escape(msg) .. ']'
render_into(element_dialog, fs, { render_into(element_dialog, fs, {
back = show_load_save_dialog, back = show_load_save_dialog,
}) })
end end
function callbacks.save()
get_options()
local tree = renderer.elem_to_ast(element_dialog_base)
save_dialog(renderer.export(tree, load_save_opts))
end
function callbacks.digistuff_ts()
get_options()
local tree = renderer.elem_to_ast(element_dialog_base)
local f = load_save_opts.use_v1 and renderer.fs51_backport or nil
save_dialog(digistuff_ts_export(tree, f))
end
render_into(element_dialog, formspec, callbacks) render_into(element_dialog, formspec, callbacks)
end end

View File

@ -441,20 +441,25 @@ function renderer.import(fs, opts)
return tree, err return tree, err
end end
function renderer.export(tree, opts) function renderer.fs51_backport(tree)
if opts.use_v1 then tree = fs51.backport(tree)
tree = fs51.backport(tree)
-- Round numbers to 2 decimal places -- Round numbers to 2 decimal places
local c = {'x', 'y', 'w', 'h'} local c = {'x', 'y', 'w', 'h'}
for node in formspec_ast.walk(tree) do for node in formspec_ast.walk(tree) do
for _, k in ipairs(c) do for _, k in ipairs(c) do
if type(node[k]) == 'number' then if type(node[k]) == 'number' then
node[k] = math.floor((node[k] * 100) + 0.5) / 100 node[k] = math.floor((node[k] * 100) + 0.5) / 100
end
end end
end end
end end
return tree
end
function renderer.export(tree, opts)
if opts.use_v1 then
tree = renderer.fs51_backport(tree)
end
local fs, err = formspec_ast.unparse(tree) local fs, err = formspec_ast.unparse(tree)
if not fs then return nil, err end if not fs then return nil, err end