- major code reorganization into multiple classes
- added support for pixel-based unit of measurement
- further simplified some "black magic" constants
- implemented margins to simulate container element
- revamped translation interface for stateful use
- various improvements to element parameter parsing
This commit is contained in:
Leslie Krause 2019-05-22 19:38:31 -04:00
parent 24912c357e
commit 019c412d42
2 changed files with 430 additions and 374 deletions

View File

@ -1,4 +1,4 @@
Scarlet Mod v1.0 Scarlet Mod v1.1
By Leslie Krause By Leslie Krause
Scarlet is a thin-wrapper library for Minetest that provides a logical, uniform system of Scarlet is a thin-wrapper library for Minetest that provides a logical, uniform system of
@ -20,6 +20,14 @@ Revision History
Version 1.0b (18-May-2019) Version 1.0b (18-May-2019)
- initial alpha version - initial alpha version
Version 1.1b (22-May-2019)
- major code reorganization into multiple classes
- added support for pixel-based unit of measurement
- further simplified some "black magic" constants
- implemented margins to simulate container element
- revamped translation interface for stateful use
- various improvements to element parameter parsing
Compatability Compatability
---------------------- ----------------------
@ -44,7 +52,7 @@ Source Code License
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2018, Leslie Krause (leslie@searstower.org) Copyright (c) 2019, Leslie Krause (leslie@searstower.org)
Permission is hereby granted, free of charge, to any person obtaining a copy of this Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software software and associated documentation files (the "Software"), to deal in the Software

792
init.lua
View File

