2024-02-19 18:49:50 +00:00
--
-- Configuration GUI
--
local log = require ( " scada-common.log " )
local tcd = require ( " scada-common.tcd " )
local util = require ( " scada-common.util " )
local core = require ( " graphics.core " )
local DisplayBox = require ( " graphics.elements.displaybox " )
local Div = require ( " graphics.elements.div " )
local ListBox = require ( " graphics.elements.listbox " )
local MultiPane = require ( " graphics.elements.multipane " )
local TextBox = require ( " graphics.elements.textbox " )
local CheckBox = require ( " graphics.elements.controls.checkbox " )
local PushButton = require ( " graphics.elements.controls.push_button " )
local RadioButton = require ( " graphics.elements.controls.radio_button " )
local NumberField = require ( " graphics.elements.form.number_field " )
local TextField = require ( " graphics.elements.form.text_field " )
local println = util.println
local tri = util.trinary
local cpair = core.cpair
local LEFT = core.ALIGN . LEFT
local CENTER = core.ALIGN . CENTER
local RIGHT = core.ALIGN . RIGHT
-- changes to the config data/format to let the user know
local changes = { }
---@class pkt_configurator
local configurator = { }
local style = { }
style.root = cpair ( colors.black , colors.lightGray )
style.header = cpair ( colors.white , colors.gray )
style.colors = {
{ c = colors.red , hex = 0xdf4949 } ,
{ c = colors.orange , hex = 0xffb659 } ,
{ c = colors.yellow , hex = 0xfffc79 } ,
{ c = colors.lime , hex = 0x80ff80 } ,
{ c = colors.green , hex = 0x4aee8a } ,
{ c = colors.cyan , hex = 0x34bac8 } ,
{ c = colors.lightBlue , hex = 0x6cc0f2 } ,
{ c = colors.blue , hex = 0x0096ff } ,
{ c = colors.purple , hex = 0xb156ee } ,
{ c = colors.pink , hex = 0xf26ba2 } ,
{ c = colors.magenta , hex = 0xf9488a } ,
{ c = colors.lightGray , hex = 0xcacaca } ,
{ c = colors.gray , hex = 0x575757 }
}
local bw_fg_bg = cpair ( colors.black , colors.white )
local g_lg_fg_bg = cpair ( colors.gray , colors.lightGray )
local nav_fg_bg = bw_fg_bg
local btn_act_fg_bg = cpair ( colors.white , colors.gray )
local dis_fg_bg = cpair ( colors.lightGray , colors.white )
local tool_ctl = {
ask_config = false ,
has_config = false ,
viewing_config = false ,
importing_legacy = false ,
view_cfg = nil , ---@type graphics_element
settings_apply = nil , ---@type graphics_element
set_networked = nil , ---@type function
bundled_emcool = nil , ---@type function
gen_summary = nil , ---@type function
show_current_cfg = nil , ---@type function
load_legacy = nil , ---@type function
show_auth_key = nil , ---@type function
show_key_btn = nil , ---@type graphics_element
auth_key_textbox = nil , ---@type graphics_element
auth_key_value = " "
}
---@class pkt_config
local tmp_cfg = {
SVR_Channel = nil , ---@type integer
CRD_Channel = nil , ---@type integer
PKT_Channel = nil , ---@type integer
ConnTimeout = nil , ---@type number
TrustedRange = nil , ---@type number
AuthKey = nil , ---@type string|nil
LogMode = 0 ,
LogPath = " " ,
LogDebug = false ,
}
---@class pkt_config
local ini_cfg = { }
---@class pkt_config
local settings_cfg = { }
-- all settings fields, their nice names, and their default values
local fields = {
{ " SVR_Channel " , " SVR Channel " , 16240 } ,
{ " CRD_Channel " , " CRD Channel " , 16243 } ,
{ " PKT_Channel " , " PKT Channel " , 16244 } ,
{ " ConnTimeout " , " Connection Timeout " , 5 } ,
{ " TrustedRange " , " Trusted Range " , 0 } ,
{ " AuthKey " , " Facility Auth Key " , " " } ,
{ " LogMode " , " Log Mode " , log.MODE . APPEND } ,
{ " LogPath " , " Log Path " , " /log.txt " } ,
{ " LogDebug " , " Log Debug Messages " , false }
}
-- load data from the settings file
---@param target pkt_config
---@param raw boolean? true to not use default values
local function load_settings ( target , raw )
for _ , v in pairs ( fields ) do settings.unset ( v [ 1 ] ) end
local loaded = settings.load ( " /pocket.settings " )
for _ , v in pairs ( fields ) do target [ v [ 1 ] ] = settings.get ( v [ 1 ] , tri ( raw , nil , v [ 3 ] ) ) end
return loaded
end
-- create the config view
---@param display graphics_element
local function config_view ( display )
---@diagnostic disable-next-line: undefined-field
local function exit ( ) os.queueEvent ( " terminate " ) end
TextBox { parent = display , y = 1 , text = " Pocket Configurator " , alignment = CENTER , height = 1 , fg_bg = style.header }
local root_pane_div = Div { parent = display , x = 1 , y = 2 }
local main_page = Div { parent = root_pane_div , x = 1 , y = 1 }
local net_cfg = Div { parent = root_pane_div , x = 1 , y = 1 }
local log_cfg = Div { parent = root_pane_div , x = 1 , y = 1 }
local summary = Div { parent = root_pane_div , x = 1 , y = 1 }
local changelog = Div { parent = root_pane_div , x = 1 , y = 1 }
local main_pane = MultiPane { parent = root_pane_div , x = 1 , y = 1 , panes = { main_page , net_cfg , log_cfg , summary , changelog } }
-- Main Page
local y_start = 7
TextBox { parent = main_page , x = 2 , y = 2 , height = 4 , text = " Welcome to the Pocket configurator! Please select one of the following options. " }
if tool_ctl.ask_config then
TextBox { parent = main_page , x = 2 , y = y_start , height = 4 , width = 49 , text = " Please configure before starting up. " , fg_bg = cpair ( colors.red , colors.lightGray ) }
y_start = y_start + 3
end
local function view_config ( )
tool_ctl.viewing_config = true
tool_ctl.gen_summary ( settings_cfg )
tool_ctl.settings_apply . hide ( true )
main_pane.set_value ( 4 )
end
if fs.exists ( " /pocket/config.lua " ) then
PushButton { parent = main_page , x = 2 , y = y_start , min_width = 22 , text = " Import Legacy Config " , callback = function ( ) tool_ctl.load_legacy ( ) end , fg_bg = cpair ( colors.black , colors.cyan ) , active_fg_bg = btn_act_fg_bg }
y_start = y_start + 2
end
2024-02-20 00:36:27 +00:00
PushButton { parent = main_page , x = 2 , y = y_start , min_width = 18 , text = " Configure Device " , callback = function ( ) main_pane.set_value ( 2 ) end , fg_bg = cpair ( colors.black , colors.blue ) , active_fg_bg = btn_act_fg_bg }
2024-02-19 18:49:50 +00:00
tool_ctl.view_cfg = PushButton { parent = main_page , x = 2 , y = y_start + 2 , min_width = 20 , text = " View Configuration " , callback = view_config , fg_bg = cpair ( colors.black , colors.blue ) , active_fg_bg = btn_act_fg_bg , dis_fg_bg = dis_fg_bg }
if not tool_ctl.has_config then tool_ctl.view_cfg . disable ( ) end
PushButton { parent = main_page , x = 2 , y = 18 , min_width = 6 , text = " Exit " , callback = exit , fg_bg = cpair ( colors.black , colors.red ) , active_fg_bg = btn_act_fg_bg }
PushButton { parent = main_page , x = 14 , y = 18 , min_width = 12 , text = " Change Log " , callback = function ( ) main_pane.set_value ( 5 ) end , fg_bg = nav_fg_bg , active_fg_bg = btn_act_fg_bg }
--#region Network
local net_c_1 = Div { parent = net_cfg , x = 2 , y = 4 , width = 24 }
local net_c_2 = Div { parent = net_cfg , x = 2 , y = 4 , width = 24 }
local net_c_3 = Div { parent = net_cfg , x = 2 , y = 4 , width = 24 }
local net_c_4 = Div { parent = net_cfg , x = 2 , y = 4 , width = 24 }
local net_pane = MultiPane { parent = net_cfg , x = 1 , y = 4 , panes = { net_c_1 , net_c_2 , net_c_3 , net_c_4 } }
TextBox { parent = net_cfg , x = 1 , y = 2 , height = 1 , text = " Network Configuration " , fg_bg = cpair ( colors.black , colors.lightBlue ) }
TextBox { parent = net_c_1 , x = 1 , y = 1 , height = 1 , text = " Set network channels. " }
TextBox { parent = net_c_1 , x = 1 , y = 3 , height = 4 , text = " Each of the named channels must be the same within a particular SCADA network. " , fg_bg = g_lg_fg_bg }
TextBox { parent = net_c_1 , x = 1 , y = 8 , height = 1 , width = 18 , text = " Supervisor Channel " }
local svr_chan = NumberField { parent = net_c_1 , x = 1 , y = 9 , width = 7 , default = ini_cfg.SVR_Channel , min = 1 , max = 65535 , fg_bg = bw_fg_bg }
TextBox { parent = net_c_1 , x = 9 , y = 9 , height = 4 , text = " [SVR_CHANNEL] " , fg_bg = g_lg_fg_bg }
TextBox { parent = net_c_1 , x = 1 , y = 10 , height = 1 , width = 19 , text = " Coordinator Channel " }
local crd_chan = NumberField { parent = net_c_1 , x = 1 , y = 11 , width = 7 , default = ini_cfg.CRD_Channel , min = 1 , max = 65535 , fg_bg = bw_fg_bg }
TextBox { parent = net_c_1 , x = 9 , y = 11 , height = 4 , text = " [CRD_CHANNEL] " , fg_bg = g_lg_fg_bg }
TextBox { parent = net_c_1 , x = 1 , y = 12 , height = 1 , width = 14 , text = " Pocket Channel " }
local pkt_chan = NumberField { parent = net_c_1 , x = 1 , y = 13 , width = 7 , default = ini_cfg.PKT_Channel , min = 1 , max = 65535 , fg_bg = bw_fg_bg }
TextBox { parent = net_c_1 , x = 9 , y = 13 , height = 4 , text = " [PKT_CHANNEL] " , fg_bg = g_lg_fg_bg }
local chan_err = TextBox { parent = net_c_1 , x = 1 , y = 14 , height = 1 , width = 24 , text = " Please set all channels. " , fg_bg = cpair ( colors.red , colors.lightGray ) , hidden = true }
local function submit_channels ( )
local svr_c , crd_c , pkt_c = tonumber ( svr_chan.get_value ( ) ) , tonumber ( crd_chan.get_value ( ) ) , tonumber ( pkt_chan.get_value ( ) )
if svr_c ~= nil and crd_c ~= nil and pkt_c ~= nil then
tmp_cfg.SVR_Channel , tmp_cfg.CRD_Channel , tmp_cfg.PKT_Channel = svr_c , crd_c , pkt_c
net_pane.set_value ( 2 )
chan_err.hide ( true )
else chan_err.show ( ) end
end
PushButton { parent = net_c_1 , x = 1 , y = 15 , text = " \x1b Back " , callback = function ( ) main_pane.set_value ( 1 ) end , fg_bg = nav_fg_bg , active_fg_bg = btn_act_fg_bg }
PushButton { parent = net_c_1 , x = 19 , y = 15 , text = " Next \x1a " , callback = submit_channels , fg_bg = nav_fg_bg , active_fg_bg = btn_act_fg_bg }
TextBox { parent = net_c_2 , x = 1 , y = 1 , height = 1 , text = " Set connection timeout. " }
TextBox { parent = net_c_2 , x = 1 , y = 3 , height = 7 , text = " You generally should not need to modify this. On slow servers, you can try to increase this to make the system wait longer before assuming a disconnection. " , fg_bg = g_lg_fg_bg }
TextBox { parent = net_c_2 , x = 1 , y = 11 , height = 1 , width = 19 , text = " Connection Timeout " }
local timeout = NumberField { parent = net_c_2 , x = 1 , y = 12 , width = 7 , default = ini_cfg.ConnTimeout , min = 2 , max = 25 , max_chars = 6 , max_frac_digits = 2 , allow_decimal = true , fg_bg = bw_fg_bg }
TextBox { parent = net_c_2 , x = 9 , y = 12 , height = 2 , text = " seconds \n (default 5) " , fg_bg = g_lg_fg_bg }
local ct_err = TextBox { parent = net_c_2 , x = 1 , y = 14 , height = 1 , width = 24 , text = " Please set timeout. " , fg_bg = cpair ( colors.red , colors.lightGray ) , hidden = true }
local function submit_timeouts ( )
local timeout_val = tonumber ( timeout.get_value ( ) )
if timeout_val ~= nil then
tmp_cfg.ConnTimeout = timeout_val
net_pane.set_value ( 3 )
ct_err.hide ( true )
else ct_err.show ( ) end
end
PushButton { parent = net_c_2 , x = 1 , y = 15 , text = " \x1b Back " , callback = function ( ) net_pane.set_value ( 1 ) end , fg_bg = nav_fg_bg , active_fg_bg = btn_act_fg_bg }
PushButton { parent = net_c_2 , x = 19 , y = 15 , text = " Next \x1a " , callback = submit_timeouts , fg_bg = nav_fg_bg , active_fg_bg = btn_act_fg_bg }
TextBox { parent = net_c_3 , x = 1 , y = 1 , height = 1 , text = " Set the trusted range. " }
TextBox { parent = net_c_3 , x = 1 , y = 3 , height = 4 , text = " Setting this to a value larger than 0 prevents connections with devices that many blocks away. " , fg_bg = g_lg_fg_bg }
TextBox { parent = net_c_3 , x = 1 , y = 8 , height = 4 , text = " This is optional. You can disable this functionality by setting the value to 0. " , fg_bg = g_lg_fg_bg }
local range = NumberField { parent = net_c_3 , x = 1 , y = 13 , width = 10 , default = ini_cfg.TrustedRange , min = 0 , max_chars = 20 , allow_decimal = true , fg_bg = bw_fg_bg }
local tr_err = TextBox { parent = net_c_3 , x = 1 , y = 14 , height = 1 , width = 24 , text = " Set the trusted range. " , fg_bg = cpair ( colors.red , colors.lightGray ) , hidden = true }
local function submit_tr ( )
local range_val = tonumber ( range.get_value ( ) )
if range_val ~= nil then
tmp_cfg.TrustedRange = range_val
net_pane.set_value ( 4 )
tr_err.hide ( true )
else tr_err.show ( ) end
end
PushButton { parent = net_c_3 , x = 1 , y = 15 , text = " \x1b Back " , callback = function ( ) net_pane.set_value ( 2 ) end , fg_bg = nav_fg_bg , active_fg_bg = btn_act_fg_bg }
PushButton { parent = net_c_3 , x = 19 , y = 15 , text = " Next \x1a " , callback = submit_tr , fg_bg = nav_fg_bg , active_fg_bg = btn_act_fg_bg }
TextBox { parent = net_c_4 , x = 1 , y = 1 , height = 4 , text = " Optionally, set the facility authentication key. Do NOT use one of your passwords. " }
TextBox { parent = net_c_4 , x = 1 , y = 6 , height = 6 , text = " This enables verifying that messages are authentic, so it is intended for security on multiplayer servers. " , fg_bg = g_lg_fg_bg }
TextBox { parent = net_c_4 , x = 1 , y = 12 , height = 1 , text = " Facility Auth Key " }
local key , _ , censor = TextField { parent = net_c_4 , x = 1 , y = 13 , max_len = 64 , value = ini_cfg.AuthKey , width = 24 , height = 1 , fg_bg = bw_fg_bg }
local function censor_key ( enable ) censor ( util.trinary ( enable , " * " , nil ) ) end
2024-02-20 00:36:27 +00:00
-- declare back first so tabbing makes sense visually
PushButton { parent = net_c_4 , x = 1 , y = 15 , text = " \x1b Back " , callback = function ( ) net_pane.set_value ( 3 ) end , fg_bg = nav_fg_bg , active_fg_bg = btn_act_fg_bg }
2024-02-19 18:49:50 +00:00
local hide_key = CheckBox { parent = net_c_4 , x = 8 , y = 15 , label = " Hide Key " , box_fg_bg = cpair ( colors.lightBlue , colors.black ) , callback = censor_key }
hide_key.set_value ( true )
censor_key ( true )
local key_err = TextBox { parent = net_c_4 , x = 1 , y = 14 , height = 1 , width = 24 , text = " Length must be > 7. " , fg_bg = cpair ( colors.red , colors.lightGray ) , hidden = true }
local function submit_auth ( )
local v = key.get_value ( )
if string.len ( v ) == 0 or string.len ( v ) >= 8 then
tmp_cfg.AuthKey = key.get_value ( )
main_pane.set_value ( 3 )
key_err.hide ( true )
else key_err.show ( ) end
end
PushButton { parent = net_c_4 , x = 19 , y = 15 , text = " Next \x1a " , callback = submit_auth , fg_bg = nav_fg_bg , active_fg_bg = btn_act_fg_bg }
--#endregion
--#region Logging
local log_c_1 = Div { parent = log_cfg , x = 2 , y = 4 , width = 24 }
TextBox { parent = log_cfg , x = 1 , y = 2 , height = 1 , text = " Logging Configuration " , fg_bg = cpair ( colors.black , colors.pink ) }
TextBox { parent = log_c_1 , x = 1 , y = 1 , height = 1 , text = " Configure logging below. " }
TextBox { parent = log_c_1 , x = 1 , y = 3 , height = 1 , text = " Log File Mode " }
local mode = RadioButton { parent = log_c_1 , x = 1 , y = 4 , default = ini_cfg.LogMode + 1 , options = { " Append on Startup " , " Replace on Startup " } , callback = function ( ) end , radio_colors = cpair ( colors.lightGray , colors.black ) , select_color = colors.pink }
TextBox { parent = log_c_1 , x = 1 , y = 7 , height = 1 , text = " Log File Path " }
local path = TextField { parent = log_c_1 , x = 1 , y = 8 , width = 24 , height = 1 , value = ini_cfg.LogPath , max_len = 128 , fg_bg = bw_fg_bg }
local en_dbg = CheckBox { parent = log_c_1 , x = 1 , y = 10 , default = ini_cfg.LogDebug , label = " Enable Debug Messages " , box_fg_bg = cpair ( colors.pink , colors.black ) }
TextBox { parent = log_c_1 , x = 3 , y = 11 , height = 4 , text = " This results in much larger log files. Use only as needed. " , fg_bg = g_lg_fg_bg }
local path_err = TextBox { parent = log_c_1 , x = 1 , y = 14 , height = 1 , width = 24 , text = " Provide a log file path. " , fg_bg = cpair ( colors.red , colors.lightGray ) , hidden = true }
local function submit_log ( )
if path.get_value ( ) ~= " " then
path_err.hide ( true )
tmp_cfg.LogMode = mode.get_value ( ) - 1
tmp_cfg.LogPath = path.get_value ( )
tmp_cfg.LogDebug = en_dbg.get_value ( )
tool_ctl.gen_summary ( tmp_cfg )
tool_ctl.viewing_config = false
tool_ctl.importing_legacy = false
tool_ctl.settings_apply . show ( )
main_pane.set_value ( 4 )
else path_err.show ( ) end
end
PushButton { parent = log_c_1 , x = 1 , y = 15 , text = " \x1b Back " , callback = function ( ) main_pane.set_value ( 2 ) end , fg_bg = nav_fg_bg , active_fg_bg = btn_act_fg_bg }
PushButton { parent = log_c_1 , x = 19 , y = 15 , text = " Next \x1a " , callback = submit_log , fg_bg = nav_fg_bg , active_fg_bg = btn_act_fg_bg }
--#endregion
--#region Summary and Saving
local sum_c_1 = Div { parent = summary , x = 2 , y = 4 , width = 24 }
local sum_c_2 = Div { parent = summary , x = 2 , y = 4 , width = 24 }
local sum_c_3 = Div { parent = summary , x = 2 , y = 4 , width = 24 }
local sum_c_4 = Div { parent = summary , x = 2 , y = 4 , width = 24 }
local sum_pane = MultiPane { parent = summary , x = 1 , y = 4 , panes = { sum_c_1 , sum_c_2 , sum_c_3 , sum_c_4 } }
TextBox { parent = summary , x = 1 , y = 2 , height = 1 , text = " Summary " , fg_bg = cpair ( colors.black , colors.green ) }
local setting_list = ListBox { parent = sum_c_1 , x = 1 , y = 1 , height = 11 , width = 24 , scroll_height = 100 , fg_bg = bw_fg_bg , nav_fg_bg = g_lg_fg_bg , nav_active = cpair ( colors.black , colors.gray ) }
local function back_from_summary ( )
if tool_ctl.viewing_config or tool_ctl.importing_legacy then
main_pane.set_value ( 1 )
tool_ctl.viewing_config = false
tool_ctl.importing_legacy = false
tool_ctl.settings_apply . show ( )
else
main_pane.set_value ( 3 )
end
end
---@param element graphics_element
---@param data any
local function try_set ( element , data )
if data ~= nil then element.set_value ( data ) end
end
local function save_and_continue ( )
for k , v in pairs ( tmp_cfg ) do settings.set ( k , v ) end
if settings.save ( " pocket.settings " ) then
load_settings ( settings_cfg , true )
load_settings ( ini_cfg )
try_set ( svr_chan , ini_cfg.SVR_Channel )
try_set ( crd_chan , ini_cfg.CRD_Channel )
try_set ( pkt_chan , ini_cfg.PKT_Channel )
try_set ( timeout , ini_cfg.ConnTimeout )
try_set ( range , ini_cfg.TrustedRange )
try_set ( key , ini_cfg.AuthKey )
try_set ( mode , ini_cfg.LogMode )
try_set ( path , ini_cfg.LogPath )
try_set ( en_dbg , ini_cfg.LogDebug )
tool_ctl.view_cfg . enable ( )
if tool_ctl.importing_legacy then
tool_ctl.importing_legacy = false
sum_pane.set_value ( 3 )
else
sum_pane.set_value ( 2 )
end
else
sum_pane.set_value ( 4 )
end
end
PushButton { parent = sum_c_1 , x = 1 , y = 15 , text = " \x1b Back " , callback = back_from_summary , fg_bg = nav_fg_bg , active_fg_bg = btn_act_fg_bg }
tool_ctl.show_key_btn = PushButton { parent = sum_c_1 , x = 1 , y = 13 , min_width = 17 , text = " Unhide Auth Key " , callback = function ( ) tool_ctl.show_auth_key ( ) end , fg_bg = nav_fg_bg , active_fg_bg = btn_act_fg_bg , dis_fg_bg = dis_fg_bg }
tool_ctl.settings_apply = PushButton { parent = sum_c_1 , x = 18 , y = 15 , min_width = 7 , text = " Apply " , callback = save_and_continue , fg_bg = cpair ( colors.black , colors.green ) , active_fg_bg = btn_act_fg_bg }
TextBox { parent = sum_c_2 , x = 1 , y = 1 , height = 1 , text = " Settings saved! " }
local function go_home ( )
main_pane.set_value ( 1 )
net_pane.set_value ( 1 )
sum_pane.set_value ( 1 )
end
PushButton { parent = sum_c_2 , x = 1 , y = 15 , min_width = 6 , text = " Home " , callback = go_home , fg_bg = nav_fg_bg , active_fg_bg = btn_act_fg_bg }
PushButton { parent = sum_c_2 , x = 19 , y = 15 , min_width = 6 , text = " Exit " , callback = exit , fg_bg = cpair ( colors.black , colors.red ) , active_fg_bg = cpair ( colors.white , colors.gray ) }
2024-02-20 00:36:27 +00:00
TextBox { parent = sum_c_3 , x = 1 , y = 1 , height = 4 , text = " The old config.lua file will now be deleted, then the configurator will exit. " }
2024-02-19 18:49:50 +00:00
local function delete_legacy ( )
fs.delete ( " /pocket/config.lua " )
exit ( )
end
PushButton { parent = sum_c_3 , x = 1 , y = 15 , min_width = 8 , text = " Cancel " , callback = go_home , fg_bg = nav_fg_bg , active_fg_bg = btn_act_fg_bg }
PushButton { parent = sum_c_3 , x = 19 , y = 15 , min_width = 6 , text = " OK " , callback = delete_legacy , fg_bg = cpair ( colors.black , colors.green ) , active_fg_bg = cpair ( colors.white , colors.gray ) }
TextBox { parent = sum_c_4 , x = 1 , y = 1 , height = 8 , text = " Failed to save the settings file. \n \n There may not be enough space for the modification or server file permissions may be denying writes. " }
PushButton { parent = sum_c_4 , x = 1 , y = 15 , min_width = 6 , text = " Home " , callback = go_home , fg_bg = nav_fg_bg , active_fg_bg = btn_act_fg_bg }
PushButton { parent = sum_c_4 , x = 19 , y = 15 , min_width = 6 , text = " Exit " , callback = exit , fg_bg = cpair ( colors.black , colors.red ) , active_fg_bg = cpair ( colors.white , colors.gray ) }
--#endregion
-- Config Change Log
local cl = Div { parent = changelog , x = 2 , y = 4 , width = 24 }
TextBox { parent = changelog , x = 1 , y = 2 , height = 1 , text = " Config Change Log " , fg_bg = bw_fg_bg }
local c_log = ListBox { parent = cl , x = 1 , y = 1 , height = 13 , width = 24 , scroll_height = 100 , fg_bg = bw_fg_bg , nav_fg_bg = g_lg_fg_bg , nav_active = cpair ( colors.black , colors.gray ) }
for _ , change in ipairs ( changes ) do
TextBox { parent = c_log , text = change [ 1 ] , height = 1 , fg_bg = bw_fg_bg }
for _ , v in ipairs ( change [ 2 ] ) do
local e = Div { parent = c_log , height =# util.strwrap ( v , 21 ) }
TextBox { parent = e , y = 1 , x = 1 , text = " - " , height = 1 , fg_bg = cpair ( colors.gray , colors.white ) }
TextBox { parent = e , y = 1 , x = 3 , text = v , height = e.get_height ( ) , fg_bg = cpair ( colors.gray , colors.white ) }
end
end
PushButton { parent = cl , x = 1 , y = 15 , text = " \x1b Back " , callback = function ( ) main_pane.set_value ( 1 ) end , fg_bg = nav_fg_bg , active_fg_bg = btn_act_fg_bg }
-- set tool functions now that we have the elements
-- load a legacy config file
function tool_ctl . load_legacy ( )
local config = require ( " pocket.config " )
tmp_cfg.SVR_Channel = config.SVR_CHANNEL
tmp_cfg.CRD_Channel = config.CRD_CHANNEL
tmp_cfg.PKT_Channel = config.PKT_CHANNEL
tmp_cfg.ConnTimeout = config.COMMS_TIMEOUT
tmp_cfg.TrustedRange = config.TRUSTED_RANGE
tmp_cfg.AuthKey = config.AUTH_KEY or " "
tmp_cfg.LogMode = config.LOG_MODE
tmp_cfg.LogPath = config.LOG_PATH
tmp_cfg.LogDebug = config.LOG_DEBUG or false
tool_ctl.gen_summary ( tmp_cfg )
sum_pane.set_value ( 1 )
main_pane.set_value ( 4 )
tool_ctl.importing_legacy = true
end
-- expose the auth key on the summary page
function tool_ctl . show_auth_key ( )
tool_ctl.show_key_btn . disable ( )
tool_ctl.auth_key_textbox . set_value ( tool_ctl.auth_key_value )
end
-- generate the summary list
---@param cfg pkt_config
function tool_ctl . gen_summary ( cfg )
setting_list.remove_all ( )
local alternate = false
local inner_width = setting_list.get_width ( ) - 1
tool_ctl.show_key_btn . enable ( )
tool_ctl.auth_key_value = cfg.AuthKey or " " -- to show auth key
for i = 1 , # fields do
local f = fields [ i ]
local height = 1
local label_w = string.len ( f [ 2 ] )
local val_max_w = ( inner_width - label_w ) - 1
local raw = cfg [ f [ 1 ] ]
local val = util.strval ( raw )
if f [ 1 ] == " AuthKey " then val = string.rep ( " * " , string.len ( val ) )
elseif f [ 1 ] == " LogMode " then val = util.trinary ( raw == log.MODE . APPEND , " append " , " replace " )
end
if val == " nil " then val = " <not set> " end
local c = util.trinary ( alternate , g_lg_fg_bg , cpair ( colors.gray , colors.white ) )
alternate = not alternate
if string.len ( val ) > val_max_w then
local lines = util.strwrap ( val , inner_width )
height = # lines + 1
end
local line = Div { parent = setting_list , height = height , fg_bg = c }
TextBox { parent = line , text = f [ 2 ] , width = string.len ( f [ 2 ] ) , fg_bg = cpair ( colors.black , line.get_fg_bg ( ) . bkg ) }
local textbox
if height > 1 then
textbox = TextBox { parent = line , x = 1 , y = 2 , text = val , height = height - 1 , alignment = LEFT }
else
textbox = TextBox { parent = line , x = label_w + 1 , y = 1 , text = val , alignment = RIGHT }
end
if f [ 1 ] == " AuthKey " then tool_ctl.auth_key_textbox = textbox end
end
end
end
-- reset terminal screen
local function reset_term ( )
term.setTextColor ( colors.white )
term.setBackgroundColor ( colors.black )
term.clear ( )
term.setCursorPos ( 1 , 1 )
end
-- run the pcoket configurator
---@param ask_config? boolean indicate if this is being called by the startup app due to an invalid configuration
function configurator . configure ( ask_config )
tool_ctl.ask_config = ask_config == true
load_settings ( settings_cfg , true )
tool_ctl.has_config = load_settings ( ini_cfg )
reset_term ( )
-- set overridden colors
for i = 1 , # style.colors do
term.setPaletteColor ( style.colors [ i ] . c , style.colors [ i ] . hex )
end
local status , error = pcall ( function ( )
local display = DisplayBox { window = term.current ( ) , fg_bg = style.root }
config_view ( display )
while true do
local event , param1 , param2 , param3 = util.pull_event ( )
-- handle event
if event == " timer " then
tcd.handle ( param1 )
elseif event == " mouse_click " or event == " mouse_up " or event == " mouse_drag " or event == " mouse_scroll " or event == " double_click " then
local m_e = core.events . new_mouse_event ( event , param1 , param2 , param3 )
if m_e then display.handle_mouse ( m_e ) end
elseif event == " char " or event == " key " or event == " key_up " then
local k_e = core.events . new_key_event ( event , param1 , param2 )
if k_e then display.handle_key ( k_e ) end
elseif event == " paste " then
display.handle_paste ( param1 )
end
if event == " terminate " then return end
end
end )
-- restore colors
for i = 1 , # style.colors do
local r , g , b = term.nativePaletteColor ( style.colors [ i ] . c )
term.setPaletteColor ( style.colors [ i ] . c , r , g , b )
end
reset_term ( )
if not status then
println ( " configurator error: " .. error )
end
return status , error
end
return configurator