diff --git a/system/formspec/formspec_creation.lua b/system/formspec/formspec_creation.lua index f446987..db26c43 100644 --- a/system/formspec/formspec_creation.lua +++ b/system/formspec/formspec_creation.lua @@ -1,3 +1,10 @@ +-- # vim: nowrap +-- +-- Set Vim to no-wrapping mode because of some lines not fitting within the 80 +-- characters width limit due to overall readability of the code. + + +-- Localise needed functions local m = mtimer local S = m.translator local build_frame = m.build_frame @@ -8,7 +15,7 @@ local fe = minetest.formspec_escape -- correlates with the formspec to show. All of the names are self-explanatory -- and within the functions no logic is used. -- --- @see mtimer.build_frame +-- @see mtimer.show_formspec -- @see mtimer.get_times -- @see ./system/on_receive_fields.lua -- @see ./system/chat_command.lua @@ -16,71 +23,74 @@ local fe = minetest.formspec_escape mtimer.dialog.main_menu = function (player_name) - minetest.show_formspec(player_name, 'mtimer:main_menu', [[ - size[9.5,5.75] - - label[0,-0.125;]]..S('mTimer')..[[] - box[0,0.35;9.25,0.02;#ffffff] - - container[0,0.5] - label[0,0;]]..S('Visuals')..[[] - button[0,0.5;3,1;set_visibility;]]..S('Visibility')..[[] - button[0,1.5;3,1;set_position;]]..S('Position')..[[] - button[0,2.5;3,1;set_color;]]..S('Color')..[[] - container_end[] - - container[3.25,0.5] - label[0,0;]]..S('Time Representation')..[[] - button[0,0.5;3,1;ingame_time_format;]]..S('Ingame Time Format')..[[] - button[0,1.5;3,1;real_world_time_format;]]..S('Real-World Time Format')..[[] - button[0,2.5;3,1;session_start_time_format;]]..S('Session Start Time Format')..[[] - button[0,3.5;3,1;session_duration_format;]]..S('Session Duration Format')..[[] - container_end[] - - container[6.5,0.5] - label[0,0;]]..S('Timer Configuration')..[[] - button[0,0.5;3,1;timer_format;]]..S('Timer Format')..[[] - button[0,1.5;3,1;timezone_offset;]]..S('Timezone Offset')..[[] - container_end[] - - container[0,5] - box[0,0;9.25,0.02;#ffffff] - button[4.5,0.125;2.5,1;reset_everything;]]..S('Reset Everything')..[[] - button_exit[7,0.125;2.5,1;exit;]]..S('Exit')..[[] - container_end[] - ]]) + mtimer.show_formspec('mtimer:main_menu', { + title = S('mTimer'), + width = 9.5, + height = 6.125, + prefix = '', + add_buttons = false, + show_to = player_name, + formspec = { + 'container[0,0]', + 'label[0,0;'..S('Visuals')..']', + 'button[0,0.5;3,1;set_visibility;'..S('Visibility')..']', + 'button[0,1.5;3,1;set_position;'..S('Position')..']', + 'button[0,2.5;3,1;set_color;'..S('Color')..']', + 'container_end[]', + 'container[3.25,0]', + 'label[0,0;'..S('Time Representation')..']', + 'button[0,0.5;3,1;ingame_time_format;'..S('Ingame Time Format')..']', + 'button[0,1.5;3,1;real_world_time_format;'..S('Real-World Time Format')..']', + 'button[0,2.5;3,1;session_start_time_format;'..S('Session Start Time Format')..']', + 'button[0,3.5;3,1;session_duration_format;'..S('Session Duration Format')..']', + 'container_end[]', + 'container[6.5,0]', + 'label[0,0;'..S('Timer Configuration')..']', + 'button[0,0.5;3,1;timer_format;'..S('Timer Format')..']', + 'button[0,1.5;3,1;timezone_offset;'..S('Timezone Offset')..']', + 'container_end[]', + 'container[0,4.55]', + 'box[0,0;+linewidth,0.02;#ffffff]', + 'button[4.5,0.225;2.5,1;reset_everything;'..S('Reset Everything')..']', + 'button_exit[7,0.225;2.5,1;exit;'..S('Exit')..']', + 'container_end[]' + } + }) end mtimer.dialog.set_visibility = function (player_name) - minetest.show_formspec(player_name, 'mtimer:set_visibility', - build_frame(6, 2.25, S('Visibility'))..[[ - button[0,0.5;3,1;visible;]]..S('Visible')..[[] - button[3,0.5;3,1;invisible;]]..S('Invisible')..[[] - ]]) + mtimer.show_formspec('mtimer:set_visibility', { + title = S('Visibility'), + show_to = player_name, + formspec = { + 'button[0,0;3,1;visible;'..S('Visible')..']', + 'button[3,0;3,1;invisible;'..S('Invisible')..']' + } + }) end mtimer.dialog.set_position = function (player_name) - minetest.show_formspec(player_name, 'mtimer:set_position', - build_frame(8, 6.2, S('Position'))..[[ - - image_button[0,0.5;8,4.5 ;mtimer_positions_orientation.png;pos_xx;;;false] - - image_button[0,0.5;2.67,1.5;mtimer_transparent.png;pos_tl;;;false] - image_button[2.67,0.5;2.67,1.5;mtimer_transparent.png;pos_tc;;;false] - image_button[5.34,0.5;2.67,1.5;mtimer_transparent.png;pos_tr;;;false] - - image_button[0,2;2.67,1.5;mtimer_transparent.png;pos_ml;;;false] - image_button[2.67,2;2.67,1.5;mtimer_transparent.png;pos_mc;;;false] - image_button[5.34,2;2.67,1.5;mtimer_transparent.png;pos_mr;;;false] - - image_button[0,3.5;2.67,1.5;mtimer_transparent.png;pos_bl;;;false] - image_button[2.67,3.5;2.67,1.5;mtimer_transparent.png;pos_bc;;;false] - image_button[5.34,3.5;2.67,1.5;mtimer_transparent.png;pos_br;;;false] - - label[0,5;]]..S('Click the position you want to place the timer at.')..[[] - ]]) + mtimer.show_formspec('mtimer:set_position', { + title = S('Position'), + height = 5, + content_offset = 0.1, + show_to = player_name, + formspec = { + 'image_button[0,0;8,4.5 ;mtimer_positions_orientation.png;pos_xx;;;false]', + 'image_button[0,0;2.67,1.5;mtimer_transparent.png;pos_tl;;;false]', -- TL + 'image_button[2.67,0;2.67,1.5;mtimer_transparent.png;pos_tc;;;false]', -- TC + 'image_button[5.34,0;2.67,1.5;mtimer_transparent.png;pos_tr;;;false]', -- TR + 'image_button[0,1.5;2.67,1.5;mtimer_transparent.png;pos_ml;;;false]', -- ML + 'image_button[2.67,1.5;2.67,1.5;mtimer_transparent.png;pos_mc;;;false]', -- MC + 'image_button[5.34,1.5;2.67,1.5;mtimer_transparent.png;pos_mr;;;false]', -- MR + 'image_button[0,3;2.67,1.5;mtimer_transparent.png;pos_bl;;;false]', -- BL + 'image_button[2.67,3;2.67,1.5;mtimer_transparent.png;pos_bc;;;false]', -- BC + 'image_button[5.34,3;2.67,1.5;mtimer_transparent.png;pos_br;;;false]', -- BR + 'label[0,4.5;'..S('Click the position you want to place the timer at.')..']' + } + }) end @@ -95,13 +105,17 @@ mtimer.dialog.set_color = function (player_name) minetest.colorize('#729fcf', 'bb') }) - minetest.show_formspec(player_name, 'mtimer:set_color', - build_frame(6, 2.7, S('Color'))..[[ - field_close_on_enter[color;false] - field[0.25,0.75;3,1;color;;]]..color..[[] - box[3,0.55;0.65,0.65;]]..color..[[ff] - label[-0.05,1.45;]]..S('Use `@1` format only!', hexcolor)..[[] - ]]) + mtimer.show_formspec('mtimer:set_color', { + title = S('Color'), + show_to = player_name, + content_offset = 0.275, + formspec = { + 'field_close_on_enter[color;false]', + 'field[0.3,0;3,1;color;;'..color..']', + 'box[3,-0.2;0.65,0.65;'..color..'ff]', + 'label[0.025,0.60;'..S('Use `@1` format only!', hexcolor)..']' + } + }) end @@ -118,52 +132,45 @@ mtimer.dialog.timezone_offset = function (player_name) S('Local Time: @1', time_data.times.local_time) }, '\n') - minetest.show_formspec(player_name, 'mtimer:timezone_offset', - build_frame(7, 3.125, S('Timezone Offset'))..[[ - field_close_on_enter[offset;false] - field[0.25,0.75;3,1;offset;;]]..time_data.times.offset..[[] - label[3,0.425;]]..format_information..[[] - label[0,1.45;]]..time_information..[[] - ]]) + mtimer.show_formspec('mtimer:timezone_offset', { + title = S('Timezone Offset'), + show_to = player_name, + content_offset = 0.275, + formspec = { + 'field_close_on_enter[offset;false]', + 'field[0.3,0;3,1;offset;;'..time_data.times.offset..']', + 'label[3,-0.3;'..format_information..']', + 'label[0,0.55;'..time_information..']' + } + }) end mtimer.dialog.ingame_time_format = function (player_name) local time_data = mtimer.get_times(player_name).ingame_time - minetest.show_formspec(player_name, 'mtimer:ingame_time_format', - build_frame(7, 4.9, S('Ingame Time Format'))..[[ - field_close_on_enter[format;false] - field[0.25,0.75;7,1;format;;]]..fe(time_data.format)..[[] - container[0,1.425] - - label[2.8,0;]]..S('Variable')..[[] - label[4.25,0;]]..S('Current value')..[[] - - box[0,0.45;6.75,0.02;#ffffff] - - label[0,0.5;]]..S('Hours (24h)')..[[] - label[2.8,0.5;{24h}] - label[4.25,0.5;]]..time_data.hours_24..[[] - - label[0,0.9;]]..S('Hours (12h)')..[[] - label[2.8,0.9;{12h}] - label[4.25,0.9;]]..time_data.hours_12..[[] - - label[0,1.3;]]..S('Minutes')..[[] - label[2.8,1.3;{min}] - label[4.25,1.3;]]..time_data.minutes..[[] - - label[0,1.7;]]..S('Ingame Timestamp')..[[] - label[2.8,1.7;{its}] - label[4.25,1.7;]]..time_data.ingame_timestamp..[[] - - box[0,2.2;6.75,0.02;#ffffff] - - label[0,2.25;]]..S('Current Result')..[[] - label[2.8,2.25;]]..fe(time_data.formatted)..[[] - container_end[] - ]]) + mtimer.show_formspec('mtimer:ingame_time_format', { + title = S('Ingame Time Format'), + height = 3.5, + show_to = player_name, + content_offset = 0.275, + formspec = { + 'field_close_on_enter[format;false]', + 'field[0.3,0;+width,1;format;;'..fe(time_data.format)..']', + 'container[0,0.65]', + 'label[2.8,0;'..S('Variable')..']', + 'label[4.25,0;'..S('Current value')..']', + 'box[0,0.45;+linewidth,0.02;#ffffff]', + 'label[0,0.5;'..S('Hours (24h)')..'] label[2.8,0.5;{24h}] label[4.25,0.5;'..time_data.hours_24..']', + 'label[0,0.9;'..S('Hours (12h)')..'] label[2.8,0.9;{12h}] label[4.25,0.9;'..time_data.hours_12..']', + 'label[0,1.3;'..S('Minutes')..'] label[2.8,1.3;{min}] label[4.25,1.3;'..time_data.minutes..']', + 'label[0,1.7;'..S('Ingame Timestamp')..'] label[2.8,1.7;{its}] label[4.25,1.7;'..time_data.ingame_timestamp..']', + 'box[0,2.2;+linewidth,0.02;#ffffff]', + 'label[0,2.25;'..S('Current Result')..']', + 'label[2.8,2.25;'..fe(time_data.formatted)..']', + 'container_end[]' + } + }) end @@ -188,78 +195,52 @@ end mtimer.dialog.session_duration_format = function (player_name) local time_data = mtimer.get_times(player_name).session_duration - minetest.show_formspec(player_name, 'mtimer:session_duration_format', - build_frame(7, 5, S('Session Duration Format'))..[[ - field_close_on_enter[format;false] - field[0.25,0.75;7,1;format;;]]..fe(time_data.format)..[[] - - container[0,1.425] - - label[2.5,0;]]..S('Variable')..[[] - label[4,0;]]..S('Current value')..[[] - - box[0,0.45;6.75,0.02;#ffffff] - - label[0,0.5;]]..S('Days')..[[] - label[2.5,0.5;{days}] - label[4,0.5;]]..time_data.days..[[] - - label[0,0.9;]]..S('Hours')..[[] - label[2.5,0.9;{hours}] - label[4,0.9;]]..time_data.hours..[[] - - label[0,1.3;]]..S('Minutes')..[[] - label[2.5,1.3;{minutes}] - label[4,1.3;]]..time_data.minutes..[[] - - label[0,1.7;]]..S('Seconds')..[[] - label[2.5,1.7;{seconds}] - label[4,1.7;]]..time_data.seconds..[[] - - box[0,2.2;6.75,0.02;#ffffff] - - label[0,2.25;]]..S('Current Result')..[[] - label[2.5,2.25;]]..fe(time_data.formatted)..[[] - - container_end[] - ]]) + mtimer.show_formspec('mtimer:session_duration_format', { + title = S('Session Duration Format'), + show_to = player_name, + height = 3.425, + content_offset = 0.275, + formspec = { + 'field_close_on_enter[format;false]', + 'field[0.3,0;+width,1;format;;'..fe(time_data.format)..']', + 'container[0,0.65]', + 'label[2.5,0;'..S('Variable')..']', + 'label[4,0;'..S('Current value')..']', + 'box[0,0.45;+linewidth,0.02;#ffffff]', + 'label[0,0.5;'..S('Days')..'] label[2.5,0.5;{days}] label[4,0.5;'..time_data.days..']', + 'label[0,0.9;'..S('Hours')..'] label[2.5,0.9;{hours}] label[4,0.9;'..time_data.hours..']', + 'label[0,1.3;'..S('Minutes')..'] label[2.5,1.3;{minutes}] label[4,1.3;'..time_data.minutes..']', + 'label[0,1.7;'..S('Seconds')..'] label[2.5,1.7;{seconds}] label[4,1.7;'..time_data.seconds..']', + 'box[0,2.2;+linewidth,0.02;#ffffff]', + 'label[0,2.25;'..S('Current Result')..']', + 'label[2.5,2.25;'..fe(time_data.formatted)..']', + 'container_end[]' + } + }) end mtimer.dialog.timer_format = function (player_name) local timer_data = mtimer.get_timer_data(player_name) - minetest.show_formspec(player_name, 'mtimer:timer_format', - build_frame(9, 5.8, S('Timer Format'))..[[ - textarea[0.25,0.5;6,2.5;format;;]]..fe(timer_data.format)..[[] - container[0,2.785] - - label[2.5,0;]]..S('Variable')..[[] - label[4,0;]]..S('Current value')..[[] - - box[0,0.45;8.75,0.02;#ffffff] - - label[0,0.5;]]..S('Real-World Date')..[[] - label[2.5,0.5;{rd}] - label[4,0.5;]]..fe(timer_data.real_world_date)..[[] - - label[0,0.9;]]..S('In-Game Time')..[[] - label[2.5,0.9;{it}] - label[4,0.9;]]..fe(timer_data.ingame_time)..[[] - - label[0,1.3;]]..S('Session Start Time')..[[] - label[2.5,1.3;{st}] - label[4,1.3;]]..fe(timer_data.session_start_time)..[[] - - label[0,1.7;]]..S('Session Duration')..[[] - label[2.5,1.7;{sd}] - label[4,1.7;]]..fe(timer_data.session_duration)..[[] - - container_end[] - - container[6,0.45] - button[0,0;3,1;apply;]]..S('Apply')..[[] - container_end[] - - ]]) + mtimer.show_formspec('mtimer:timer_format', { + title = S('Timer Format'), + show_to = player_name, + height = 4.41, + formspec = { + 'textarea[0.3,0;6,2.5;format;;'..fe(timer_data.format)..']', + 'container[0,2.18]', + 'label[2.5,0;'..S('Variable')..']', + 'label[4,0;'..S('Current value')..']', + 'box[0,0.45;+linewidth,0.02;#ffffff]', + 'label[0,0.5;'..S('Real-World Date')..'] label[2.5,0.5;{rd}] label[4,0.5;'..fe(timer_data.real_world_date)..']', + 'label[0,0.9;'..S('In-Game Time')..'] label[2.5,0.9;{it}] label[4,0.9;'..fe(timer_data.ingame_time)..']', + 'label[0,1.3;'..S('Session Start Time')..'] label[2.5,1.3;{st}] label[4,1.3;'..fe(timer_data.session_start_time)..']', + 'label[0,1.7;'..S('Session Duration')..'] label[2.5,1.7;{sd}] label[4,1.7;'..fe(timer_data.session_duration)..']', + 'container_end[]', + 'container[6,0]', + 'button[0,-0.05;2,1;apply;'..S('Apply')..']', + 'container_end[]' + } + }) end diff --git a/system/formspec/formspec_helpers.lua b/system/formspec/formspec_helpers.lua index 147c68e..3ae07b8 100644 --- a/system/formspec/formspec_helpers.lua +++ b/system/formspec/formspec_helpers.lua @@ -4,38 +4,111 @@ local S = m.translator -- Build the formspec frame -- --- With this function the size and title of a formspec are set. It also adds --- the default buttons to the formspec. All calculations for the buttons are --- done automatically but directly correlate to the size of the formspec. +-- This function builds and displays a formspec based on the input. -- --- All formspecs are by minimum 6 units wide and 2 units high to allow enough --- space for the buttons and the button texts. +-- The `name` is the usual formspec name (for example `mymod:my_formspec`) and +-- has to be provided as a simple string all other parameters are provided via +-- the `def` table. The following table is an example. -- --- @param width The width of the formspec in formspec units --- @param height The height of the formspec in formspec units --- @param title The title for the formspec (a label shown on the formspec) +-- { +-- title = 'Nice Title' -- Automatically prefixed for orientation +-- prefix = '[Blarb] ' -- Optional title prefix +-- width = 8, -- Optional width of the content container +-- height = 3, -- Optional height of the content container +-- show_to = 'Playername' -- Name of the player to show the formspec to +-- add_buttons = false -- Optionally hide buttons +-- content_offset = 0 -- Optionally Offset content height position +-- formspec = {} -- Table with formspec definition +-- } +-- +-- When set the title is prefixed with the prefix value. If omitted “[mTimer] ” +-- is used. The example creates “[Blarb] Nice Title” as title. Translated +-- strings can be used here. The Title and prefix are “formspec-safe” so +-- strings that are formspec elements can be used to show them literal. +-- +-- The default buttons can be hidden by adding `add_buttons = false` to the +-- definition table. If omitted the buttons are shown. When not shown the +-- formspec size will be reduced by the amout of units the buttons would +-- have taken place. +-- +-- Some formspec elements do nbot properly start at 0,0 even if set so. The +-- `content_offset` attribute offsets the content vertically by the given +-- amount of units. Formspec height and button positions are fixed according +-- to the given value. +-- +-- The table entries for `formspec` are the usual formspec elements that +-- define what a formspec looks like. You can write all definition in one entry +-- or split the definition into multiple entries. +-- +-- The definition defines the CONTENT of the formspec not the whole formspec so +-- you can easily start at 0,0 for your definition. The function automatically +-- places everything in relation to the formspec frame and default buttons. +-- +-- The minimum formspec width and height are 8 units in width and 3 units in +-- height. So `width` and `height` can be omitted when all of your content fits +-- into the default size. The resulting formspec is a minimum of 8 units wide +-- and 4.6 units high (1.6 units are added for the title and the buttons). +-- +-- All formspec table entries can contain the following variables. Variables +-- start with a plus sign (+) and are read until any character that is not +-- a letter. Some variables are useless, some can be used quite well. +-- +-- Variable Name Value Type +-- -------------------------------------------------------------------------- +-- +width width of the formspec +-- +height height of the formspec +-- +linewidth optimal width for a box that is used as horizontal line +-- +title formspec’s title +-- +content content container vertical position (+offset) +-- +buttons default buttons vertical position +-- +defbutton “Default” button’s horizontal position +-- +mainbutton “Main Menu” button’s horizontal position +-- +exitbutton “Exit” button’s horizontal position +-- +-- @param name The name of the formspec +-- @param def The definition table as described -- @return string the constructed “frame” -mtimer.build_frame = function (width, height, title) - local formspec_frame = [[ - size[+width,+height] label[0,-0.125;+title] - container[0,+position] - button_exit[+exitpos,0;+bwidth,1;exit;]]..S('Exit')..[[] - button[+mainpos,0;+bwidth,1;main_menu;]]..S('Main Menu')..[[] - button[+defaultpos,0;+bwidth,1;default;]]..S('Default')..[[] - container_end[] - ]] +mtimer.show_formspec = function (name, def) + local add_buttons = def.add_buttons == true or def.add_buttons == nil + local content_offset = def.content_offset or 0 + local width = (def.width or 0) <= 8 and 8 or def.width + local height = (def.height or 0) <= 3 and 4.6 or def.height + 1.6 + local prefix = def.prefix or '[mTimer] ' + if not add_buttons then height = height - 1.6 end - local width = width < 6 and 6 or width - local height = height < 2 and 2 or height + height = height + content_offset - return formspec_frame:gsub('%+%a+', { + local buttons = not add_buttons and '' or table.concat({ + 'container[0,+buttons]', + 'box[0,0;+linewidth,0.02;#ffffff]', + 'button[+defbutton,0.2;2,1;default;'..S('Default')..']', + 'button[+mainbutton,0.2;2,1;main_menu;'..S('Main Menu')..']', + 'button_exit[+exitbutton,0.2;2,1;exit;'..S('Exit')..']', + 'container_end[]' + }, ' ') + + local formspec = table.concat({ + 'size[+width,+height]', + 'label[0,-0.1;+title]', + 'box[0,0.5;+linewidth,0.02;#ffffff]', + 'container[0,+content]', + table.concat(def.formspec, ' '), + 'container_end[]', + buttons + }, ' ') + + formspec = formspec:gsub('%+%a+', { ['+width'] = width, ['+height'] = height, - ['+title'] = minetest.formspec_escape('[mTimer] '..title), - ['+position'] = height-0.7, - ['+bwidth'] = width/3, - ['+exitpos'] = 0, - ['+mainpos'] = width/3, - ['+defaultpos'] = (width/3)*2 + ['+linewidth'] = width-0.215, + ['+title'] = minetest.formspec_escape(prefix..def.title), + ['+content'] = 0.7 + content_offset, + ['+buttons'] = height-0.8, + ['+defbutton'] = 0, + ['+mainbutton'] = width-4, + ['+exitbutton'] = width-2, + }) + + minetest.show_formspec(def.show_to, name, formspec) end diff --git a/system/formspec/real_time_universal.lua b/system/formspec/real_time_universal.lua index 3a83410..01ad1be 100644 --- a/system/formspec/real_time_universal.lua +++ b/system/formspec/real_time_universal.lua @@ -1,3 +1,10 @@ +-- # vim: nowrap +-- +-- Set Vim to no-wrapping mode because of some lines not fitting within the 80 +-- characters width limit due to overall readability of the code. + + +-- Localise needed functions local m = mtimer local S = m.translator local build_frame = m.build_frame @@ -18,77 +25,38 @@ local fe = minetest.formspec_escape mtimer.dialog.real_time_universal = function (player_name, config) local time_data = mtimer.get_times(player_name)[config.time_type] - minetest.show_formspec(player_name, config.formspec_name, - build_frame(7, 8.5, config.title)..[[ - field_close_on_enter[format;false] - field[0.25,0.75;7,1;format;;]]..fe(time_data.format)..[[] - container[0,1.425] - - label[2.8,0;]]..S('Variable')..[[] - label[4.6,0;]]..S('Current value')..[[] - - box[0,0.45;6.75,0.02;#ffffff] - - label[0,0.5;]]..S('Hours (24h)')..[[] - label[2.8,0.5;{24h}] - label[4.6,0.5;]]..time_data.variables.hours_24..[[] - - label[0,0.9;]]..S('Hours (12h)')..[[] - label[2.8,0.9;{12h}] - label[4.6,0.9;]]..time_data.variables.hours_12..[[] - - label[0,1.3;]]..S('Minutes')..[[] - label[2.8,1.3;{min}] - label[4.6,1.3;]]..time_data.variables.minutes..[[] - - label[0,1.7;]]..S('Seconds')..[[] - label[2.8,1.7;{sec}] - label[4.6,1.7;]]..time_data.variables.seconds..[[] - - box[0,2.18;6.75,0.02;#ffffff] - - label[0,2.2;]]..S('Day Name')..[[] - label[2.8,2.2;{dname}] - label[4.6,2.2;]]..time_data.variables.dayname..[[] - - label[0,2.6;]]..S('Month Name')..[[] - label[2.8,2.6;{mname}] - label[4.6,2.6;]]..time_data.variables.monthname..[[] - - box[0,3.05;6.75,0.02;#ffffff] - - label[0,3.1;]]..S('Year')..[[] - label[2.8,3.1;{year}] - label[4.6,3.1;]]..time_data.variables.year..[[] - - label[0,3.5;]]..S('Month')..[[] - label[2.8,3.5;{month}] - label[4.6,3.5;]]..time_data.variables.month..[[] - - label[0,3.9;]]..S('Day')..[[] - label[2.8,3.9;{day}] - label[4.6,3.9;]]..time_data.variables.day..[[] - - box[0,4.4;6.75,0.02;#ffffff] - - label[0,4.45;]]..S('ISO 8601 Date')..[[] - label[2.8,4.45;{isodate}] - label[4.6,4.45;]]..time_data.variables.iso8601_date..[[] - - label[0,4.85;]]..S('ISO 8601 Time')..[[] - label[2.8,4.85;{isotime}] - label[4.6,4.85;]]..time_data.variables.iso8601_time..[[] - - label[0,5.25;]]..S('Timestamp')..[[] - label[2.8,5.25;{timestamp}] - label[4.6,5.25;]]..time_data.variables.timestamp..[[] - - box[0,5.75;6.75,0.02;#ffffff] - - label[0,5.8;]]..S('Current Result')..[[] - label[2.8,5.8;]]..fe(time_data.formatted)..[[] - - container_end[] - ]]) + mtimer.show_formspec(config.formspec_name, { + title = config.title, + show_to = player_name, + height = 7, + content_offset = 0.275, + formspec = { + 'field_close_on_enter[format;false]', + 'field[0.3,0;+width,1;format;;'..fe(time_data.format)..']', + 'container[0,0.65]', + 'label[2.8,0;'..S('Variable')..']', + 'label[4.6,0;'..S('Current value')..']', + 'box[0,0.45;+linewidth,0.02;#ffffff]', + 'label[0,0.5;'..S('Hours (24h)')..'] label[2.8,0.5;{24h}] label[4.6,0.5;'..time_data.variables.hours_24..']', + 'label[0,0.9;'..S('Hours (12h)')..'] label[2.8,0.9;{12h}] label[4.6,0.9;'..time_data.variables.hours_12..']', + 'label[0,1.3;'..S('Minutes')..'] label[2.8,1.3;{min}] label[4.6,1.3;'..time_data.variables.minutes..']', + 'label[0,1.7;'..S('Seconds')..'] label[2.8,1.7;{sec}] label[4.6,1.7;'..time_data.variables.seconds..']', + 'box[0,2.18;+linewidth,0.02;#ffffff]', + 'label[0,2.2;'..S('Day Name')..'] label[2.8,2.2;{dname}] label[4.6,2.2;'..time_data.variables.dayname..']', + 'label[0,2.6;'..S('Month Name')..'] label[2.8,2.6;{mname}] label[4.6,2.6;'..time_data.variables.monthname..']', + 'box[0,3.05;+linewidth,0.02;#ffffff]', + 'label[0,3.1;'..S('Year')..'] label[2.8,3.1;{year}] label[4.6,3.1;'..time_data.variables.year..']', + 'label[0,3.5;'..S('Month')..'] label[2.8,3.5;{month}] label[4.6,3.5;'..time_data.variables.month..']', + 'label[0,3.9;'..S('Day')..'] label[2.8,3.9;{day}] label[4.6,3.9;'..time_data.variables.day..']', + 'box[0,4.4;+linewidth,0.02;#ffffff]', + 'label[0,4.45;'..S('ISO 8601 Date')..'] label[2.8,4.45;{isodate}] label[4.6,4.45;'..time_data.variables.iso8601_date..']', + 'label[0,4.85;'..S('ISO 8601 Time')..'] label[2.8,4.85;{isotime}] label[4.6,4.85;'..time_data.variables.iso8601_time..']', + 'label[0,5.25;'..S('Timestamp')..'] label[2.8,5.25;{timestamp}] label[4.6,5.25;'..time_data.variables.timestamp..']', + 'box[0,5.75;+linewidth,0.02;#ffffff]', + 'label[0,5.8;'..S('Current Result')..']', + 'label[2.8,5.8;'..fe(time_data.formatted)..']', + 'container_end[]' + } + }) end