@ -5,474 +5,528 @@
-- Copyright (c) 2019, Leslie E. Krause -- Copyright (c) 2019, Leslie E. Krause
-------------------------------------------------------- --------------------------------------------------------
ScarletDef = function ( screen_dpi, gui_scaling, has_padding ) scarlet = { }
------------------------
-- UnitConversion Class
------------------------
function UnitConversion( screen_dpi, gui_scaling, has_padding )
local self = { }
local image_size = 0.55 * ( screen_dpi or 72 ) * ( gui_scaling or 1 ) local image_size = 0.55 * ( screen_dpi or 72 ) * ( gui_scaling or 1 )
-- calculate the dot pitch as images per pixel and cells per pixel -- calculate the dot pitch as images per pixel and cells per pixel
-- using the "black magic" algorithm from guiFormSpecMenu.cpp -- using the "black magic" algorithm from guiFormSpecMenu.cpp
local dot_pitch = {
self.dot_pitch = {
-- imgsize (images per pixel) -- imgsize (images per pixel)
ix = 1 / image_size, ix = 1 / image_size,
iy = 1 / image_size, iy = 1 / image_size,
-- spacing (cells per pixel) -- spacing (cells per pixel)
x = 1 / ( image_size * 5 / 4 ), x = 1 / image_size * 4 / 5,
y = 1 / ( image_size * 15 / 13 ) y = 1 / image_size * 13 / 15
} }
-- padding width and height in cell units -- padding width and height in cell units
-- original formula: image_size * 3.0 / 8 -- original formula: image_size * 3.0 / 8
local padding_width = has_padding and 0 or 3 / 10 self.padding_width = has_padding and 0.0 or 3 / 10
local padding_height = has_padding and 0 or 13 / 40 self.padding_height = has_padding and 0.0 or 13 / 40
-- nominal button height in cell units -- nominal button height in cell units
-- NB: this is 2x the value of m_button_height used internally! -- NB: this is 2x the value of m_button_height used internally!
-- original formula: image_size * 15.0 / 13 * 0.35 -- original formula: image_size * 15.0 / 13 * 0.35
local button_height = 0.7 self.button_height = 0.7
-- cell margin width and height in cell units -- cell margin width and height in cell units
-- original formula: vx * spacing.x - ( spacing.x - imgsize.x ) -- original formula: vx * spacing.x - ( spacing.x - imgsize.x )
local cell_margin_width = 1 / 5 self.cell_margin_width = 1 / 5
local cell_margin_height = 2 / 15 self.cell_margin_height = 2 / 15
--------------------------- self.units = ( function ( )
-- unit conversion objects
---------------------------
local units = ( function ( )
-- cell size measurements -- cell size measurements
local factors = { local factors = {
i = { x = 4 / 5, y = 13 / 15 }, -- imgsize d = { x = 1 / 39.6 * 4 / 5, y = 1 / 39.6 * 13 / 15 },
i = { x = 4 / 5, y = 13 / 15 }, -- imgsize
c = { x = 1, y = 1 }, -- spacing (unity) c = { x = 1, y = 1 }, -- spacing (unity)
b = { y = button_height }, -- 2 x m_button_height b = { y = self.button_height }, -- 2 x m_button_height
} }
local function get_x( v, u ) local function get_x( v, u, dot_pitch )
return not factors[ u ] and math.floor( v ) * dot_pitch.x or v * factors[ u ].x return not factors[ u ] and math.floor( v ) * self.dot_pitch.x or v * factors[ u ].x
end end
local function get_y( v, u ) local function get_y( v, u, dot_pitch )
return not factors[ u ] and math.floor( v ) * dot_pitch.y or v * factors[ u ].y return not factors[ u ] and math.floor( v ) * self.dot_pitch.y or v * factors[ u ].y
end end
return { get_x = get_x, get_y = get_y } return { get_x = get_x, get_y = get_y }
end )( ) end )( )
local iunits = ( function ( ) self.iunits = ( function ( )
-- image size measurements -- image size measurements
local factors = { local factors = {
d = { x = 1 / 39.6, y = 1 / 39.6 },
i = { x = 1, y = 1 }, -- imgsize (unity) i = { x = 1, y = 1 }, -- imgsize (unity)
c = { x = 5 / 4, y = 15 / 13 }, -- spacing c = { x = 5 / 4, y = 15 / 13 }, -- spacing
b = { y = button_height * 15 / 13 }, -- 2 x m_button_height b = { y = self.button_height * 15 / 13 }, -- 2 x m_button_height
} }
local function get_x( v, u ) local function get_x( v, u )
return not factors[ u ] and math.floor( v ) * dot_pitch.ix or v * factors[ u ].x return not factors[ u ] and math.floor( v ) * self.dot_pitch.ix or v * factors[ u ].x
end end
local function get_y( v, u ) local function get_y( v, u )
return not factors[ u ] and math.floor( v ) * dot_pitch.iy or v * factors[ u ].y return not factors[ u ] and math.floor( v ) * self.dot_pitch.iy or v * factors[ u ].y
end end
return { get_x = get_x, get_y = get_y } return { get_x = get_x, get_y = get_y }
end )( ) end )( )
----------------------- return self
-- translation helpers end
-----------------------
local function element( name, params ) ---------------------------
return name .. "[" .. table.concat( params, ";" ) .. "]" -- RuntimeTranslator Class
end ---------------------------
local function get_pos( params, pos_units, offsets ) function RuntimeTranslator( screen_dpi, gui_scaling, has_padding )
local replace = "%0.3f,%0.3f"
local pos_x, u1, pos_y, u2 = string.match( params[ 1 ], "^(-?[0-9.]+)([icp]?),(-?[0-9.]+)([icpb]?)$" )
if not pos_x then return end local self = UnitConversion( screen_dpi, gui_scaling, has_padding ) -- extend the base class
return string.format( replace, self.margins = { { width = 0.0, height = 0.0 } }
pos_units.get_x( pos_x, u1 ) + offsets[ 1 ],
pos_units.get_y( pos_y, u2 ) + offsets[ 2 ] self.insert_margin = function ( width, height )
table.insert( self.margins, 1,
{ width = width + self.margins[ 1 ].width, height = height + self.margins[ 1 ].height }
) )
end end
local function get_pos_and_dim_x( params, pos_units, dim_units, offsets ) self.remove_margin = function ( )
local replace = "%0.3f,%0.3f;%0.3f,0.000" if #self.margins > 1 then
local pos_x, u1, pos_y, u2 = string.match( params[ 1 ], "^(-?[0-9.]+)([icp]?),(-?[0-9.]+)([icpb]?)$" ) table.remove( self.margins, 1 )
local dim_x, u3 = string.match( params[ 2 ], "^([0-9.]+)([iscp]?)$" )
if not pos_x or not dim_x then return end
if u3 == "s" then
u3 = "i"
offsets[ 3 ] = offsets[ 3 ] + ( dim_x % 1 == 0 and dim_x - 1 or math.floor( dim_x ) ) * cell_margin_width
end
return string.format( replace,
pos_units.get_x( pos_x, u1 ) + offsets[ 1 ],
pos_units.get_y( pos_y, u2 ) + offsets[ 2 ],
dim_units.get_x( dim_x, u3 ) + offsets[ 3 ]
)
end
local function get_pos_and_dim( params, pos_units, dim_units, offsets )
local replace = "%0.3f,%0.3f;%0.3f,%0.3f"
local pos_x, u1, pos_y, u2 = string.match( params[ 1 ], "^(-?[0-9.]+)([icp]?),(-?[0-9.]+)([icpb]?)$" )
local dim_x, u3, dim_y, u4 = string.match( params[ 2 ], "^([0-9.]+)([iscp]?),([0-9.]+)([iscpb]?)$" )
if not pos_x or not dim_x then return end
if u3 == "s" then
u3 = "i"
offsets[ 3 ] = offsets[ 3 ] + ( dim_x % 1 == 0 and dim_x - 1 or math.floor( dim_x ) ) * cell_margin_width
end
if u4 == "s" then
u4 = "i"
offsets[ 4 ] = offsets[ 4 ] + ( dim_y % 1 == 0 and dim_y - 1 or math.floor( dim_y ) ) * cell_margin_height
end
return string.format( replace,
pos_units.get_x( pos_x, u1 ) + offsets[ 1 ],
pos_units.get_y( pos_y, u2 ) + offsets[ 2 ],
dim_units.get_x( dim_x, u3 ) + offsets[ 3 ],
dim_units.get_y( dim_y, u4 ) + offsets[ 4 ]
)
end
------------------------------
-- generic element subclasses
------------------------------
local function ElemPos( pos_units, length )
return function ( name, params )
local pos = get_pos( params, pos_units, {
-padding_width,
-padding_height
} )
assert( pos and #params == length, "Cannot parse formspec element " .. name .. "[]" )
return element( name, { pos, unpack( params, 2 ) } )
end end
end end
local function ElemPosAndDim( pos_units, dim_units, length, is_unlimited ) self.get_pos = function ( pos_value, pos_units, offsets )
return function ( name, params ) if pos_value then
local pos_and_dim = get_pos_and_dim( params, pos_units, dim_units, { local pos_x, u1, pos_y, u2 = string.match( pos_value, "^(-?[0-9.]+)([icpd]?),(-?[0-9.]+)([icpdb]?)$" )
-padding_width,
-padding_height, if not pos_x then return end
0,
0 return string.format( "%0.3f,%0.3f",
} ) pos_units.get_x( pos_x, u1 ) + offsets[ 1 ] + self.margins[ 1 ].width,
assert( pos_and_dim and ( #params == length or is_unlimited and #params > length ), "Cannot parse formspec element " .. name .. "[]" ) pos_units.get_y( pos_y, u2 ) + offsets[ 2 ] + self.margins[ 1 ].height
return element( name, { pos_and_dim, unpack( params, 3 ) } ) )
end end
end end
local function ElemPosAndDimX( pos_units, dim_units, length, is_unlimited ) self.get_pos_and_dim_x = function ( pos_value, dim_value, pos_units, dim_units, offsets )
return function ( name, params ) if pos_value and dim_value then
local pos_and_dim_x = get_pos_and_dim_x( params, pos_units, dim_units, { local pos_x, u1, pos_y, u2 = string.match( pos_value, "^(-?[0-9.]+)([icpd]?),(-?[0-9.]+)([icpdb]?)$" )
-padding_width, local dim_x, u3 = string.match( dim_value, "^([0-9.]+)([iscp]?)$" )
-padding_height,
0 if not pos_x or not dim_x then return end
} )
assert( pos_and_dim_x and ( #params == length or is_unlimited and #params > length ), "Cannot parse formspec element " .. name .. "[]" ) if u3 == "s" then
return element( name, { pos_and_dim_x, unpack( params, 3 ) } ) u3 = "i"
offsets[ 3 ] = offsets[ 3 ] + ( dim_x % 1 == 0 and dim_x - 1 or math.floor( dim_x ) ) * self.cell_margin_width
end
return string.format( "%0.3f,%0.3f;%0.3f,0.000",
pos_units.get_x( pos_x, u1 ) + offsets[ 1 ] + self.margins[ 1 ].width,
pos_units.get_y( pos_y, u2 ) + offsets[ 2 ] + self.margins[ 1 ].height,
dim_units.get_x( dim_x, u3 ) + offsets[ 3 ]
)
end end
end end
------------------------------ self.get_pos_and_dim = function ( pos_value, dim_value, pos_units, dim_units, offsets )
-- special element subclasses if pos_value and dim_value then
------------------------------ local pos_x, u1, pos_y, u2 = string.match( pos_value, "^(-?[0-9.]+)([icpd]?),(-?[0-9.]+)([icpdb]?)$" )
local dim_x, u3, dim_y, u4 = string.match( dim_value, "^([0-9.]+)([iscpd]?),([0-9.]+)([iscpdb]?)$" )
local function SizeElement( ) if not pos_x or not dim_x then return end
local pattern = "^(%d+)([iscp]?),(%d+)([iscpb]?)$"
local replace = "%0.3f,%0.3f,true"
return function ( name, params ) if u3 == "s" then
local dim, count = string.gsub( params[ 1 ], pattern, function ( dim_x, u1, dim_y, u2 ) u3 = "i"
return string.format( replace, offsets[ 3 ] = offsets[ 3 ] + ( dim_x % 1 == 0 and dim_x - 1 or math.floor( dim_x ) ) * self.cell_margin_width
units.get_x( dim_x, u1 ), end
units.get_y( dim_y, u2 ) if u4 == "s" then
) u4 = "i"
end ) offsets[ 4 ] = offsets[ 4 ] + ( dim_y % 1 == 0 and dim_y - 1 or math.floor( dim_y ) ) * self.cell_margin_height
assert( count == 1, "Cannot parse formspec element size[]" ) end
return element( "size", { dim } )
return string.format( "%0.3f,%0.3f;%0.3f,%0.3f",
pos_units.get_x( pos_x, u1 ) + offsets[ 1 ] + self.margins[ 1 ].width,
pos_units.get_y( pos_y, u2 ) + offsets[ 2 ] + self.margins[ 1 ].height,
dim_units.get_x( dim_x, u3 ) + offsets[ 3 ],
dim_units.get_y( dim_y, u4 ) + offsets[ 4 ]
)
end end
end end
local function ListElement( ) return self
local pattern = "^(%d+)([icp]?),(%d+)([icpb]?)$" end
local replace = "%0.3f,%0.3f"
return function ( name, params ) ------------------------------
local pos, count = string.gsub( params[ 3 ], pattern, function ( pos_x, u1, pos_y, u2 ) -- Generic Element Subclasses
return string.format( replace, ------------------------------
units.get_x( pos_x, u1 ) - padding_width,
units.get_y( pos_y, u2 ) - padding_height local function element( name, params )
) return name .. "[" .. table.concat( params, ";" ) .. "]"
end ) end
assert( count == 1, "Cannot parse formspec element list[]" )
return element( "list", { params[ 1 ], params[ 2 ], pos, unpack( params, 4 ) } ) local function ElemPos( pos_units, length )
end return function ( tx, name, params )
local pos = tx.get_pos( params[ 1 ], pos_units, {
-tx.padding_width,
-tx.padding_height
} )
assert( pos and #params == length, "Cannot parse formspec element " .. name .. "[]" )
return element( name, { pos, unpack( params, 2 ) } )
end end
end
-- container[<x>,<y>] local function ElemPosAndDim( pos_units, dim_units, length, is_unlimited )
return function ( tx, name, params )
local function ContainerElement( ) local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], pos_units, dim_units, {
return function ( name, params ) -tx.padding_width,
local pos = get_pos( params, units, { 0, 0 } ) -tx.padding_height,
assert( pos and #params == 1, "Cannot parse formspec element container[]" ) 0,
return element( "container", { pos } ) 0
end } )
assert( pos_and_dim and ( #params == length or is_unlimited and #params > length ), "Cannot parse formspec element " .. name .. "[]" )
return element( name, { pos_and_dim, unpack( params, 3 ) } )
end end
end
-- background[<w>,<h>;<texture name>] local function ElemPosAndDimX( pos_units, dim_units, length, is_unlimited )
return function ( tx, name, params )
local function BackgroundElement( ) local pos_and_dim_x = tx.get_pos_and_dim_x( params[ 1 ], params[ 2 ], pos_units, dim_units, {
local pattern = "^(-?%d+),(-?%d+)$" -tx.padding_width,
local replace = "%d,%d;0,0" -tx.padding_height,
0
return function ( name, params ) } )
local dim, count = string.gsub( params[ 1 ], pattern, function ( pos_x, pos_y ) assert( pos_and_dim_x and ( #params == length or is_unlimited and #params > length ), "Cannot parse formspec element " .. name .. "[]" )
return string.format( replace, -pos_x, -pos_y ) return element( name, { pos_and_dim_x, unpack( params, 3 ) } )
end )
assert( count == 1, "Cannot parse formspec element background[]" )
return element( "background", { dim, params[ 2 ], "true" } )
end
end end
end
-- bgimage[<x>,<y>;<w>,<h>;<texture name>] ------------------------------
-- Special Element Subclasses
------------------------------
local function BgImageElement( ) local function SizeElement( )
local pattern = "^(%d+)([iscp]?),(%d+)([iscpb]?)$"
local replace = "%0.3f,%0.3f,true"
return function ( tx, name, params )
local dim, count = string.gsub( params[ 1 ], pattern, function ( dim_x, u1, dim_y, u2 )
return string.format( replace,
tx.units.get_x( dim_x, u1 ),
tx.units.get_y( dim_y, u2 )
)
end )
assert( count == 1, "Cannot parse formspec element size[]" )
return element( "size", { dim } )
end
end
-- list[<inventory_location>;<list_name>;<x>,<y>;<colums>;<rows>]
local function ListElement( )
local pattern = "^(%d+)([icp]?),(%d+)([icpb]?)$"
local replace = "%0.3f,%0.3f"
return function ( tx, name, params )
local pos = tx.get_pos( params[ 3 ], tx.units, {
-tx.padding_width,
-tx.padding_height,
} )
assert( pos and ( #params == 4 or #params == 5 ), "Cannot parse formspec element list[]" )
return element( "list", { params[ 1 ], params[ 2 ], pos, unpack( params, 4 ) } )
end
end
-- margin[]
-- margin[<x>,<y>]
local function MarginElement( )
local pattern = "^(-?[0-9.]+)([icpd]?),(-?[0-9.]+)([icpdb]?)$"
return function ( tx, name, params )
if #params == 0 then
tx.insert_margin( tx.padding_width, tx.padding_height )
else
local pos_x, u1, pos_y, u2 = string.match( params[ 1 ], pattern )
assert( pos_x and #params == 1, "Cannot parse formspec element margin[]" )
tx.insert_margin( tx.units.get_x( pos_x, u1 ), tx.units.get_y( pos_y, u2 ) )
end
return "" -- remove virtual element
end
end
-- margin_end[]
local function MarginEndElement( )
return function ( tx, name, params )
assert( #params == 0, "Cannot parse formspec element container_end[]" )
tx.remove_margin( )
return "" -- remove virtual element
end
end
-- background[<w>,<h>;<texture name>]
local function BackgroundElement( )
local pattern = "^(-?%d+),(-?%d+)$"
local replace = "%d,%d;0,0"
return function ( tx, name, params )
local dim, count = string.gsub( params[ 1 ], pattern, function ( pos_x, pos_y )
return string.format( replace, -pos_x, -pos_y )
end )
assert( count == 1, "Cannot parse formspec element background[]" )
return element( "background", { dim, params[ 2 ], "true" } )
end
end
-- bgimage[<x>,<y>;<w>,<h>;<texture name>]
local function BgImageElement( )
return function ( tx, name, params )
-- original formula: vx * spacing.x - ( spacing.x - imgsize.x ) / 2 -- original formula: vx * spacing.x - ( spacing.x - imgsize.x ) / 2
local pos_offset_x = 0.5 * 1 / 5 local pos_offset_x = 0.5 * 1 / 5
local pos_offset_y = 0.5 * 2 / 15 local pos_offset_y = 0.5 * 2 / 15
return function ( name, params ) local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], tx.units, tx.units, {
local pos_and_dim = get_pos_and_dim( params, units, units, { -tx.padding_width + pos_offset_x,
-padding_width + pos_offset_x, -tx.padding_height + pos_offset_y,
-padding_height + pos_offset_y, 0,
0, 0
0 } )
} ) assert( pos_and_dim and #params == 3, "Cannot parse formspec element bgimage[]" )
assert( pos_and_dim and #params == 3, "Cannot parse formspec element bgimage[]" ) return element( "background", { pos_and_dim, params[ 3 ], "false" } )
return element( "background", { pos_and_dim, params[ 3 ], "false" } )
end
end end
end
-- label[<x>,<y>;<label>] -- label[<x>,<y>;<label>]
-- vertlabel[<x>,<y>;<label>] -- vertlabel[<x>,<y>;<label>]
local function LabelElement( is_vertical ) local function LabelElement( is_vertical )
return function ( tx, name, params )
-- original formula: ( vy + 7 / 30 ) * spacing.y - m_button_height -- original formula: ( vy + 7 / 30 ) * spacing.y - m_button_height
local pos_offset_y = -7 / 30 + button_height / 2 local pos_offset_y = -7 / 30 + tx.button_height / 2
return function ( name, params ) local pos = tx.get_pos( params[ 1 ], tx.units, {
local pos = get_pos( params, units, { -tx.padding_width,
-padding_width, -tx.padding_height + pos_offset_y,
-padding_height + pos_offset_y, } )
} ) assert( pos and #params == 2, "Cannot parse formspec element " .. name .. "[]" )
assert( pos and #params == 2, "Cannot parse formspec element " .. name .. "[]" ) return element( is_vertical and "vertlabel" or "label", { pos, params[ 2 ] } )
return element( is_vertical and "vertlabel" or "label", { pos, params[ 2 ] } )
end
end end
end
-- checkbox[<x>,<y>;<w>;<name>;<label>] -- checkbox[<x>,<y>;<w>;<name>;<label>]
local function CheckboxElement( ) local function CheckboxElement( )
return function ( tx, name, params )
-- original formula: vy * spacing.y + ( imgsize.y / 2 ) - m_button_height -- original formula: vy * spacing.y + ( imgsize.y / 2 ) - m_button_height
local pos_offset_y = -13 / 30 + button_height / 2 local pos_offset_y = -13 / 30 + tx.button_height / 2
return function ( name, params ) local pos = tx.get_pos( params[ 1 ], tx.units, {
local pos = get_pos( params, units, { -tx.padding_width,
-padding_width, -tx.padding_height + pos_offset_y,
-padding_height + pos_offset_y, } )
} ) assert( pos and #params == 4, "Cannot parse formspec element checkbox[]" )
assert( pos and #params == 4, "Cannot parse formspec element checkbox[]" ) return element( "checkbox", { pos, unpack( params, 3 ) } )
return element( "checkbox", { pos, unpack( params, 3 ) } )
end
end end
end
-- button[<x>,<y>;<w>;<name>;<label>] -- button[<x>,<y>;<w>;<name>;<label>]
local function ButtonElement( ) local function ButtonElement( )
return function ( name, params ) return function ( tx, name, params )
local pos_and_dim = get_pos_and_dim( params, units, units, { local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], tx.units, tx.units, {
-padding_width, -tx.padding_width,
-padding_height, -tx.padding_height,
cell_margin_width, tx.cell_margin_width,
cell_margin_height, tx.cell_margin_height,
} ) } )
assert( pos_and_dim and #params == 4, "Cannot parse formspec element " .. name .. "[]" ) assert( pos_and_dim and #params == 4, "Cannot parse formspec element " .. name .. "[]" )
return element( "image_" .. name, { pos_and_dim, "", unpack( params, 3 ) } ) return element( "image_" .. name, { pos_and_dim, "", unpack( params, 3 ) } )
end
end end
end
-- image_button[<x>,<y>;<w>;<name>;<texture_name>;<label>] -- image_button[<x>,<y>;<w>;<name>;<texture_name>;<label>]
local function ImageButtonElement( ) local function ImageButtonElement( )
return function ( name, params ) return function ( tx, name, params )
local pos_and_dim = get_pos_and_dim( params, units, units, { local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], tx.units, tx.units, {
-padding_width, -tx.padding_width,
-padding_height, -tx.padding_height,
cell_margin_width, tx.cell_margin_width,
cell_margin_height, tx.cell_margin_height,
} ) } )
assert( pos_and_dim and ( #params == 5 or #params == 8 ), "Cannot parse formspec element " .. name .. "[]" ) assert( pos_and_dim and ( #params == 5 or #params == 8 ), "Cannot parse formspec element " .. name .. "[]" )
return element( name, { pos_and_dim, params[ 4 ], params[ 3 ], unpack( params, 5 ) } ) return element( name, { pos_and_dim, params[ 4 ], params[ 3 ], unpack( params, 5 ) } )
end
end end
end
-- item_image_button[<x>,<y>;<w>,<h>;<item name>;<name>;<label>] -- item_image_button[<x>,<y>;<w>,<h>;<item name>;<name>;<label>]
local function ItemImageButtonElement( ) local function ItemImageButtonElement( )
return function ( name, params ) return function ( tx, name, params )
local pos_and_dim = get_pos_and_dim( params, units, units, { local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], tx.units, tx.units, {
-padding_width, -tx.padding_width,
-padding_height, -tx.padding_height,
cell_margin_width, tx.cell_margin_width,
cell_margin_height, tx.cell_margin_height,
} ) } )
assert( pos_and_dim and #params == 5, "Cannot parse formspec element item_image_button[]" ) assert( pos_and_dim and #params == 5, "Cannot parse formspec element item_image_button[]" )
return element( "item_image_button", { pos_and_dim, params[ 4 ], params[ 3 ], params[ 5 ] } ) return element( "item_image_button", { pos_and_dim, params[ 4 ], params[ 3 ], params[ 5 ] } )
end
end end
end
-- textlist[<x>,<y>;<w>,<h>;<name>;...] -- textlist[<x>,<y>;<w>,<h>;<name>;...]
local function TextListElement( ) local function TextListElement( )
return function ( name, params ) return function ( tx, name, params )
local pos_and_dim = get_pos_and_dim( params, units, units, { local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], tx.units, tx.units, {
-padding_width, -tx.padding_width,
-padding_height, -tx.padding_height,
0, 0,
0, 0,
} ) } )
assert( pos_and_dim and ( #params == 4 or #params == 5 ), "Cannot parse formspec element textlist[]" ) assert( pos_and_dim and ( #params == 4 or #params == 5 ), "Cannot parse formspec element textlist[]" )
return element( "textlist", { pos_and_dim, unpack( params, 3 ) } ) return element( "textlist", { pos_and_dim, unpack( params, 3 ) } )
end
end end
end
-- dropdown[<x>,<y>;<w>,<h>;<name>;...] -- dropdown[<x>,<y>;<w>,<h>;<name>;...]
local function DropdownElement( ) local function DropdownElement( )
return function ( name, params ) return function ( tx, name, params )
local pos_and_dim_x = get_pos_and_dim_x( params, units, units, { local pos_and_dim_x = tx.get_pos_and_dim_x( params[ 1 ], params[ 2 ], tx.units, tx.units, {
-padding_width, -tx.padding_width,
-padding_height, -tx.padding_height,
0, 0,
0, 0,
} ) } )
assert( pos_and_dim_x and #params == 5, "Cannot parse formspec element dropdown[]" ) assert( pos_and_dim_x and #params == 5, "Cannot parse formspec element dropdown[]" )
return element( "dropdown", { pos_and_dim_x, unpack( params, 3 ) } ) return element( "dropdown", { pos_and_dim_x, unpack( params, 3 ) } )
end
end end
end
-- pwdfield[<x>,<y>;<w>;<name>] -- pwdfield[<x>,<y>;<w>;<name>]
local function PwdFieldElement( ) local function PwdFieldElement( )
return function ( name, params ) return function ( tx, name, params )
local pos_and_dim_x = get_pos_and_dim_x( params, units, units, { local pos_and_dim_x = tx.get_pos_and_dim_x( params[ 1 ], params[ 2 ], tx.units, tx.units, {
0, 0,
button_height / 2, tx.button_height / 2,
cell_margin_width, tx.cell_margin_width,
} ) } )
assert( pos_and_dim_x, #params == 3, "Cannot parse formspec element pwdfield[]" ) assert( pos_and_dim_x, #params == 3, "Cannot parse formspec element pwdfield[]" )
return element( "pwdfield", { pos_and_dim_x, params[ 3 ], "" } ) return element( "pwdfield", { pos_and_dim_x, params[ 3 ], "" } )
end
end end
end
-- field[<x>,<y>;<w>;<name>;<default>] -- field[<x>,<y>;<w>;<name>;<default>]
local function FieldElement( ) local function FieldElement( )
return function ( name, params ) return function ( tx, name, params )
local pos_and_dim_x = get_pos_and_dim_x( params, units, units, { local pos_and_dim_x = tx.get_pos_and_dim_x( params[ 1 ], params[ 2 ], tx.units, tx.units, {
0, 0,
button_height / 2, tx.button_height / 2,
cell_margin_width, tx.cell_margin_width,
} ) } )
assert( pos_and_dim_x and #params == 4, "Cannot parse formspec element field[]" ) assert( pos_and_dim_x and #params == 4, "Cannot parse formspec element field[]" )
return element( "field", { pos_and_dim_x, params[ 3 ], "", params[ 4 ] } ) return element( "field", { pos_and_dim_x, params[ 3 ], "", params[ 4 ] } )
end
end end
end
-- caption[<x>,<y>;<w>,<h>;<caption>] -- caption[<x>,<y>;<w>,<h>;<caption>]
local function CaptionElement( ) local function CaptionElement( )
return function ( name, params ) return function ( tx, name, params )
local pos_and_dim = get_pos_and_dim( params, units, units, { local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], tx.units, tx.units, {
0, 0,
-button_height / 2, -tx.button_height / 2,
cell_margin_width, tx.cell_margin_width,
cell_margin_height + button_height / 2 tx.cell_margin_height + tx.button_height / 2
} ) } )
assert( pos_and_dim and #params == 3, "Cannot parse formspec element caption[]" ) assert( pos_and_dim and #params == 3, "Cannot parse formspec element caption[]" )
return element( "textarea", { pos_and_dim, "", params[ 3 ], "" } ) return element( "textarea", { pos_and_dim, "", params[ 3 ], "" } )
end
end end
end
-- textarea[<x>,<y>;<w>,<h>;<name>;<default>] -- textarea[<x>,<y>;<w>,<h>;<name>;<default>]
local function TextAreaElement( ) local function TextAreaElement( )
return function ( name, params ) return function ( tx, name, params )
local pos_and_dim = get_pos_and_dim( params, units, units, { local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], tx.units, tx.units, {
0, 0,
-button_height / 2, -tx.button_height / 2,
cell_margin_width, tx.cell_margin_width,
cell_margin_height + button_height / 2 tx.cell_margin_height + tx.button_height / 2
} ) } )
assert( pos_and_dim and #params == 4, "Cannot parse formspec element textarea[]" ) assert( pos_and_dim and #params == 4, "Cannot parse formspec element textarea[]" )
return element( "textarea", { pos_and_dim, params[ 3 ], "", params[ 4 ] } ) return element( "textarea", { pos_and_dim, params[ 3 ], "", params[ 4 ] } )
end
end end
end
-- horz_scrollbar[<x>,<y>;<w>,<h>;<name>;<value>] -- horz_scrollbar[<x>,<y>;<w>,<h>;<name>;<value>]
-- vert_scrollbar[<x>,<y>;<w>,<h>;<name>;<value>] -- vert_scrollbar[<x>,<y>;<w>,<h>;<name>;<value>]
local function ScrollbarElement( orientation ) local function ScrollbarElement( orientation )
return function ( name, params ) return function ( tx, name, params )
local pos_and_dim = get_pos_and_dim( params, units, units, { local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], tx.units, tx.units, {
-padding_width, -tx.padding_width,
-padding_height, -tx.padding_height,
0, 0,
0 0
} ) } )
assert( pos_and_dim and #params == 4, "Cannot parse formspec element " .. name .. "[]" ) assert( pos_and_dim and #params == 4, "Cannot parse formspec element " .. name .. "[]" )
return element( "scrollbar", { pos_and_dim, orientation, unpack( params, 3 ) } ) return element( "scrollbar", { pos_and_dim, orientation, unpack( params, 3 ) } )
end
end end
end
-- area_tooltip[<x>,<y>;<w>,<h>;<name>;<tooltip_text>] -- area_tooltip[<x>,<y>;<w>,<h>;<name>;<tooltip_text>]
local function AreaTooltipElement( ) local function AreaTooltipElement( )
return function ( name, params ) return function ( tx, name, params )
local pos_and_dim = get_pos_and_dim( params, units, units, { local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], tx.units, tx.units, {
-padding_width, -tx.padding_width,
-padding_height, -tx.padding_height,
0, 0,
0 0
} ) } )
assert( pos_and_dim and #params >= 3, "Cannot parse formspec element area_tooltip[]" ) assert( pos_and_dim and #params >= 3, "Cannot parse formspec element area_tooltip[]" )
return element( "tooltip", { pos_and_dim, unpack( params, 3 ) } ) return element( "tooltip", { pos_and_dim, unpack( params, 3 ) } )
end
end end
end
-- tabheader[<x>,<y>;<w>,<h>;<name>;<tooltip_text>] -- tabheader[<x>,<y>;<w>,<h>;<name>;<tooltip_text>]
local function TabHeaderElement( ) local function TabHeaderElement( )
return function ( name, params ) return function ( tx, name, params )
local pos = get_pos( params, units, { local pos = tx.get_pos( params[ 1 ], tx.units, {
0, 0,
0 0
} ) } )
assert( pos and ( #params == 4 or #params == 6 ), "Cannot parse formspec element tabheader[]" ) assert( pos and ( #params == 4 or #params == 6 ), "Cannot parse formspec element tabheader[]" )
return element( "tabheader", { pos, unpack( params, 2 ) } ) return element( "tabheader", { pos, unpack( params, 2 ) } )
end
end end
end
------------------- -------------------------
-- element parsers -- Translation Interface
------------------- -------------------------
scarlet.translate = function ( fs, screen_dpi, gui_scaling )
local tx = RuntimeTranslator( screen_dpi, gui_scaling, false )
local element_parsers = { local element_parsers = {
size = SizeElement( ), size = SizeElement( ),
list = ListElement( ), list = ListElement( ),
background = BackgroundElement( ), background = BackgroundElement( ),
box = ElemPosAndDim( units, units, 3, false ), box = ElemPosAndDim( tx.units, tx.units, 3, false ),
button = ButtonElement( ), button = ButtonElement( ),
button_exit = ButtonElement( ), button_exit = ButtonElement( ),
image_button = ImageButtonElement( ), image_button = ImageButtonElement( ),
@ -483,45 +537,39 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
checkbox = CheckboxElement( ), checkbox = CheckboxElement( ),
pwdfield = PwdFieldElement( ), pwdfield = PwdFieldElement( ),
item_image_button = ItemImageButtonElement( ), item_image_button = ItemImageButtonElement( ),
image = ElemPosAndDim( units, iunits, 3, false ), image = ElemPosAndDim( tx.units, tx.iunits, 3, false ),
item_image = ElemPosAndDim( units, iunits, 3, false ), item_image = ElemPosAndDim( tx.units, tx.iunits, 3, false ),
field = FieldElement( ), field = FieldElement( ),
dropdown = DropdownElement( ), dropdown = DropdownElement( ),
textlist = TextListElement( ), textlist = TextListElement( ),
vert_scrollbar = ScrollbarElement( "vertical" ), vert_scrollbar = ScrollbarElement( "vertical" ),
horz_scrollbar = ScrollbarElement( "horizontal" ), horz_scrollbar = ScrollbarElement( "horizontal" ),
table = ElemPosAndDim( units, units, 5, false ), table = ElemPosAndDim( tx.units, tx.units, 5, false ),
textarea = TextAreaElement( ), textarea = TextAreaElement( ),
caption = CaptionElement( ), caption = CaptionElement( ),
area_tooltip = AreaTooltipElement( ), -- added in 5.0 (https://github.com/minetest/minetest/pull/7469) area_tooltip = AreaTooltipElement( ), -- not added until 5.0 (https://github.com/minetest/minetest/pull/7469)
container = ContainerElement( ), -- fixed in 5.0 (https://github.com/minetest/minetest/pull/7497) container = ElemPos( tx.units, 1 ), -- not fixed until 5.0 (https://github.com/minetest/minetest/pull/7497)
margin = MarginElement( ), -- emulation of container[] element
margin_end = MarginEndElement( ),
tabheader = TabHeaderElement( ), tabheader = TabHeaderElement( ),
} }
------------------------- fs = string.gsub( fs, "([a-z_]+)%[(.-)%]", function( name, parts )
-- translation interface local parser = element_parsers[ name ]
------------------------- if parser then
local res = parser( tx, name, parts == "" and { } or string.split( parts, ";", true ) )
return res
end
end )
local function translate( fs ) -- minetest.debug( "ACTION", "Result:" .. fs )
fs = string.gsub( fs, "([a-z_]+)%[(.-)%]", function( name, parts ) return fs
local parser = element_parsers[ name ]
if parser then
local res = parser( name, string.split( parts, ";", true ) )
return res
end
end )
minetest.debug( "ACTION", "Result:" .. fs )
return fs
end
return {
-- public method
translate = translate
}
end end
scarlet = { scarlet.translate_96dpi = function ( fs )
translate_96dpi = ScarletDef( 96, 1, false ).translate, return scarlet.translate( fs, 96, 1 )
translate_72dpi = ScarletDef( 72, 1, false ).translate end
}
scarlet.translate_72dpi = function ( fs )
return scarlet.translate( fs, 72, 1 )
end