From a7d265799e5545120a63953c89aba7e714415098 Mon Sep 17 00:00:00 2001 From: Leslie Krause Date: Mon, 27 May 2019 19:40:39 -0400 Subject: [PATCH] BUILD 04 - added method to evaluate arithmetic expressions - developed in-game unit conversion calculator - added optional padding parameter to size element - fixed ordering of checkbox element parameters - added methods to extract raw pos and dim values --- README.txt | 11 +- init.lua | 308 +++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 271 insertions(+), 48 deletions(-) diff --git a/README.txt b/README.txt index 18d7fbd..d9cd435 100644 --- a/README.txt +++ b/README.txt @@ -1,4 +1,4 @@ -Scarlet Mod v1.2 +Scarlet Mod v1.3 By Leslie Krause Scarlet is a thin-wrapper library for Minetest that provides a logical, uniform system of @@ -28,7 +28,7 @@ Version 1.1b (22-May-2019) - revamped translation interface for stateful use - various improvements to element parameter parsing -Version 1.2b (23-May-2019) +Version 1.2b (24-May-2019) - included mod.conf and description.txt files - fixed parsing of list and size element parameters - recomputed textarea position due to engine bug @@ -36,6 +36,13 @@ Version 1.2b (23-May-2019) - implemented algorithm to compute form dimensions - reversed point and dot units per documentation +Version 1.3b (27-May-2019) + - added method to evaluate arithmetic expressions + - developed in-game unit conversion calculator + - added optional padding parameter to size element + - fixed ordering of checkbox element parameters + - added methods to extract raw pos and dim values + Compatability ---------------------- diff --git a/init.lua b/init.lua index e477e71..74e71aa 100644 --- a/init.lua +++ b/init.lua @@ -7,6 +7,19 @@ scarlet = { } +-------------------------- +-- 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 + ------------------------ -- UnitConversion Class ------------------------ @@ -23,8 +36,8 @@ function UnitConversion( screen_dpi, gui_scaling, has_padding ) ix = 1 / image_size, iy = 1 / image_size, -- spacing (cells per pixel) - x = 1 / image_size * 4 / 5, - y = 1 / image_size * 13 / 15 + x = 1 / image_size * 4 / 5, + y = 1 / image_size * 13 / 15 } -- padding width and height in cell units @@ -48,18 +61,18 @@ function UnitConversion( screen_dpi, gui_scaling, has_padding ) self.units = ( function ( ) -- cell size measurements - local factors = { + local factors = { p = { x = self.point_width, y = self.point_height }, - 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 ) + 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 ) return not factors[ u ] and math.floor( v ) * self.dot_pitch.x or v * factors[ u ].x end - local function get_y( v, u, dot_pitch ) + local function get_y( v, u, dot_pitch ) 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 } end )( ) @@ -71,15 +84,53 @@ function UnitConversion( screen_dpi, gui_scaling, has_padding ) c = { x = 5 / 4, y = 15 / 13 }, -- spacing b = { y = self.button_height * 15 / 13 }, -- 2 x m_btn_height } - local function get_x( v, u ) + local function get_x( v, u ) return not factors[ u ] and math.floor( v ) * self.dot_pitch.ix or v * factors[ u ].x - end - local function get_y( v, u ) + end + local function get_y( v, u ) 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 } end )( ) + 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 + return self end @@ -163,6 +214,18 @@ function RuntimeTranslator( screen_dpi, gui_scaling, has_padding ) end end + 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 + return self end @@ -170,10 +233,6 @@ end -- Generic Element Subclasses ------------------------------ -local function element( name, params ) - return name .. "[" .. table.concat( params, ";" ) .. "]" -end - local function ElemPos( pos_units, length, has_padding ) return function ( tx, name, params ) local pos = tx.get_pos( params[ 1 ], pos_units, { @@ -214,30 +273,42 @@ end -- Special Element Subclasses ------------------------------ +-- size[,] +-- size[,;,] + local function SizeElement( ) - local pattern = "^([0-9.]+)([iscpd]?),([0-9.]+)([iscpdb]?)$" - 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 ) - if u1 == "s" then - u1 = "i" - dim_x = dim_x + ( dim_x % 1 == 0 and dim_x - 1 or math.floor( dim_x ) ) * tx.cell_margin_width - end - if u2 == "s" then - u2 = "i" - dim_y = dim_x + ( dim_y % 1 == 0 and dim_y - 1 or math.floor( dim_y ) ) * tx.cell_margin_height - end + 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 ] ) - -- 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 - return string.format( replace, - tx.units.get_x( dim_x, u1 ) + 1 - tx.padding_width * 2 - 4 / 5, - tx.units.get_y( dim_y, u2 ) + 1 - tx.padding_height * 2 - 13 / 15 - tx.button_height / 3 - ) - end ) - assert( count == 1, "Cannot parse formspec element size[]" ) + 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 + ) return element( "size", { dim } ) end end @@ -337,7 +408,7 @@ local function LabelElement( is_vertical ) end end --- checkbox[,;;;