- 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

464
init.lua
View File

@ -5,144 +5,176 @@
-- 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 = {
d = { x = 1 / 39.6 * 4 / 5, y = 1 / 39.6 * 13 / 15 },
i = { x = 4 / 5, y = 13 / 15 }, -- imgsize 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
-----------------------
---------------------------
-- RuntimeTranslator Class
---------------------------
function RuntimeTranslator( screen_dpi, gui_scaling, has_padding )
local self = UnitConversion( screen_dpi, gui_scaling, has_padding ) -- extend the base class
self.margins = { { width = 0.0, height = 0.0 } }
self.insert_margin = function ( width, height )
table.insert( self.margins, 1,
{ width = width + self.margins[ 1 ].width, height = height + self.margins[ 1 ].height }
)
end
self.remove_margin = function ( )
if #self.margins > 1 then
table.remove( self.margins, 1 )
end
end
self.get_pos = function ( pos_value, pos_units, offsets )
if pos_value then
local pos_x, u1, pos_y, u2 = string.match( pos_value, "^(-?[0-9.]+)([icpd]?),(-?[0-9.]+)([icpdb]?)$" )
if not pos_x then return end
return string.format( "%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
)
end
end
self.get_pos_and_dim_x = function ( pos_value, dim_value, pos_units, dim_units, offsets )
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 = string.match( dim_value, "^([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 ) ) * 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
self.get_pos_and_dim = function ( pos_value, dim_value, pos_units, dim_units, offsets )
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]?)$" )
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 ) ) * self.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 ) ) * self.cell_margin_height
end
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
return self
end
------------------------------
-- Generic Element Subclasses
------------------------------
local function element( name, params ) local function element( name, params )
return name .. "[" .. table.concat( params, ";" ) .. "]" return name .. "[" .. table.concat( params, ";" ) .. "]"
end end
local function get_pos( params, pos_units, offsets )
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
return string.format( replace,
pos_units.get_x( pos_x, u1 ) + offsets[ 1 ],
pos_units.get_y( pos_y, u2 ) + offsets[ 2 ]
)
end
local function get_pos_and_dim_x( params, pos_units, dim_units, offsets )
local replace = "%0.3f,%0.3f;%0.3f,0.000"
local pos_x, u1, pos_y, u2 = string.match( params[ 1 ], "^(-?[0-9.]+)([icp]?),(-?[0-9.]+)([icpb]?)$" )
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 ) local function ElemPos( pos_units, length )
return function ( name, params ) return function ( tx, name, params )
local pos = get_pos( params, pos_units, { local pos = tx.get_pos( params[ 1 ], pos_units, {
-padding_width, -tx.padding_width,
-padding_height -tx.padding_height
} ) } )
assert( pos and #params == length, "Cannot parse formspec element " .. name .. "[]" ) assert( pos and #params == length, "Cannot parse formspec element " .. name .. "[]" )
return element( name, { pos, unpack( params, 2 ) } ) return element( name, { pos, unpack( params, 2 ) } )
@ -150,10 +182,10 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
end end
local function ElemPosAndDim( pos_units, dim_units, length, is_unlimited ) local function ElemPosAndDim( pos_units, dim_units, length, is_unlimited )
return function ( name, params ) return function ( tx, name, params )
local pos_and_dim = get_pos_and_dim( params, pos_units, dim_units, { local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], pos_units, dim_units, {
-padding_width, -tx.padding_width,
-padding_height, -tx.padding_height,
0, 0,
0 0
} ) } )
@ -163,10 +195,10 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
end end
local function ElemPosAndDimX( pos_units, dim_units, length, is_unlimited ) local function ElemPosAndDimX( pos_units, dim_units, length, is_unlimited )
return function ( name, params ) return function ( tx, name, params )
local pos_and_dim_x = get_pos_and_dim_x( params, pos_units, dim_units, { local pos_and_dim_x = tx.get_pos_and_dim_x( params[ 1 ], params[ 2 ], pos_units, dim_units, {
-padding_width, -tx.padding_width,
-padding_height, -tx.padding_height,
0 0
} ) } )
assert( pos_and_dim_x and ( #params == length or is_unlimited and #params > length ), "Cannot parse formspec element " .. name .. "[]" ) assert( pos_and_dim_x and ( #params == length or is_unlimited and #params > length ), "Cannot parse formspec element " .. name .. "[]" )
@ -175,18 +207,18 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
end end
------------------------------ ------------------------------
-- special element subclasses -- Special Element Subclasses
------------------------------ ------------------------------
local function SizeElement( ) local function SizeElement( )
local pattern = "^(%d+)([iscp]?),(%d+)([iscpb]?)$" local pattern = "^(%d+)([iscp]?),(%d+)([iscpb]?)$"
local replace = "%0.3f,%0.3f,true" local replace = "%0.3f,%0.3f,true"
return function ( name, params ) return function ( tx, name, params )
local dim, count = string.gsub( params[ 1 ], pattern, function ( dim_x, u1, dim_y, u2 ) local dim, count = string.gsub( params[ 1 ], pattern, function ( dim_x, u1, dim_y, u2 )
return string.format( replace, return string.format( replace,
units.get_x( dim_x, u1 ), tx.units.get_x( dim_x, u1 ),
units.get_y( dim_y, u2 ) tx.units.get_y( dim_y, u2 )
) )
end ) end )
assert( count == 1, "Cannot parse formspec element size[]" ) assert( count == 1, "Cannot parse formspec element size[]" )
@ -194,29 +226,47 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
end end
end end
-- list[<inventory_location>;<list_name>;<x>,<y>;<colums>;<rows>]
local function ListElement( ) local function ListElement( )
local pattern = "^(%d+)([icp]?),(%d+)([icpb]?)$" local pattern = "^(%d+)([icp]?),(%d+)([icpb]?)$"
local replace = "%0.3f,%0.3f" local replace = "%0.3f,%0.3f"
return function ( name, params ) return function ( tx, name, params )
local pos, count = string.gsub( params[ 3 ], pattern, function ( pos_x, u1, pos_y, u2 ) local pos = tx.get_pos( params[ 3 ], tx.units, {
return string.format( replace, -tx.padding_width,
units.get_x( pos_x, u1 ) - padding_width, -tx.padding_height,
units.get_y( pos_y, u2 ) - padding_height } )
) assert( pos and ( #params == 4 or #params == 5 ), "Cannot parse formspec element list[]" )
end )
assert( count == 1, "Cannot parse formspec element list[]" )
return element( "list", { params[ 1 ], params[ 2 ], pos, unpack( params, 4 ) } ) return element( "list", { params[ 1 ], params[ 2 ], pos, unpack( params, 4 ) } )
end end
end end
-- container[<x>,<y>] -- margin[]
-- margin[<x>,<y>]
local function ContainerElement( ) local function MarginElement( )
return function ( name, params ) local pattern = "^(-?[0-9.]+)([icpd]?),(-?[0-9.]+)([icpdb]?)$"
local pos = get_pos( params, units, { 0, 0 } )
assert( pos and #params == 1, "Cannot parse formspec element container[]" ) return function ( tx, name, params )
return element( "container", { pos } ) 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
end end
@ -226,7 +276,7 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
local pattern = "^(-?%d+),(-?%d+)$" local pattern = "^(-?%d+),(-?%d+)$"
local replace = "%d,%d;0,0" local replace = "%d,%d;0,0"
return function ( name, params ) return function ( tx, name, params )
local dim, count = string.gsub( params[ 1 ], pattern, function ( pos_x, pos_y ) local dim, count = string.gsub( params[ 1 ], pattern, function ( pos_x, pos_y )
return string.format( replace, -pos_x, -pos_y ) return string.format( replace, -pos_x, -pos_y )
end ) end )
@ -238,14 +288,14 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
-- bgimage[<x>,<y>;<w>,<h>;<texture name>] -- bgimage[<x>,<y>;<w>,<h>;<texture name>]
local function BgImageElement( ) 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
} ) } )
@ -258,13 +308,13 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
-- 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 ] } )
@ -274,13 +324,13 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
-- 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 ) } )
@ -290,12 +340,12 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
-- 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 ) } )
@ -305,12 +355,12 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
-- 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 ) } )
@ -320,12 +370,12 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
-- 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 ] } )
@ -335,10 +385,10 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
-- 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,
} ) } )
@ -350,10 +400,10 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
-- 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,
} ) } )
@ -365,11 +415,11 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
-- 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 ], "" } )
@ -379,11 +429,11 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
-- 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 ] } )
@ -393,12 +443,12 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
-- 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 ], "" } )
@ -408,12 +458,12 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
-- 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 ] } )
@ -424,10 +474,10 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
-- 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
} ) } )
@ -439,10 +489,10 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
-- 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
} ) } )
@ -454,8 +504,8 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
-- 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
} ) } )
@ -464,15 +514,19 @@ ScarletDef = function ( screen_dpi, gui_scaling, has_padding )
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( ),
} }
-------------------------
-- translation interface
-------------------------
local function translate( fs )
fs = string.gsub( fs, "([a-z_]+)%[(.-)%]", function( name, parts ) fs = string.gsub( fs, "([a-z_]+)%[(.-)%]", function( name, parts )
local parser = element_parsers[ name ] local parser = element_parsers[ name ]
if parser then if parser then
local res = parser( name, string.split( parts, ";", true ) ) local res = parser( tx, name, parts == "" and { } or string.split( parts, ";", true ) )
return res return res
end end
end ) end )
minetest.debug( "ACTION", "Result:" .. fs ) -- minetest.debug( "ACTION", "Result:" .. fs )
return fs return fs
end end
return { scarlet.translate_96dpi = function ( fs )
-- public method return scarlet.translate( fs, 96, 1 )
translate = translate
}
end end
scarlet = { scarlet.translate_72dpi = function ( fs )
translate_96dpi = ScarletDef( 96, 1, false ).translate, return scarlet.translate( fs, 72, 1 )
translate_72dpi = ScarletDef( 72, 1, false ).translate end
}