Add WIP digistuff touchscreen exporting
This commit is contained in:
parent
3c52ddff9b
commit
c01a5fa734
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
49
index.lua
49
index.lua
|
@ -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
|
||||||
|
|
||||||
|
|
25
renderer.lua
25
renderer.lua
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue