2019-05-19 00:52:00 +02:00
|
|
|
--------------------------------------------------------
|
|
|
|
-- Minetest :: Scarlet Mod (scarlet)
|
|
|
|
--
|
|
|
|
-- See README.txt for licensing and release notes.
|
|
|
|
-- Copyright (c) 2019, Leslie E. Krause
|
|
|
|
--------------------------------------------------------
|
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
scarlet = { }
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-28 01:40:39 +02:00
|
|
|
--------------------------
|
|
|
|
-- Local Helper Functions
|
|
|
|
--------------------------
|
|
|
|
|
|
|
|
local function element( name, params )
|
|
|
|
return name .. "[" .. table.concat( params, ";" ) .. "]"
|
|
|
|
end
|
|
|
|
|
|
|
|
local function is_match( text, glob )
|
|
|
|
_ = { string.match( text, glob ) }
|
|
|
|
return #_ > 0
|
|
|
|
end
|
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
------------------------
|
|
|
|
-- UnitConversion Class
|
|
|
|
------------------------
|
|
|
|
|
|
|
|
function UnitConversion( screen_dpi, gui_scaling, has_padding )
|
|
|
|
local self = { }
|
2019-05-19 00:52:00 +02:00
|
|
|
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
|
|
|
|
-- using the "black magic" algorithm from guiFormSpecMenu.cpp
|
2019-05-23 01:38:31 +02:00
|
|
|
|
|
|
|
self.dot_pitch = {
|
2019-05-19 00:52:00 +02:00
|
|
|
-- imgsize (images per pixel)
|
|
|
|
ix = 1 / image_size,
|
|
|
|
iy = 1 / image_size,
|
|
|
|
-- spacing (cells per pixel)
|
2019-05-28 01:40:39 +02:00
|
|
|
x = 1 / image_size * 4 / 5,
|
|
|
|
y = 1 / image_size * 13 / 15
|
2019-05-19 00:52:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
-- padding width and height in cell units
|
|
|
|
-- original formula: image_size * 3.0 / 8
|
2019-05-23 01:38:31 +02:00
|
|
|
self.padding_width = has_padding and 0.0 or 3 / 10
|
|
|
|
self.padding_height = has_padding and 0.0 or 13 / 40
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-24 18:39:07 +02:00
|
|
|
-- button height in cell units
|
|
|
|
-- NB: this is 2x the value of m_btn_height used internally!
|
2019-05-19 00:52:00 +02:00
|
|
|
-- original formula: image_size * 15.0 / 13 * 0.35
|
2019-05-23 01:38:31 +02:00
|
|
|
self.button_height = 0.7
|
2019-05-19 00:52:00 +02:00
|
|
|
|
|
|
|
-- cell margin width and height in cell units
|
|
|
|
-- original formula: vx * spacing.x - ( spacing.x - imgsize.x )
|
2019-05-23 01:38:31 +02:00
|
|
|
self.cell_margin_width = 1 / 5
|
|
|
|
self.cell_margin_height = 2 / 15
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-24 18:39:07 +02:00
|
|
|
-- point width and height in cell units
|
|
|
|
self.point_width = 1 / 39.6 * 4 / 5
|
|
|
|
self.point_height = 1 / 39.6 * 13 / 15
|
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
self.units = ( function ( )
|
2019-05-19 00:52:00 +02:00
|
|
|
-- cell size measurements
|
2019-05-28 01:40:39 +02:00
|
|
|
local factors = {
|
2019-05-24 18:39:07 +02:00
|
|
|
p = { x = self.point_width, y = self.point_height },
|
2019-05-28 01:40:39 +02:00
|
|
|
i = { x = 4 / 5, y = 13 / 15 }, -- imgsize
|
|
|
|
c = { x = 1, y = 1 }, -- spacing (unity)
|
|
|
|
b = { y = self.button_height }, -- 2 x m_btn_height
|
|
|
|
}
|
|
|
|
local function get_x( v, u, dot_pitch )
|
2019-05-23 01:38:31 +02:00
|
|
|
return not factors[ u ] and math.floor( v ) * self.dot_pitch.x or v * factors[ u ].x
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-28 01:40:39 +02:00
|
|
|
local function get_y( v, u, dot_pitch )
|
2019-05-23 01:38:31 +02:00
|
|
|
return not factors[ u ] and math.floor( v ) * self.dot_pitch.y or v * factors[ u ].y
|
2019-05-28 01:40:39 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
return { get_x = get_x, get_y = get_y }
|
|
|
|
end )( )
|
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
self.iunits = ( function ( )
|
2019-05-19 00:52:00 +02:00
|
|
|
-- image size measurements
|
|
|
|
local factors = {
|
2019-05-24 18:39:07 +02:00
|
|
|
p = { x = 1 / 39.6, y = 1 / 39.6 },
|
2019-05-19 00:52:00 +02:00
|
|
|
i = { x = 1, y = 1 }, -- imgsize (unity)
|
|
|
|
c = { x = 5 / 4, y = 15 / 13 }, -- spacing
|
2019-05-24 18:39:07 +02:00
|
|
|
b = { y = self.button_height * 15 / 13 }, -- 2 x m_btn_height
|
2019-05-19 00:52:00 +02:00
|
|
|
}
|
2019-05-28 01:40:39 +02:00
|
|
|
local function get_x( v, u )
|
2019-05-23 01:38:31 +02:00
|
|
|
return not factors[ u ] and math.floor( v ) * self.dot_pitch.ix or v * factors[ u ].x
|
2019-05-28 01:40:39 +02:00
|
|
|
end
|
|
|
|
local function get_y( v, u )
|
2019-05-23 01:38:31 +02:00
|
|
|
return not factors[ u ] and math.floor( v ) * self.dot_pitch.iy or v * factors[ u ].y
|
2019-05-28 01:40:39 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
return { get_x = get_x, get_y = get_y }
|
|
|
|
end )( )
|
|
|
|
|
2019-05-28 01:40:39 +02:00
|
|
|
self.evaluate = function ( axis, expr, old_res )
|
|
|
|
local res = 0.0
|
|
|
|
local glob, vars, to_val
|
|
|
|
|
|
|
|
if axis == "x" then
|
|
|
|
glob = "^([-+][0-9.]+)([cpdi])$"
|
|
|
|
vars = { P = self.padding_width, S = self.cell_margin_width, R = old_res or 0.0 }
|
|
|
|
to_val = self.units.get_x
|
|
|
|
elseif axis == "y" then
|
|
|
|
glob = "^([-+][0-9.]+)([cpdib])$"
|
|
|
|
vars = { P = self.padding_height, S = self.cell_margin_height, B = self.button_height, R = old_res or 0.0 }
|
|
|
|
to_val = self.units.get_y
|
|
|
|
else
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local pos1 = 1
|
|
|
|
|
|
|
|
if not string.match( expr, "^[-+]" ) then expr = "+" .. expr end
|
|
|
|
|
|
|
|
while pos1 do
|
|
|
|
local pos2 = string.find( expr, "[-+]", pos1 + 1 )
|
|
|
|
local token = string.sub( expr, pos1, pos2 and pos2 - 1 )
|
|
|
|
|
|
|
|
if is_match( token, "^([-+])%$([A-Z])$" ) and vars[ _[ 2 ] ] then
|
|
|
|
res = res + tonumber( _[ 1 ] .. vars[ _[ 2 ] ] )
|
|
|
|
elseif is_match( token, glob ) then
|
|
|
|
res = res + to_val( tonumber( _[ 1 ] ), _[ 2 ] )
|
|
|
|
else
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
pos1 = pos2
|
|
|
|
end
|
|
|
|
|
|
|
|
return res
|
|
|
|
end
|
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
return self
|
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
---------------------------
|
|
|
|
-- RuntimeTranslator Class
|
|
|
|
---------------------------
|
|
|
|
|
|
|
|
function RuntimeTranslator( screen_dpi, gui_scaling, has_padding )
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
local self = UnitConversion( screen_dpi, gui_scaling, has_padding ) -- extend the base class
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
self.margins = { { width = 0.0, height = 0.0 } }
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
self.insert_margin = function ( width, height )
|
|
|
|
table.insert( self.margins, 1,
|
|
|
|
{ width = width + self.margins[ 1 ].width, height = height + self.margins[ 1 ].height }
|
2019-05-19 00:52:00 +02:00
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
self.remove_margin = function ( )
|
|
|
|
if #self.margins > 1 then
|
|
|
|
table.remove( self.margins, 1 )
|
|
|
|
end
|
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
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]?)$" )
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
if not pos_x then return end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
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
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
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]?)$" )
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
if not pos_x or not dim_x then return end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
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 ]
|
|
|
|
)
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
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 ]
|
|
|
|
)
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-28 01:40:39 +02:00
|
|
|
self.get_pos_raw = function ( pos_value )
|
|
|
|
if pos_value then
|
|
|
|
return string.match( pos_value, "^(-?[0-9.]+)([icpd]?),(-?[0-9.]+)([icpdb]?)$" )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
self.get_dim_raw = function ( dim_value )
|
|
|
|
if dim_value then
|
|
|
|
return string.match( dim_value, "^([0-9.]+)([iscpd]?),([0-9.]+)([iscpdb]?)$" )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
return self
|
|
|
|
end
|
|
|
|
|
|
|
|
------------------------------
|
|
|
|
-- Generic Element Subclasses
|
|
|
|
------------------------------
|
|
|
|
|
2019-05-24 18:39:07 +02:00
|
|
|
local function ElemPos( pos_units, length, has_padding )
|
2019-05-23 01:38:31 +02:00
|
|
|
return function ( tx, name, params )
|
|
|
|
local pos = tx.get_pos( params[ 1 ], pos_units, {
|
2019-05-24 18:39:07 +02:00
|
|
|
has_padding and -tx.padding_width or 0,
|
|
|
|
has_padding and -tx.padding_height or 0
|
2019-05-23 01:38:31 +02:00
|
|
|
} )
|
|
|
|
assert( pos and #params == length, "Cannot parse formspec element " .. name .. "[]" )
|
|
|
|
return element( name, { pos, unpack( params, 2 ) } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-24 18:39:07 +02:00
|
|
|
local function ElemPosAndDim( pos_units, dim_units, length, has_padding )
|
2019-05-23 01:38:31 +02:00
|
|
|
return function ( tx, name, params )
|
|
|
|
local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], pos_units, dim_units, {
|
2019-05-24 18:39:07 +02:00
|
|
|
has_padding and -tx.padding_width or 0,
|
|
|
|
has_padding and -tx.padding_height or 0,
|
2019-05-23 01:38:31 +02:00
|
|
|
0,
|
|
|
|
0
|
|
|
|
} )
|
2019-05-24 18:39:07 +02:00
|
|
|
assert( pos_and_dim and #params == length, "Cannot parse formspec element " .. name .. "[]" )
|
2019-05-23 01:38:31 +02:00
|
|
|
return element( name, { pos_and_dim, unpack( params, 3 ) } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-24 18:39:07 +02:00
|
|
|
local function ElemPosAndDimX( pos_units, dim_units, length, has_padding )
|
2019-05-23 01:38:31 +02:00
|
|
|
return function ( tx, name, params )
|
|
|
|
local pos_and_dim_x = tx.get_pos_and_dim_x( params[ 1 ], params[ 2 ], pos_units, dim_units, {
|
2019-05-24 18:39:07 +02:00
|
|
|
has_padding and -tx.padding_width or 0,
|
|
|
|
has_padding and -tx.padding_height or 0,
|
2019-05-23 01:38:31 +02:00
|
|
|
0
|
|
|
|
} )
|
2019-05-24 18:39:07 +02:00
|
|
|
assert( pos_and_dim_x and #params == length, "Cannot parse formspec element " .. name .. "[]" )
|
2019-05-23 01:38:31 +02:00
|
|
|
return element( name, { pos_and_dim_x, unpack( params, 3 ) } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
------------------------------
|
|
|
|
-- Special Element Subclasses
|
|
|
|
------------------------------
|
|
|
|
|
2019-05-28 01:40:39 +02:00
|
|
|
-- size[<w>,<h>]
|
|
|
|
-- size[<w>,<h>;<x>,<y>]
|
2019-05-23 01:38:31 +02:00
|
|
|
|
2019-05-28 01:40:39 +02:00
|
|
|
local function SizeElement( )
|
2019-05-23 01:38:31 +02:00
|
|
|
return function ( tx, name, params )
|
2019-05-28 01:40:39 +02:00
|
|
|
local pos_offset_x, pos_offset_y
|
|
|
|
local dim_x, u1, dim_y, u2 = tx.get_dim_raw( params[ 1 ] )
|
|
|
|
local pos_x, u3, pos_y, u4 = tx.get_pos_raw( params[ 2 ] )
|
2019-05-24 18:39:07 +02:00
|
|
|
|
2019-05-28 01:40:39 +02:00
|
|
|
assert( #params == 1 and dim_x or #params == 2 and dim_x and ( params[ 2 ] == "" or pos_x ), "Cannot parse formspec element size[]" )
|
|
|
|
|
|
|
|
if u1 == "s" then
|
|
|
|
u1 = "c"
|
|
|
|
dim_x = dim_x - tx.cell_margin_width
|
|
|
|
end
|
|
|
|
if u2 == "s" then
|
|
|
|
u2 = "c"
|
|
|
|
dim_y = dim_y - tx.cell_margin_height
|
|
|
|
end
|
|
|
|
|
|
|
|
if not pos_x then
|
|
|
|
pos_offset_x = tx.padding_width
|
|
|
|
pos_offset_y = tx.padding_height
|
|
|
|
else
|
|
|
|
pos_offset_x = tx.units.get_x( pos_x, u3 )
|
|
|
|
pos_offset_y = tx.units.get_y( pos_y, u4 )
|
|
|
|
end
|
|
|
|
tx.insert_margin( pos_offset_x, pos_offset_y )
|
|
|
|
|
|
|
|
-- original formulas:
|
|
|
|
-- padding.x * 2 + spacing.x * ( vx - 1.0 ) + imgsize.x
|
|
|
|
-- padding.y * 2 + spacing.y * ( vy - 1.0 ) + imgsize.y + m_btn_height * 2.0 / 3.0
|
|
|
|
local dim = string.format( "%0.3f,%0.3f",
|
|
|
|
tx.units.get_x( dim_x, u1 ) + 2 * pos_offset_x + 1 - tx.padding_width * 2 - 4 / 5,
|
|
|
|
tx.units.get_y( dim_y, u2 ) + 2 * pos_offset_y + 1 - tx.padding_height * 2 - 13 / 15 - tx.button_height / 3
|
|
|
|
)
|
2019-05-23 01:38:31 +02:00
|
|
|
return element( "size", { dim } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
-- list[<inventory_location>;<list_name>;<x>,<y>;<colums>;<rows>]
|
|
|
|
|
|
|
|
local function ListElement( )
|
2019-05-24 18:39:07 +02:00
|
|
|
local pattern = "^(-?[0-9.]+)([icpd]?),(-?[0-9.]+)([icpdb]?)$"
|
2019-05-23 01:38:31 +02:00
|
|
|
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 ) } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
-- margin[]
|
|
|
|
-- margin[<x>,<y>]
|
|
|
|
|
|
|
|
local function MarginElement( )
|
|
|
|
local pattern = "^(-?[0-9.]+)([icpd]?),(-?[0-9.]+)([icpdb]?)$"
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
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 ) )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
return "" -- remove virtual element
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
-- margin_end[]
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
local function MarginEndElement( )
|
|
|
|
return function ( tx, name, params )
|
|
|
|
assert( #params == 0, "Cannot parse formspec element container_end[]" )
|
|
|
|
tx.remove_margin( )
|
|
|
|
return "" -- remove virtual element
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
-- background[<w>,<h>;<texture name>]
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
local function BackgroundElement( )
|
|
|
|
local pattern = "^(-?%d+),(-?%d+)$"
|
|
|
|
local replace = "%d,%d;0,0"
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
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" } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
-- bgimage[<x>,<y>;<w>,<h>;<texture name>]
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
local function BgImageElement( )
|
|
|
|
return function ( tx, name, params )
|
2019-05-19 00:52:00 +02:00
|
|
|
-- original formula: vx * spacing.x - ( spacing.x - imgsize.x ) / 2
|
|
|
|
local pos_offset_x = 0.5 * 1 / 5
|
|
|
|
local pos_offset_y = 0.5 * 2 / 15
|
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], tx.units, tx.units, {
|
|
|
|
-tx.padding_width + pos_offset_x,
|
|
|
|
-tx.padding_height + pos_offset_y,
|
|
|
|
0,
|
|
|
|
0
|
|
|
|
} )
|
|
|
|
assert( pos_and_dim and #params == 3, "Cannot parse formspec element bgimage[]" )
|
|
|
|
return element( "background", { pos_and_dim, params[ 3 ], "false" } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
-- label[<x>,<y>;<label>]
|
|
|
|
-- vertlabel[<x>,<y>;<label>]
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
local function LabelElement( is_vertical )
|
|
|
|
return function ( tx, name, params )
|
2019-05-19 00:52:00 +02:00
|
|
|
-- original formula: ( vy + 7 / 30 ) * spacing.y - m_button_height
|
2019-05-23 01:38:31 +02:00
|
|
|
local pos_offset_y = -7 / 30 + tx.button_height / 2
|
|
|
|
|
|
|
|
local pos = tx.get_pos( params[ 1 ], tx.units, {
|
|
|
|
-tx.padding_width,
|
|
|
|
-tx.padding_height + pos_offset_y,
|
|
|
|
} )
|
|
|
|
assert( pos and #params == 2, "Cannot parse formspec element " .. name .. "[]" )
|
|
|
|
return element( is_vertical and "vertlabel" or "label", { pos, params[ 2 ] } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-28 01:40:39 +02:00
|
|
|
-- checkbox[<x>,<y>;<name>;<label>;<selected>]
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
local function CheckboxElement( )
|
|
|
|
return function ( tx, name, params )
|
2019-05-19 00:52:00 +02:00
|
|
|
-- original formula: vy * spacing.y + ( imgsize.y / 2 ) - m_button_height
|
2019-05-23 01:38:31 +02:00
|
|
|
local pos_offset_y = -13 / 30 + tx.button_height / 2
|
|
|
|
|
|
|
|
local pos = tx.get_pos( params[ 1 ], tx.units, {
|
|
|
|
-tx.padding_width,
|
|
|
|
-tx.padding_height + pos_offset_y,
|
|
|
|
} )
|
|
|
|
assert( pos and #params == 4, "Cannot parse formspec element checkbox[]" )
|
2019-05-28 01:40:39 +02:00
|
|
|
return element( "checkbox", { pos, unpack( params, 2 ) } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-28 01:40:39 +02:00
|
|
|
-- button[<x>,<y>;<w>,<h>;<name>;<label>]
|
2019-05-23 01:38:31 +02:00
|
|
|
|
|
|
|
local function ButtonElement( )
|
|
|
|
return function ( tx, name, params )
|
|
|
|
local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], tx.units, tx.units, {
|
|
|
|
-tx.padding_width,
|
|
|
|
-tx.padding_height,
|
|
|
|
tx.cell_margin_width,
|
|
|
|
tx.cell_margin_height,
|
|
|
|
} )
|
|
|
|
assert( pos_and_dim and #params == 4, "Cannot parse formspec element " .. name .. "[]" )
|
|
|
|
return element( "image_" .. name, { pos_and_dim, "", unpack( params, 3 ) } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-28 01:40:39 +02:00
|
|
|
-- image_button[<x>,<y>;<w>,<h>;<name>;<texture_name>;<label>]
|
2019-05-23 01:38:31 +02:00
|
|
|
|
|
|
|
local function ImageButtonElement( )
|
|
|
|
return function ( tx, name, params )
|
|
|
|
local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], tx.units, tx.units, {
|
|
|
|
-tx.padding_width,
|
|
|
|
-tx.padding_height,
|
|
|
|
tx.cell_margin_width,
|
|
|
|
tx.cell_margin_height,
|
|
|
|
} )
|
|
|
|
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 ) } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
-- item_image_button[<x>,<y>;<w>,<h>;<item name>;<name>;<label>]
|
|
|
|
|
|
|
|
local function ItemImageButtonElement( )
|
|
|
|
return function ( tx, name, params )
|
|
|
|
local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], tx.units, tx.units, {
|
|
|
|
-tx.padding_width,
|
|
|
|
-tx.padding_height,
|
|
|
|
tx.cell_margin_width,
|
|
|
|
tx.cell_margin_height,
|
|
|
|
} )
|
|
|
|
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 ] } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-28 01:40:39 +02:00
|
|
|
-- textlist[<x>,<y>;<w>,<h>;<name>;<item_1>...;<selected_idx>]
|
2019-05-23 01:38:31 +02:00
|
|
|
|
|
|
|
local function TextListElement( )
|
|
|
|
return function ( tx, name, params )
|
|
|
|
local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], tx.units, tx.units, {
|
|
|
|
-tx.padding_width,
|
|
|
|
-tx.padding_height,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
} )
|
|
|
|
assert( pos_and_dim and ( #params == 4 or #params == 5 ), "Cannot parse formspec element textlist[]" )
|
|
|
|
return element( "textlist", { pos_and_dim, unpack( params, 3 ) } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-28 01:40:39 +02:00
|
|
|
-- dropdown[<x>,<y>;<w>;<name>;<item_1>...;<selected_idx>]
|
2019-05-23 01:38:31 +02:00
|
|
|
|
|
|
|
local function DropdownElement( )
|
|
|
|
return function ( tx, name, params )
|
|
|
|
local pos_and_dim_x = tx.get_pos_and_dim_x( params[ 1 ], params[ 2 ], tx.units, tx.units, {
|
|
|
|
-tx.padding_width,
|
|
|
|
-tx.padding_height,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
} )
|
|
|
|
assert( pos_and_dim_x and #params == 5, "Cannot parse formspec element dropdown[]" )
|
|
|
|
return element( "dropdown", { pos_and_dim_x, unpack( params, 3 ) } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
-- pwdfield[<x>,<y>;<w>;<name>]
|
|
|
|
|
|
|
|
local function PwdFieldElement( )
|
|
|
|
return function ( tx, name, params )
|
|
|
|
local pos_and_dim_x = tx.get_pos_and_dim_x( params[ 1 ], params[ 2 ], tx.units, tx.units, {
|
|
|
|
0,
|
|
|
|
tx.button_height / 2,
|
|
|
|
tx.cell_margin_width,
|
|
|
|
} )
|
|
|
|
assert( pos_and_dim_x, #params == 3, "Cannot parse formspec element pwdfield[]" )
|
|
|
|
return element( "pwdfield", { pos_and_dim_x, params[ 3 ], "" } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
-- field[<x>,<y>;<w>;<name>;<default>]
|
|
|
|
|
|
|
|
local function FieldElement( )
|
|
|
|
return function ( tx, name, params )
|
|
|
|
local pos_and_dim_x = tx.get_pos_and_dim_x( params[ 1 ], params[ 2 ], tx.units, tx.units, {
|
|
|
|
0,
|
|
|
|
tx.button_height / 2,
|
|
|
|
tx.cell_margin_width,
|
|
|
|
} )
|
|
|
|
assert( pos_and_dim_x and #params == 4, "Cannot parse formspec element field[]" )
|
|
|
|
return element( "field", { pos_and_dim_x, params[ 3 ], "", params[ 4 ] } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
-- caption[<x>,<y>;<w>,<h>;<caption>]
|
|
|
|
|
|
|
|
local function CaptionElement( )
|
2019-05-24 18:39:07 +02:00
|
|
|
local use_legacy_render = minetest.is_player == nil
|
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
return function ( tx, name, params )
|
|
|
|
local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], tx.units, tx.units, {
|
2019-05-24 18:39:07 +02:00
|
|
|
use_legacy_render and 0 or -tx.point_width * 3,
|
2019-05-23 01:38:31 +02:00
|
|
|
-tx.button_height / 2,
|
2019-05-24 18:39:07 +02:00
|
|
|
use_legacy_render and tx.cell_margin_width or tx.cell_margin_width + tx.point_width * 6,
|
2019-05-23 01:38:31 +02:00
|
|
|
tx.cell_margin_height + tx.button_height / 2
|
|
|
|
} )
|
|
|
|
assert( pos_and_dim and #params == 3, "Cannot parse formspec element caption[]" )
|
|
|
|
return element( "textarea", { pos_and_dim, "", params[ 3 ], "" } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
-- textarea[<x>,<y>;<w>,<h>;<name>;<default>]
|
|
|
|
|
|
|
|
local function TextAreaElement( )
|
|
|
|
return function ( tx, name, params )
|
|
|
|
local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], tx.units, tx.units, {
|
|
|
|
0,
|
|
|
|
-tx.button_height / 2,
|
|
|
|
tx.cell_margin_width,
|
|
|
|
tx.cell_margin_height + tx.button_height / 2
|
|
|
|
} )
|
|
|
|
assert( pos_and_dim and #params == 4, "Cannot parse formspec element textarea[]" )
|
|
|
|
return element( "textarea", { pos_and_dim, params[ 3 ], "", params[ 4 ] } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
-- horz_scrollbar[<x>,<y>;<w>,<h>;<name>;<value>]
|
|
|
|
-- vert_scrollbar[<x>,<y>;<w>,<h>;<name>;<value>]
|
|
|
|
|
|
|
|
local function ScrollbarElement( orientation )
|
|
|
|
return function ( tx, name, params )
|
|
|
|
local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], tx.units, tx.units, {
|
|
|
|
-tx.padding_width,
|
|
|
|
-tx.padding_height,
|
|
|
|
0,
|
|
|
|
0
|
|
|
|
} )
|
|
|
|
assert( pos_and_dim and #params == 4, "Cannot parse formspec element " .. name .. "[]" )
|
|
|
|
return element( "scrollbar", { pos_and_dim, orientation, unpack( params, 3 ) } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
-- area_tooltip[<x>,<y>;<w>,<h>;<name>;<tooltip_text>]
|
|
|
|
|
|
|
|
local function AreaTooltipElement( )
|
|
|
|
return function ( tx, name, params )
|
|
|
|
local pos_and_dim = tx.get_pos_and_dim( params[ 1 ], params[ 2 ], tx.units, tx.units, {
|
|
|
|
-tx.padding_width,
|
|
|
|
-tx.padding_height,
|
|
|
|
0,
|
|
|
|
0
|
|
|
|
} )
|
2019-05-28 01:40:39 +02:00
|
|
|
assert( pos_and_dim and ( #params == 3 or #params == 5 ), "Cannot parse formspec element area_tooltip[]" )
|
2019-05-23 01:38:31 +02:00
|
|
|
return element( "tooltip", { pos_and_dim, unpack( params, 3 ) } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
-- tabheader[<x>,<y>;<w>,<h>;<name>;<tooltip_text>]
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
local function TabHeaderElement( )
|
|
|
|
return function ( tx, name, params )
|
|
|
|
local pos = tx.get_pos( params[ 1 ], tx.units, {
|
|
|
|
0,
|
|
|
|
0
|
|
|
|
} )
|
|
|
|
assert( pos and ( #params == 4 or #params == 6 ), "Cannot parse formspec element tabheader[]" )
|
|
|
|
return element( "tabheader", { pos, unpack( params, 2 ) } )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
2019-05-23 01:38:31 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
-------------------------
|
|
|
|
-- Translation Interface
|
|
|
|
-------------------------
|
|
|
|
|
|
|
|
scarlet.translate = function ( fs, screen_dpi, gui_scaling )
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
local tx = RuntimeTranslator( screen_dpi, gui_scaling, false )
|
2019-05-19 00:52:00 +02:00
|
|
|
|
|
|
|
local element_parsers = {
|
|
|
|
size = SizeElement( ),
|
|
|
|
list = ListElement( ),
|
|
|
|
background = BackgroundElement( ),
|
2019-05-24 18:39:07 +02:00
|
|
|
box = ElemPosAndDim( tx.units, tx.units, 3, true ),
|
2019-05-19 00:52:00 +02:00
|
|
|
button = ButtonElement( ),
|
|
|
|
button_exit = ButtonElement( ),
|
|
|
|
image_button = ImageButtonElement( ),
|
|
|
|
image_button_exit = ImageButtonElement( ),
|
|
|
|
bgimage = BgImageElement( ),
|
|
|
|
label = LabelElement( false ),
|
|
|
|
vertlabel = LabelElement( true ),
|
|
|
|
checkbox = CheckboxElement( ),
|
|
|
|
pwdfield = PwdFieldElement( ),
|
|
|
|
item_image_button = ItemImageButtonElement( ),
|
2019-05-24 18:39:07 +02:00
|
|
|
image = ElemPosAndDim( tx.units, tx.iunits, 3, true ),
|
|
|
|
item_image = ElemPosAndDim( tx.units, tx.iunits, 3, true ),
|
2019-05-19 00:52:00 +02:00
|
|
|
field = FieldElement( ),
|
|
|
|
dropdown = DropdownElement( ),
|
|
|
|
textlist = TextListElement( ),
|
|
|
|
vert_scrollbar = ScrollbarElement( "vertical" ),
|
|
|
|
horz_scrollbar = ScrollbarElement( "horizontal" ),
|
2019-05-24 18:39:07 +02:00
|
|
|
table = ElemPosAndDim( tx.units, tx.units, 5, true ),
|
2019-05-19 00:52:00 +02:00
|
|
|
textarea = TextAreaElement( ),
|
|
|
|
caption = CaptionElement( ),
|
2019-05-23 01:38:31 +02:00
|
|
|
area_tooltip = AreaTooltipElement( ), -- not added until 5.0 (https://github.com/minetest/minetest/pull/7469)
|
2019-05-24 18:39:07 +02:00
|
|
|
container = ElemPos( tx.units, 1, false ), -- not fixed until 5.0 (https://github.com/minetest/minetest/pull/7497)
|
2019-05-23 01:38:31 +02:00
|
|
|
margin = MarginElement( ), -- emulation of container[] element
|
|
|
|
margin_end = MarginEndElement( ),
|
2019-05-19 00:52:00 +02:00
|
|
|
tabheader = TabHeaderElement( ),
|
|
|
|
}
|
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
fs = string.gsub( fs, "([a-z_]+)%[(.-)%]", function( name, parts )
|
|
|
|
local parser = element_parsers[ name ]
|
|
|
|
if parser then
|
|
|
|
local res = parser( tx, name, parts == "" and { } or string.split( parts, ";", true ) )
|
|
|
|
return res
|
|
|
|
end
|
|
|
|
end )
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
-- minetest.debug( "ACTION", "Result:" .. fs )
|
|
|
|
return fs
|
|
|
|
end
|
2019-05-19 00:52:00 +02:00
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
scarlet.translate_96dpi = function ( fs )
|
|
|
|
return scarlet.translate( fs, 96, 1 )
|
2019-05-19 00:52:00 +02:00
|
|
|
end
|
|
|
|
|
2019-05-23 01:38:31 +02:00
|
|
|
scarlet.translate_72dpi = function ( fs )
|
|
|
|
return scarlet.translate( fs, 72, 1 )
|
|
|
|
end
|
2019-05-28 01:40:39 +02:00
|
|
|
|
|
|
|
----------------------------
|
|
|
|
-- Registered Chat Commands
|
|
|
|
----------------------------
|
|
|
|
|
|
|
|
minetest.register_chatcommand( "scarlet", {
|
|
|
|
description = "Formspec unit-conversion calculator",
|
|
|
|
privs = { server = true },
|
|
|
|
func = function( name, param )
|
|
|
|
if param ~= "" then
|
|
|
|
if is_match( param, "^([xy]) (.+)" ) then
|
|
|
|
local axis = _[ 1 ]
|
|
|
|
local expr = _[ 2 ]
|
|
|
|
local res = UnitConversion( 72 ).evaluate( axis, expr )
|
|
|
|
|
|
|
|
if not res then
|
|
|
|
minetest.chat_send_player( name, "Parsing failure! Unrecognized token in expression." )
|
|
|
|
else
|
|
|
|
minetest.chat_send_player( name, string.format( "Result: %0.3fc", res ) )
|
|
|
|
end
|
|
|
|
else
|
|
|
|
minetest.chat_send_player( name, "Invalid parameters supplied!" )
|
|
|
|
end
|
|
|
|
else
|
|
|
|
local status = "Ready"
|
|
|
|
local old_res = 0.0
|
|
|
|
local old_expr = ""
|
|
|
|
local expr = ""
|
|
|
|
local axis = "x"
|
|
|
|
local dpi = 72
|
|
|
|
|
|
|
|
local function get_formspec( )
|
|
|
|
local fs =
|
|
|
|
"size[4s,8s;0.6c,0.4c]" ..
|
|
|
|
"no_prepend[]" ..
|
|
|
|
"bgcolor[#333333;false]" ..
|
|
|
|
"field[0c,0c;4s;expr;" .. minetest.formspec_escape( expr ) .. "]" ..
|
|
|
|
"box[0c,0.95c;2s,0.6c;" .. ( status == "Ready" and "#2222DD" or "#DD2222" ) .."]" ..
|
|
|
|
"caption[0c,1.05c;2s,0.5c; " .. status .. "]" ..
|
|
|
|
|
|
|
|
"margin[0c,1c]" ..
|
|
|
|
"button[2c,0c;1i,0.5i;clear_entry;CE]" ..
|
|
|
|
"button[3c,0c;1i,0.5i;clear;C]" ..
|
|
|
|
"margin_end[]" ..
|
|
|
|
|
|
|
|
"margin[0c,1.7c]" ..
|
|
|
|
"button[0c,0c;1i,1i;num7;7]" ..
|
|
|
|
"button[1c,0c;1i,1i;num8;8]" ..
|
|
|
|
"button[2c,0c;1i,1i;num9;9]" ..
|
|
|
|
"button[0c,1c;1i,1i;num4;4]" ..
|
|
|
|
"button[1c,1c;1i,1i;num5;5]" ..
|
|
|
|
"button[2c,1c;1i,1i;num6;6]" ..
|
|
|
|
"button[0c,2c;1i,1i;num1;1]" ..
|
|
|
|
"button[1c,2c;1i,1i;num2;2]" ..
|
|
|
|
"button[2c,2c;1i,1i;num3;3]" ..
|
|
|
|
"button[3c,0c;1i,1i;sub;-]" ..
|
|
|
|
"button[3c,1c;1i,1i;add;+]" ..
|
|
|
|
"button[3c,2c;1i,2s;eval;=]" ..
|
|
|
|
"button[0c,3c;2s,1i;num0;0]" ..
|
|
|
|
"button[2c,3c;1s,1i;dec;.]" ..
|
|
|
|
"margin_end[]" ..
|
|
|
|
|
|
|
|
"margin[0c,5.8c]" ..
|
|
|
|
"button[0c,0c;1i,0.5i;unitC;c]" ..
|
|
|
|
"button[1c,0c;1i,0.5i;unitI;i]" ..
|
|
|
|
"button[2c,0c;1i,0.5i;unitP;p]" ..
|
|
|
|
"button[3c,0c;1i,0.5i;unitD;d]" ..
|
|
|
|
"button[0c,0.5c;1i,0.5i;varB;$B]" ..
|
|
|
|
"button[1c,0.5c;1i,0.5i;varP;$P]" ..
|
|
|
|
"button[2c,0.5c;1i,0.5i;varS;$S]" ..
|
|
|
|
"button[3c,0.5c;1i,0.5i;varR;$R]" ..
|
|
|
|
"margin_end[]" ..
|
|
|
|
|
|
|
|
"margin[0c,7c]" ..
|
|
|
|
"dropdown[0c,0c;1.9c;axis;X Axis,Y Axis;" .. ( axis == "x" and 1 or 2 ) .. "]" ..
|
|
|
|
"dropdown[2c,0c;1.9c;dpi;72 dpi,96 dpi;" .. ( dpi == 72 and 1 or 2 ) .. "]" ..
|
|
|
|
"margin_end[]"
|
|
|
|
|
|
|
|
return scarlet.translate_72dpi( fs )
|
|
|
|
end
|
|
|
|
|
|
|
|
local function on_close( meta, player, fields )
|
|
|
|
axis = ( { ["X Axis"] = "x", ["Y Axis"] = "y" } )[ fields.axis ] or "x"
|
|
|
|
dpi = ( { ["72 dpi"] = 72, ["96 dpi"] = 96 } )[ fields.dpi ] or 72
|
|
|
|
|
|
|
|
if fields.clear then
|
|
|
|
old_expr = expr
|
|
|
|
expr = ""
|
|
|
|
status = "Ready"
|
|
|
|
minetest.update_form( name, get_formspec( ) )
|
|
|
|
|
|
|
|
elseif fields.clear_entry then
|
|
|
|
expr = old_expr
|
|
|
|
minetest.update_form( name, get_formspec( ) )
|
|
|
|
|
|
|
|
elseif fields.eval then
|
|
|
|
local res = UnitConversion( dpi ).evaluate( axis, fields.expr, old_res )
|
|
|
|
if res then
|
|
|
|
old_res = res
|
|
|
|
old_expr = expr
|
|
|
|
expr = string.format( "%0.3fc", res )
|
|
|
|
status = "Ready"
|
|
|
|
else
|
|
|
|
expr = fields.expr
|
|
|
|
status = "Error"
|
|
|
|
end
|
|
|
|
minetest.update_form( name, get_formspec( ) )
|
|
|
|
|
|
|
|
elseif fields.expr then
|
|
|
|
old_expr = expr
|
|
|
|
expr = fields.expr
|
|
|
|
fields.expr = nil
|
|
|
|
fields.axis = nil
|
|
|
|
fields.dpi = nil
|
|
|
|
|
|
|
|
local field_name = next( fields, nil ) -- use next since we only care about the name of the first button
|
|
|
|
if field_name then
|
|
|
|
local aliases = {
|
|
|
|
sub = "-",
|
|
|
|
add = "+",
|
|
|
|
dec = ".",
|
|
|
|
varB = "$B",
|
|
|
|
varP = "$P",
|
|
|
|
varS = "$S",
|
|
|
|
varR = "$R",
|
|
|
|
unitC = "c",
|
|
|
|
unitI = "i",
|
|
|
|
unitP = "p",
|
|
|
|
unitD = "d",
|
|
|
|
}
|
|
|
|
|
|
|
|
if is_match( field_name, "^num([0-9])$" ) then
|
|
|
|
expr = expr .. _[ 1 ]
|
|
|
|
elseif aliases[ field_name ] then
|
|
|
|
expr = expr .. aliases[ field_name ]
|
|
|
|
end
|
|
|
|
minetest.update_form( name, get_formspec( ) )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
minetest.create_form( nil, name, get_formspec( ), on_close )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
} )
|