forked from MikaylaFischler/cc-mek-scada
-
Notifications
You must be signed in to change notification settings - Fork 0
/
configure.lua
1244 lines (967 loc) · 57.7 KB
/
configure.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
--
-- 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 themes = require("graphics.themes")
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 Radio2D = require("graphics.elements.controls.radio_2d")
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 IndLight = require("graphics.elements.indicators.light")
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 = {
{ "v1.2.12", { "Added front panel UI theme", "Added color accessibility modes" } },
{ "v1.3.2", { "Added standard with black off state color mode", "Added blue indicator color modes" } }
}
---@class svr_configurator
local configurator = {}
local style = {}
style.root = cpair(colors.black, colors.lightGray)
style.header = cpair(colors.white, colors.gray)
style.colors = themes.smooth_stone.colors
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)
---@class _svr_cfg_tool_ctl
local tool_ctl = {
ask_config = false,
has_config = false,
viewing_config = false,
importing_legacy = false,
jumped_to_color = false,
view_cfg = nil, ---@type graphics_element
color_cfg = nil, ---@type graphics_element
color_next = nil, ---@type graphics_element
color_apply = nil, ---@type graphics_element
settings_apply = nil, ---@type graphics_element
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 = "",
cooling_elems = {},
tank_elems = {},
vis_ftanks = {},
vis_utanks = {}
}
---@class svr_config
local tmp_cfg = {
UnitCount = 1,
CoolingConfig = {},
FacilityTankMode = 0,
FacilityTankDefs = {},
ExtChargeIdling = false,
SVR_Channel = nil, ---@type integer
PLC_Channel = nil, ---@type integer
RTU_Channel = nil, ---@type integer
CRD_Channel = nil, ---@type integer
PKT_Channel = nil, ---@type integer
PLC_Timeout = nil, ---@type number
RTU_Timeout = nil, ---@type number
CRD_Timeout = nil, ---@type number
PKT_Timeout = nil, ---@type number
TrustedRange = nil, ---@type number
AuthKey = nil, ---@type string|nil
LogMode = 0,
LogPath = "",
LogDebug = false,
FrontPanelTheme = 1,
ColorMode = 1
}
---@class svr_config
local ini_cfg = {}
---@class svr_config
local settings_cfg = {}
-- all settings fields, their nice names, and their default values
local fields = {
{ "UnitCount", "Number of Reactors", 1 },
{ "CoolingConfig", "Cooling Configuration", {} },
{ "FacilityTankMode", "Facility Tank Mode", 0 },
{ "FacilityTankDefs", "Facility Tank Definitions", {} },
{ "ExtChargeIdling", "Extended Charge Idling", false },
{ "SVR_Channel", "SVR Channel", 16240 },
{ "PLC_Channel", "PLC Channel", 16241 },
{ "RTU_Channel", "RTU Channel", 16242 },
{ "CRD_Channel", "CRD Channel", 16243 },
{ "PKT_Channel", "PKT Channel", 16244 },
{ "PLC_Timeout", "PLC Connection Timeout", 5 },
{ "RTU_Timeout", "RTU Connection Timeout", 5 },
{ "CRD_Timeout", "CRD Connection Timeout", 5 },
{ "PKT_Timeout", "PKT 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 },
{ "FrontPanelTheme", "Front Panel Theme", themes.FP_THEME.SANDSTONE },
{ "ColorMode", "Color Mode", themes.COLOR_MODE.STANDARD }
}
-- load data from the settings file
---@param target svr_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("/supervisor.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="Supervisor Configurator",alignment=CENTER,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 svr_cfg = 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 clr_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 import_err = Div{parent=root_pane_div,x=1,y=1}
local main_pane = MultiPane{parent=root_pane_div,x=1,y=1,panes={main_page,svr_cfg,net_cfg,log_cfg,clr_cfg,summary,changelog,import_err}}
-- Main Page
local y_start = 5
TextBox{parent=main_page,x=2,y=2,height=2,text="Welcome to the Supervisor 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="Notice: This device has no valid config so the configurator has been automatically started. If you previously had a valid config, you may want to check the Change Log to see what changed.",fg_bg=cpair(colors.red,colors.lightGray)}
y_start = y_start + 5
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(6)
end
if fs.exists("/supervisor/config.lua") then
PushButton{parent=main_page,x=2,y=y_start,min_width=28,text="Import Legacy 'config.lua'",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
PushButton{parent=main_page,x=2,y=y_start,min_width=18,text="Configure System",callback=function()main_pane.set_value(2)end,fg_bg=cpair(colors.black,colors.blue),active_fg_bg=btn_act_fg_bg}
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=cpair(colors.lightGray,colors.white)}
local function jump_color()
tool_ctl.jumped_to_color = true
tool_ctl.color_next.hide(true)
tool_ctl.color_apply.show()
main_pane.set_value(5)
end
PushButton{parent=main_page,x=2,y=17,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg}
tool_ctl.color_cfg = PushButton{parent=main_page,x=23,y=17,min_width=15,text="Color Options",callback=jump_color,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=cpair(colors.lightGray,colors.white)}
PushButton{parent=main_page,x=39,y=17,min_width=12,text="Change Log",callback=function()main_pane.set_value(7)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
if not tool_ctl.has_config then
tool_ctl.view_cfg.disable()
tool_ctl.color_cfg.disable()
end
--#region Facility
local svr_c_1 = Div{parent=svr_cfg,x=2,y=4,width=49}
local svr_c_2 = Div{parent=svr_cfg,x=2,y=4,width=49}
local svr_c_3 = Div{parent=svr_cfg,x=2,y=4,width=49}
local svr_c_4 = Div{parent=svr_cfg,x=2,y=4,width=49}
local svr_c_5 = Div{parent=svr_cfg,x=2,y=4,width=49}
local svr_c_6 = Div{parent=svr_cfg,x=2,y=4,width=49}
local svr_c_7 = Div{parent=svr_cfg,x=2,y=4,width=49}
local svr_pane = MultiPane{parent=svr_cfg,x=1,y=4,panes={svr_c_1,svr_c_2,svr_c_3,svr_c_4,svr_c_5,svr_c_6,svr_c_7}}
TextBox{parent=svr_cfg,x=1,y=2,text=" Facility Configuration",fg_bg=cpair(colors.black,colors.yellow)}
TextBox{parent=svr_c_1,x=1,y=1,height=3,text="Please enter the number of reactors you have, also referred to as reactor units or 'units' for short. A maximum of 4 is currently supported."}
local num_units = NumberField{parent=svr_c_1,x=1,y=5,width=5,max_chars=2,default=ini_cfg.UnitCount,min=1,max=4,fg_bg=bw_fg_bg}
TextBox{parent=svr_c_1,x=7,y=5,text="reactors"}
local nu_error = TextBox{parent=svr_c_1,x=8,y=14,width=35,text="Please set the number of reactors.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
local function submit_num_units()
local count = tonumber(num_units.get_value())
if count ~= nil and count > 0 and count < 5 then
nu_error.hide(true)
tmp_cfg.UnitCount = count
local confs = tool_ctl.cooling_elems
if count >= 2 then confs[2].line.show() else confs[2].line.hide(true) end
if count >= 3 then confs[3].line.show() else confs[3].line.hide(true) end
if count == 4 then confs[4].line.show() else confs[4].line.hide(true) end
svr_pane.set_value(2)
else nu_error.show() end
end
PushButton{parent=svr_c_1,x=1,y=14,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=svr_c_1,x=44,y=14,text="Next \x1a",callback=submit_num_units,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=svr_c_2,x=1,y=1,height=4,text="Please provide the reactor cooling configuration below. This includes the number of turbines, boilers, and if that reactor has a connection to a dynamic tank for emergency coolant."}
TextBox{parent=svr_c_2,x=1,y=6,text="UNIT TURBINES BOILERS HAS TANK CONNECTION?",fg_bg=g_lg_fg_bg}
for i = 1, 4 do
local num_t, num_b, has_t = 1, 0, false
if ini_cfg.CoolingConfig[i] then
local conf = ini_cfg.CoolingConfig[i]
if util.is_int(conf.TurbineCount) then num_t = math.min(3, math.max(1, conf.TurbineCount or 1)) end
if util.is_int(conf.BoilerCount) then num_b = math.min(2, math.max(0, conf.BoilerCount or 0)) end
has_t = conf.TankConnection == true
end
local line = Div{parent=svr_c_2,x=1,y=7+i,height=1}
TextBox{parent=line,text="Unit "..i,width=6}
local turbines = NumberField{parent=line,x=9,y=1,width=5,max_chars=2,default=num_t,min=1,max=3,fg_bg=bw_fg_bg}
local boilers = NumberField{parent=line,x=20,y=1,width=5,max_chars=2,default=num_b,min=0,max=2,fg_bg=bw_fg_bg}
local tank = CheckBox{parent=line,x=30,y=1,label="Is Connected",default=has_t,box_fg_bg=cpair(colors.yellow,colors.black)}
tool_ctl.cooling_elems[i] = { line = line, turbines = turbines, boilers = boilers, tank = tank }
end
local cool_err = TextBox{parent=svr_c_2,x=8,y=14,width=33,text="Please fill out all fields.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
local function submit_cooling()
local any_missing = false
for i = 1, tmp_cfg.UnitCount do
local conf = tool_ctl.cooling_elems[i]
any_missing = any_missing or (tonumber(conf.turbines.get_value()) == nil)
any_missing = any_missing or (tonumber(conf.boilers.get_value()) == nil)
end
if any_missing then
cool_err.show()
else
local any_has_tank = false
tmp_cfg.CoolingConfig = {}
for i = 1, tmp_cfg.UnitCount do
local conf = tool_ctl.cooling_elems[i]
tmp_cfg.CoolingConfig[i] = { TurbineCount = tonumber(conf.turbines.get_value()), BoilerCount = tonumber(conf.boilers.get_value()), TankConnection = conf.tank.get_value() }
if conf.tank.get_value() then any_has_tank = true end
end
for i = 1, 4 do
local elem = tool_ctl.tank_elems[i]
if i <= tmp_cfg.UnitCount then
elem.div.show()
if tmp_cfg.CoolingConfig[i].TankConnection then
elem.no_tank.hide()
elem.tank_opt.show()
else
elem.tank_opt.hide(true)
elem.no_tank.show()
end
else elem.div.hide(true) end
end
if any_has_tank then svr_pane.set_value(3) else main_pane.set_value(3) end
end
end
PushButton{parent=svr_c_2,x=1,y=14,text="\x1b Back",callback=function()svr_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=svr_c_2,x=44,y=14,text="Next \x1a",callback=submit_cooling,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=svr_c_3,x=1,y=1,height=6,text="You have set one or more of your units to use dynamic tanks for emergency coolant. You have two paths for configuration. The first is to assign dynamic tanks to reactor units; one tank per reactor, only connected to that reactor. RTU configurations must also assign it as such."}
TextBox{parent=svr_c_3,x=1,y=8,height=3,text="Alternatively, you can configure them as facility tanks to connect to multiple reactor units. These can intermingle with unit-specific tanks."}
local en_fac_tanks = CheckBox{parent=svr_c_3,x=1,y=12,label="Use Facility Dynamic Tanks",default=ini_cfg.FacilityTankMode>0,box_fg_bg=cpair(colors.yellow,colors.black)}
local function submit_en_fac_tank()
if en_fac_tanks.get_value() then
svr_pane.set_value(4)
tmp_cfg.FacilityTankMode = util.trinary(tmp_cfg.FacilityTankMode == 0, 1, math.min(8, math.max(1, ini_cfg.FacilityTankMode)))
else
tmp_cfg.FacilityTankMode = 0
tmp_cfg.FacilityTankDefs = {}
svr_pane.set_value(7)
end
end
PushButton{parent=svr_c_3,x=1,y=14,text="\x1b Back",callback=function()svr_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=svr_c_3,x=44,y=14,text="Next \x1a",callback=submit_en_fac_tank,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=svr_c_4,x=1,y=1,height=4,text="Please set unit connections to dynamic tanks, selecting at least one facility tank. The layout for facility tanks will be configured next."}
for i = 1, 4 do
local val = math.max(1, ini_cfg.FacilityTankDefs[i] or 2)
local div = Div{parent=svr_c_4,x=1,y=3+(2*i),height=2}
TextBox{parent=div,x=1,y=1,width=33,text="Unit "..i.." will be connected to..."}
TextBox{parent=div,x=6,y=2,width=3,text="..."}
local tank_opt = Radio2D{parent=div,x=9,y=2,rows=1,columns=2,default=val,options={"its own Unit Tank","a Facility Tank"},radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.yellow,disable_color=colors.gray,disable_fg_bg=g_lg_fg_bg}
local no_tank = TextBox{parent=div,x=9,y=2,width=34,text="no tank (as you set two steps ago)",fg_bg=cpair(colors.gray,colors.lightGray),hidden=true}
tool_ctl.tank_elems[i] = { div = div, tank_opt = tank_opt, no_tank = no_tank }
end
local tank_err = TextBox{parent=svr_c_4,x=8,y=14,width=33,text="You selected no facility tanks.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
local function hide_fconn(i)
if i > 1 then tool_ctl.vis_ftanks[i].pipe_conn.hide(true)
else tool_ctl.vis_ftanks[i].line.hide(true) end
end
local function submit_tank_defs()
local any_fac = false
tmp_cfg.FacilityTankDefs = {}
for i = 1, tmp_cfg.UnitCount do
local def
if tmp_cfg.CoolingConfig[i].TankConnection then
def = tool_ctl.tank_elems[i].tank_opt.get_value()
any_fac = any_fac or (def == 2)
else def = 0 end
if def == 1 then
tool_ctl.vis_utanks[i].line.show()
tool_ctl.vis_utanks[i].label.set_value("Tank U" .. i)
hide_fconn(i)
else
if def == 2 then
if i > 1 then tool_ctl.vis_ftanks[i].pipe_conn.show()
else tool_ctl.vis_ftanks[i].line.show() end
else hide_fconn(i) end
tool_ctl.vis_utanks[i].line.hide(true)
end
tmp_cfg.FacilityTankDefs[i] = def
end
for i = tmp_cfg.UnitCount + 1, 4 do
tool_ctl.vis_utanks[i].line.hide(true)
end
tool_ctl.vis_draw(tmp_cfg.FacilityTankMode)
if any_fac then
tank_err.hide(true)
svr_pane.set_value(5)
else tank_err.show() end
end
PushButton{parent=svr_c_4,x=1,y=14,text="\x1b Back",callback=function()svr_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=svr_c_4,x=44,y=14,text="Next \x1a",callback=submit_tank_defs,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=svr_c_5,x=1,y=1,text="Please select your dynamic tank layout."}
TextBox{parent=svr_c_5,x=12,y=3,text="Facility Tanks Unit Tanks",fg_bg=g_lg_fg_bg}
--#region Tank Layout Visualizer
local pipe_cpair = cpair(colors.blue,colors.lightGray)
local vis = Div{parent=svr_c_5,x=14,y=5,height=7}
local vis_unit_list = TextBox{parent=vis,x=15,y=1,width=6,height=7,text="Unit 1\n\nUnit 2\n\nUnit 3\n\nUnit 4"}
-- draw unit tanks and their pipes
for i = 1, 4 do
local line = Div{parent=vis,x=22,y=(i*2)-1,width=13,height=1}
TextBox{parent=line,width=5,text=string.rep("\x8c",5),fg_bg=pipe_cpair}
local label = TextBox{parent=line,x=7,y=1,width=7,text="Tank ?"}
tool_ctl.vis_utanks[i] = { line = line, label = label }
end
-- draw facility tank connections
local ftank_1 = Div{parent=vis,x=1,y=1,width=13,height=1}
TextBox{parent=ftank_1,width=7,text="Tank F1"}
tool_ctl.vis_ftanks[1] = {
line = ftank_1, pipe_direct = TextBox{parent=ftank_1,x=9,y=1,width=5,text=string.rep("\x8c",5),fg_bg=pipe_cpair}
}
for i = 2, 4 do
local line = Div{parent=vis,x=1,y=(i-1)*2,width=13,height=2}
local pipe_conn = TextBox{parent=line,x=13,y=2,width=1,text="\x8c",fg_bg=pipe_cpair}
local pipe_chain = TextBox{parent=line,x=12,y=1,width=1,height=2,text="\x95\n\x8d",fg_bg=pipe_cpair}
local pipe_direct = TextBox{parent=line,x=9,y=2,width=4,text="\x8c\x8c\x8c\x8c",fg_bg=pipe_cpair}
local label = TextBox{parent=line,x=1,y=2,width=7,text=""}
tool_ctl.vis_ftanks[i] = { line = line, pipe_conn = pipe_conn, pipe_chain = pipe_chain, pipe_direct = pipe_direct, label = label }
end
-- draw the pipe visualization
---@param mode integer pipe mode
function tool_ctl.vis_draw(mode)
-- is a facility tank connected to this unit
---@param i integer unit 1 - 4
---@return boolean connected
local function is_ft(i) return tmp_cfg.FacilityTankDefs[i] == 2 end
local u_text = ""
for i = 1, tmp_cfg.UnitCount do
u_text = u_text .. "Unit " .. i .. "\n\n"
end
vis_unit_list.set_value(u_text)
local next_idx = 1
if is_ft(1) then
next_idx = 2
if (mode == 1 and (is_ft(2) or is_ft(3) or is_ft(4))) or (mode == 2 and (is_ft(2) or is_ft(3))) or ((mode == 3 or mode == 5) and is_ft(2)) then
tool_ctl.vis_ftanks[1].pipe_direct.set_value("\x8c\x8c\x8c\x9c\x8c")
else
tool_ctl.vis_ftanks[1].pipe_direct.set_value(string.rep("\x8c",5))
end
end
local _2_12_need_passt = (mode == 1 and (is_ft(3) or is_ft(4))) or (mode == 2 and is_ft(3))
local _2_46_need_chain = (mode == 4 and (is_ft(3) or is_ft(4))) or (mode == 6 and is_ft(3))
if is_ft(2) then
tool_ctl.vis_ftanks[2].label.set_value("Tank F" .. next_idx)
if (mode < 4 or mode == 5) and is_ft(1) then
tool_ctl.vis_ftanks[2].label.hide(true)
tool_ctl.vis_ftanks[2].pipe_direct.hide(true)
if _2_12_need_passt then
tool_ctl.vis_ftanks[2].pipe_chain.set_value("\x95\n\x9d")
else
tool_ctl.vis_ftanks[2].pipe_chain.set_value("\x95\n\x8d")
end
tool_ctl.vis_ftanks[2].pipe_chain.show()
else
tool_ctl.vis_ftanks[2].label.show()
next_idx = next_idx + 1
tool_ctl.vis_ftanks[2].pipe_chain.hide(true)
if _2_12_need_passt or _2_46_need_chain then
tool_ctl.vis_ftanks[2].pipe_direct.set_value("\x8c\x8c\x8c\x9c")
else
tool_ctl.vis_ftanks[2].pipe_direct.set_value("\x8c\x8c\x8c\x8c")
end
tool_ctl.vis_ftanks[2].pipe_direct.show()
end
tool_ctl.vis_ftanks[2].line.show()
elseif is_ft(1) and _2_12_need_passt then
tool_ctl.vis_ftanks[2].label.hide(true)
tool_ctl.vis_ftanks[2].pipe_direct.hide(true)
tool_ctl.vis_ftanks[2].pipe_chain.set_value("\x95\n\x95")
tool_ctl.vis_ftanks[2].pipe_chain.show()
tool_ctl.vis_ftanks[2].line.show()
else
tool_ctl.vis_ftanks[2].line.hide(true)
end
if is_ft(3) then
tool_ctl.vis_ftanks[3].label.set_value("Tank F" .. next_idx)
if (mode < 3 and (is_ft(1) or is_ft(2))) or ((mode == 4 or mode == 6) and is_ft(2)) then
tool_ctl.vis_ftanks[3].label.hide(true)
tool_ctl.vis_ftanks[3].pipe_direct.hide(true)
if (mode == 1 or mode == 4) and is_ft(4) then
tool_ctl.vis_ftanks[3].pipe_chain.set_value("\x95\n\x9d")
else
tool_ctl.vis_ftanks[3].pipe_chain.set_value("\x95\n\x8d")
end
tool_ctl.vis_ftanks[3].pipe_chain.show()
else
tool_ctl.vis_ftanks[3].label.show()
next_idx = next_idx + 1
tool_ctl.vis_ftanks[3].pipe_chain.hide(true)
if (mode == 1 or mode == 3 or mode == 4 or mode == 7) and is_ft(4) then
tool_ctl.vis_ftanks[3].pipe_direct.set_value("\x8c\x8c\x8c\x9c")
else
tool_ctl.vis_ftanks[3].pipe_direct.set_value("\x8c\x8c\x8c\x8c")
end
tool_ctl.vis_ftanks[3].pipe_direct.show()
end
tool_ctl.vis_ftanks[3].line.show()
elseif (mode == 1 and is_ft(4) and (is_ft(1) or is_ft(2))) or (mode == 4 and is_ft(2) and is_ft(4)) then
tool_ctl.vis_ftanks[3].label.hide(true)
tool_ctl.vis_ftanks[3].pipe_direct.hide(true)
tool_ctl.vis_ftanks[3].pipe_chain.set_value("\x95\n\x95")
tool_ctl.vis_ftanks[3].pipe_chain.show()
tool_ctl.vis_ftanks[3].line.show()
else
tool_ctl.vis_ftanks[3].line.hide(true)
end
if is_ft(4) then
tool_ctl.vis_ftanks[4].label.set_value("Tank F" .. next_idx)
if (mode == 1 and (is_ft(1) or is_ft(2) or is_ft(3))) or ((mode == 3 or mode == 7) and is_ft(3)) or (mode == 4 and (is_ft(2) or is_ft(3))) then
tool_ctl.vis_ftanks[4].label.hide(true)
tool_ctl.vis_ftanks[4].pipe_direct.hide(true)
tool_ctl.vis_ftanks[4].pipe_chain.show()
else
tool_ctl.vis_ftanks[4].label.show()
tool_ctl.vis_ftanks[4].pipe_chain.hide(true)
tool_ctl.vis_ftanks[4].pipe_direct.show()
end
tool_ctl.vis_ftanks[4].line.show()
else
tool_ctl.vis_ftanks[4].line.hide(true)
end
end
local tank_modes = { "Mode 1", "Mode 2", "Mode 3", "Mode 4", "Mode 5", "Mode 6", "Mode 7", "Mode 8" }
local tank_mode = RadioButton{parent=svr_c_5,x=1,y=4,callback=tool_ctl.vis_draw,default=math.max(1,ini_cfg.FacilityTankMode),options=tank_modes,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.yellow}
--#endregion
local function submit_mode()
tmp_cfg.FacilityTankMode = tank_mode.get_value()
svr_pane.set_value(7)
end
PushButton{parent=svr_c_5,x=1,y=14,text="\x1b Back",callback=function()svr_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=svr_c_5,x=44,y=14,text="Next \x1a",callback=submit_mode,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=svr_c_5,x=8,y=14,min_width=7,text="About",callback=function()svr_pane.set_value(6)end,fg_bg=cpair(colors.black,colors.lightBlue),active_fg_bg=btn_act_fg_bg}
TextBox{parent=svr_c_6,height=3,text="This visualization tool shows the pipe connections required for a particular dynamic tank configuration you have selected."}
TextBox{parent=svr_c_6,y=5,height=4,text="Examples: A U2 tank should be configured on an RTU as the dynamic tank for unit #2. An F3 tank should be configured on an RTU as the #3 dynamic tank for the facility."}
TextBox{parent=svr_c_6,y=10,height=3,text="Some modes may look the same if you are not using 4 total reactor units. The wiki has details. Modes that look the same will function the same.",fg_bg=g_lg_fg_bg}
PushButton{parent=svr_c_6,x=1,y=14,text="\x1b Back",callback=function()svr_pane.set_value(5)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=svr_c_7,height=6,text="Charge control provides automatic control to maintain an induction matrix charge level. In order to have smoother control, reactors that were activated will be held on at 0.01 mB/t for a short period before allowing them to turn off. This minimizes overshooting the charge target."}
TextBox{parent=svr_c_7,y=8,height=3,text="You can extend this to a full minute to minimize reactors flickering on/off, but there may be more overshoot of the target."}
local ext_idling = CheckBox{parent=svr_c_7,x=1,y=12,label="Enable Extended Idling",default=ini_cfg.ExtChargeIdling,box_fg_bg=cpair(colors.yellow,colors.black)}
local function back_from_idling()
svr_pane.set_value(util.trinary(tmp_cfg.FacilityTankMode == 0, 3, 5))
end
local function submit_idling()
tmp_cfg.ExtChargeIdling = ext_idling.get_value()
main_pane.set_value(3)
end
PushButton{parent=svr_c_7,x=1,y=14,text="\x1b Back",callback=back_from_idling,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=svr_c_7,x=44,y=14,text="Next \x1a",callback=submit_idling,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
--#region Network
local net_c_1 = Div{parent=net_cfg,x=2,y=4,width=49}
local net_c_2 = Div{parent=net_cfg,x=2,y=4,width=49}
local net_c_3 = Div{parent=net_cfg,x=2,y=4,width=49}
local net_c_4 = Div{parent=net_cfg,x=2,y=4,width=49}
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,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)}
TextBox{parent=net_c_1,x=1,y=1,text="Please set the network channels below."}
TextBox{parent=net_c_1,x=1,y=3,height=4,text="Each of the 5 uniquely named channels must be the same for each device in this SCADA network. For multiplayer servers, it is recommended to not use the default channels.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_1,x=1,y=8,width=18,text="Supervisor Channel"}
local svr_chan = NumberField{parent=net_c_1,x=21,y=8,width=7,default=ini_cfg.SVR_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_1,x=29,y=8,height=4,text="[SVR_CHANNEL]",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_1,x=1,y=9,width=11,text="PLC Channel"}
local plc_chan = NumberField{parent=net_c_1,x=21,y=9,width=7,default=ini_cfg.PLC_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_1,x=29,y=9,height=4,text="[PLC_CHANNEL]",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_1,x=1,y=10,width=19,text="RTU Gateway Channel"}
local rtu_chan = NumberField{parent=net_c_1,x=21,y=10,width=7,default=ini_cfg.RTU_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_1,x=29,y=10,height=4,text="[RTU_CHANNEL]",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_1,x=1,y=11,width=19,text="Coordinator Channel"}
local crd_chan = NumberField{parent=net_c_1,x=21,y=11,width=7,default=ini_cfg.CRD_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_1,x=29,y=11,height=4,text="[CRD_CHANNEL]",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_1,x=1,y=12,width=14,text="Pocket Channel"}
local pkt_chan = NumberField{parent=net_c_1,x=21,y=12,width=7,default=ini_cfg.PKT_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_1,x=29,y=12,height=4,text="[PKT_CHANNEL]",fg_bg=g_lg_fg_bg}
local chan_err = TextBox{parent=net_c_1,x=8,y=14,width=35,text="Please set all channels.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
local function submit_channels()
local svr_c, plc_c, rtu_c = tonumber(svr_chan.get_value()), tonumber(plc_chan.get_value()), tonumber(rtu_chan.get_value())
local crd_c, pkt_c = tonumber(crd_chan.get_value()), tonumber(pkt_chan.get_value())
if svr_c ~= nil and plc_c ~= nil and rtu_c ~= nil and crd_c ~= nil and pkt_c ~= nil then
tmp_cfg.SVR_Channel, tmp_cfg.PLC_Channel, tmp_cfg.RTU_Channel = svr_c, plc_c, rtu_c
tmp_cfg.CRD_Channel, tmp_cfg.PKT_Channel = 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=14,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=net_c_1,x=44,y=14,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,text="Please set the connection timeouts below."}
TextBox{parent=net_c_2,x=1,y=3,height=4,text="You generally should not need to modify these. On slow servers, you can try to increase this to make the system wait longer before assuming a disconnection. The default for all is 5 seconds.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_2,x=1,y=8,width=11,text="PLC Timeout"}
local plc_timeout = NumberField{parent=net_c_2,x=21,y=8,width=7,default=ini_cfg.PLC_Timeout,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=1,y=9,width=19,text="RTU Gateway Timeout"}
local rtu_timeout = NumberField{parent=net_c_2,x=21,y=9,width=7,default=ini_cfg.RTU_Timeout,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=1,y=10,width=19,text="Coordinator Timeout"}
local crd_timeout = NumberField{parent=net_c_2,x=21,y=10,width=7,default=ini_cfg.CRD_Timeout,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=1,y=11,width=14,text="Pocket Timeout"}
local pkt_timeout = NumberField{parent=net_c_2,x=21,y=11,width=7,default=ini_cfg.PKT_Timeout,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=29,y=8,height=4,width=7,text="seconds\nseconds\nseconds\nseconds",fg_bg=g_lg_fg_bg}
local ct_err = TextBox{parent=net_c_2,x=8,y=14,width=35,text="Please set all connection timeouts.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
local function submit_timeouts()
local plc_cto, rtu_cto, crd_cto, pkt_cto = tonumber(plc_timeout.get_value()), tonumber(rtu_timeout.get_value()), tonumber(crd_timeout.get_value()), tonumber(pkt_timeout.get_value())
if plc_cto ~= nil and rtu_cto ~= nil and crd_cto ~= nil and pkt_cto ~= nil then
tmp_cfg.PLC_Timeout, tmp_cfg.RTU_Timeout, tmp_cfg.CRD_Timeout, tmp_cfg.PKT_Timeout = plc_cto, rtu_cto, crd_cto, pkt_cto
net_pane.set_value(3)
ct_err.hide(true)
else ct_err.show() end
end
PushButton{parent=net_c_2,x=1,y=14,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=44,y=14,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,text="Please set the trusted range below."}
TextBox{parent=net_c_3,x=1,y=3,height=3,text="Setting this to a value larger than 0 prevents connections with devices that many meters (blocks) away in any direction.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,x=1,y=7,height=2,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=10,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=8,y=14,width=35,text="Please 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=14,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=44,y=14,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=2,text="Optionally, set the facility authentication key below. Do NOT use one of your passwords."}
TextBox{parent=net_c_4,x=1,y=4,height=6,text="This enables verifying that messages are authentic, so it is intended for security on multiplayer servers. All devices on the same network MUST use the same key if any device has a key. This does result in some extra compution (can slow things down).",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_4,x=1,y=11,text="Facility Auth Key"}
local key, _, censor = TextField{parent=net_c_4,x=1,y=12,max_len=64,value=ini_cfg.AuthKey,width=32,height=1,fg_bg=bw_fg_bg}
local function censor_key(enable) censor(util.trinary(enable, "*", nil)) end
local hide_key = CheckBox{parent=net_c_4,x=34,y=12,label="Hide",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=8,y=14,width=35,text="Key must be at least 8 characters.",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(4)
key_err.hide(true)
else key_err.show() end
end
PushButton{parent=net_c_4,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_4,x=44,y=14,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=49}
TextBox{parent=log_cfg,x=1,y=2,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)}
TextBox{parent=log_c_1,x=1,y=1,text="Please configure logging below."}
TextBox{parent=log_c_1,x=1,y=3,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,text="Log File Path"}
local path = TextField{parent=log_c_1,x=1,y=8,width=49,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 Logging Debug Messages",box_fg_bg=cpair(colors.pink,colors.black)}
TextBox{parent=log_c_1,x=3,y=11,height=2,text="This results in much larger log files. It is best to only use this when there is a problem.",fg_bg=g_lg_fg_bg}
local path_err = TextBox{parent=log_c_1,x=8,y=14,width=35,text="Please 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.color_apply.hide(true)
tool_ctl.color_next.show()
main_pane.set_value(5)
else path_err.show() end
end
PushButton{parent=log_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=log_c_1,x=44,y=14,text="Next \x1a",callback=submit_log,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
--#region Color Options
local clr_c_1 = Div{parent=clr_cfg,x=2,y=4,width=49}
local clr_c_2 = Div{parent=clr_cfg,x=2,y=4,width=49}
local clr_c_3 = Div{parent=clr_cfg,x=2,y=4,width=49}
local clr_c_4 = Div{parent=clr_cfg,x=2,y=4,width=49}
local clr_pane = MultiPane{parent=clr_cfg,x=1,y=4,panes={clr_c_1,clr_c_2,clr_c_3,clr_c_4}}
TextBox{parent=clr_cfg,x=1,y=2,text=" Color Configuration",fg_bg=cpair(colors.black,colors.magenta)}
TextBox{parent=clr_c_1,x=1,y=1,height=2,text="Here you can select the color theme for the front panel."}
TextBox{parent=clr_c_1,x=1,y=4,height=2,text="Click 'Accessibility' below to access colorblind assistive options.",fg_bg=g_lg_fg_bg}
TextBox{parent=clr_c_1,x=1,y=7,text="Front Panel Theme"}
local fp_theme = RadioButton{parent=clr_c_1,x=1,y=8,default=ini_cfg.FrontPanelTheme,options=themes.FP_THEME_NAMES,callback=function()end,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta}
TextBox{parent=clr_c_2,x=1,y=1,height=6,text="This system uses color heavily to distinguish ok and not, with some indicators using many colors. By selecting a mode below, indicators will change as shown. For non-standard modes, indicators with more than two colors will be split up."}
TextBox{parent=clr_c_2,x=21,y=7,text="Preview"}
local _ = IndLight{parent=clr_c_2,x=21,y=8,label="Good",colors=cpair(colors.black,colors.green)}
_ = IndLight{parent=clr_c_2,x=21,y=9,label="Warning",colors=cpair(colors.black,colors.yellow)}
_ = IndLight{parent=clr_c_2,x=21,y=10,label="Bad",colors=cpair(colors.black,colors.red)}
local b_off = IndLight{parent=clr_c_2,x=21,y=11,label="Off",colors=cpair(colors.black,colors.black),hidden=true}
local g_off = IndLight{parent=clr_c_2,x=21,y=11,label="Off",colors=cpair(colors.gray,colors.gray),hidden=true}
local function recolor(value)
local c = themes.smooth_stone.color_modes[value]
if value == themes.COLOR_MODE.STANDARD or value == themes.COLOR_MODE.BLUE_IND then
b_off.hide()
g_off.show()
else
g_off.hide()
b_off.show()
end
if #c == 0 then
for i = 1, #style.colors do term.setPaletteColor(style.colors[i].c, style.colors[i].hex) end
else
term.setPaletteColor(colors.green, c[1].hex)
term.setPaletteColor(colors.yellow, c[2].hex)
term.setPaletteColor(colors.red, c[3].hex)
end
end
TextBox{parent=clr_c_2,x=1,y=7,width=10,text="Color Mode"}
local c_mode = RadioButton{parent=clr_c_2,x=1,y=8,default=ini_cfg.ColorMode,options=themes.COLOR_MODE_NAMES,callback=recolor,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta}
TextBox{parent=clr_c_2,x=21,y=13,height=2,width=18,text="Note: exact color varies by theme.",fg_bg=g_lg_fg_bg}
PushButton{parent=clr_c_2,x=44,y=14,min_width=6,text="Done",callback=function()clr_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
local function back_from_colors()
main_pane.set_value(util.trinary(tool_ctl.jumped_to_color, 1, 4))
tool_ctl.jumped_to_color = false
recolor(1)
end
local function show_access()
clr_pane.set_value(2)
recolor(c_mode.get_value())
end
local function submit_colors()
tmp_cfg.FrontPanelTheme = fp_theme.get_value()
tmp_cfg.ColorMode = c_mode.get_value()
if tool_ctl.jumped_to_color then
settings.set("FrontPanelTheme", tmp_cfg.FrontPanelTheme)
settings.set("ColorMode", tmp_cfg.ColorMode)
if settings.save("/supervisor.settings") then
load_settings(settings_cfg, true)
load_settings(ini_cfg)
clr_pane.set_value(3)
else
clr_pane.set_value(4)
end
else
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(6)
end
end
PushButton{parent=clr_c_1,x=1,y=14,text="\x1b Back",callback=back_from_colors,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=clr_c_1,x=8,y=14,min_width=15,text="Accessibility",callback=show_access,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
tool_ctl.color_next = PushButton{parent=clr_c_1,x=44,y=14,text="Next \x1a",callback=submit_colors,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
tool_ctl.color_apply = PushButton{parent=clr_c_1,x=43,y=14,min_width=7,text="Apply",callback=submit_colors,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg}
tool_ctl.color_apply.hide(true)
local function c_go_home()
main_pane.set_value(1)
clr_pane.set_value(1)
end
TextBox{parent=clr_c_3,x=1,y=1,text="Settings saved!"}
PushButton{parent=clr_c_3,x=1,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
PushButton{parent=clr_c_3,x=44,y=14,min_width=6,text="Home",callback=c_go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=clr_c_4,x=1,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=clr_c_4,x=1,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
PushButton{parent=clr_c_4,x=44,y=14,min_width=6,text="Home",callback=c_go_home,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=49}
local sum_c_2 = Div{parent=summary,x=2,y=4,width=49}
local sum_c_3 = Div{parent=summary,x=2,y=4,width=49}
local sum_c_4 = Div{parent=summary,x=2,y=4,width=49}
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,text=" Summary",fg_bg=cpair(colors.black,colors.green)}
local setting_list = ListBox{parent=sum_c_1,x=1,y=1,height=12,width=49,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_settings()
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(5)
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("/supervisor.settings") then
load_settings(settings_cfg, true)
load_settings(ini_cfg)
try_set(num_units, ini_cfg.UnitCount)
try_set(tank_mode, ini_cfg.FacilityTankMode)
try_set(svr_chan, ini_cfg.SVR_Channel)
try_set(plc_chan, ini_cfg.PLC_Channel)
try_set(rtu_chan, ini_cfg.RTU_Channel)
try_set(crd_chan, ini_cfg.CRD_Channel)
try_set(pkt_chan, ini_cfg.PKT_Channel)
try_set(plc_timeout, ini_cfg.PLC_Timeout)
try_set(rtu_timeout, ini_cfg.RTU_Timeout)
try_set(crd_timeout, ini_cfg.CRD_Timeout)
try_set(pkt_timeout, ini_cfg.PKT_Timeout)
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)
try_set(fp_theme, ini_cfg.FrontPanelTheme)
try_set(c_mode, ini_cfg.ColorMode)
for i = 1, #ini_cfg.CoolingConfig do
local cfg, elems = ini_cfg.CoolingConfig[i], tool_ctl.cooling_elems[i]
try_set(elems.boilers, cfg.BoilerCount)
try_set(elems.turbines, cfg.TurbineCount)
try_set(elems.tank, cfg.TankConnection)
end
for i = 1, #ini_cfg.FacilityTankDefs do
try_set(tool_ctl.tank_elems[i].tank_opt, ini_cfg.FacilityTankDefs[i])
end
en_fac_tanks.set_value(ini_cfg.FacilityTankMode > 0)
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=14,text="\x1b Back",callback=back_from_settings,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
tool_ctl.show_key_btn = PushButton{parent=sum_c_1,x=8,y=14,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=cpair(colors.lightGray,colors.white)}
tool_ctl.settings_apply = PushButton{parent=sum_c_1,x=43,y=14,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,text="Settings saved!"}
local function go_home()
main_pane.set_value(1)
svr_pane.set_value(1)
net_pane.set_value(1)
clr_pane.set_value(1)
sum_pane.set_value(1)
end
PushButton{parent=sum_c_2,x=1,y=14,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=44,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=sum_c_3,x=1,y=1,height=2,text="The old config.lua file will now be deleted, then the configurator will exit."}
local function delete_legacy()
fs.delete("/supervisor/config.lua")
exit()
end
PushButton{parent=sum_c_3,x=1,y=14,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=44,y=14,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=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=sum_c_4,x=1,y=14,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=44,y=14,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=49}
TextBox{parent=changelog,x=1,y=2,text=" Config Change Log",fg_bg=bw_fg_bg}
local c_log = ListBox{parent=cl,x=1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}