Last active
August 4, 2024 16:06
-
-
Save SofieBrink/5829fff6c04a2dd9de37b93a5b46f292 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// !runscript XXXXXX | |
// Sofie's Universal Display Bootfile Version | |
//------------------------------------------------------------------------------------------------- | |
// Usage Description. Parameters with {OPT} infront can be left out. | |
// FormatTime(input) - Function to format a time in seconds to a 24 hour human-readable clock format | |
//------------------------------------------------------------------------------------------------- | |
// Variables | |
global UD_Widgets is lexicon(). | |
set UD_Path to "1:/UniversalDisplay/". | |
set UD_Active to true. | |
set UD_Reboot to false. | |
set UD_HelperIndex to 0. | |
set UD_RefreshRate to 20. | |
set UD_HideOnInactive to true. | |
set UD_WidgetIndex to 0. | |
set EmptyList to ship:partsnamed("THIS PART WILL NEVER EXIST, I JUST NEED AN EMPTY LIST"). | |
EmptyList:clear(). | |
// datastructure: | |
// UD_Widgets | |
// lex { | |
// key: 0, value: | |
// lex { | |
// key: x, value: 200 | |
// key: y, value: 200 | |
// key: width, value: 250 | |
// key: background, value: "" | |
// key: displayname, value: "Left Widget" | |
// key: fontsize, value: 16 | |
// key: gui, value: | |
// lex { | |
// key: gui, value: guiElement | |
// key: contents, value: | |
// list { | |
// lex { | |
// key: layout, value: layoutElement | |
// key: contents, value: | |
// list { | |
// labelElement, | |
// labelElement | |
// } | |
// }, | |
// lex { | |
// key: layout, value layoutElement | |
// key: contents, value: | |
// list { | |
// someElement | |
// } | |
// }, | |
// lex { | |
// key: layout, value: layoutElement | |
// key: contents, value: | |
// list { | |
// labelElement, | |
// labelElement | |
// } | |
// }, | |
// lex { | |
// key: layout, value layoutElement | |
// key: contents, value: | |
// list { | |
// someElement | |
// } | |
// }, | |
// lex { | |
// key: layout, value: layoutElement | |
// key: contents, value: | |
// list { | |
// labelElement, | |
// labelElement | |
// } | |
// } | |
// } | |
// } | |
// key: contents, value: | |
// list { | |
// lex { | |
// key: type, value: "item" | |
// key: label, value: "Vessel" | |
// key: prefix, value: "", | |
// key: postfix, value: "", | |
// key: decimaldigits, value: 0, | |
// key: value, value: {return ship:name.} | |
// }, | |
// lex { | |
// key: type, value: "seperator" | |
// }, | |
// lex { | |
// key: type, value: "item" | |
// key: label, value: "Apoapsis" | |
// key: prefix, value: "", | |
// key: postfix, value: "Km", | |
// key: decimaldigits, value: 2, | |
// key: value, value: {return ship:apoapsis.} | |
// }, | |
// lex { | |
// key: type, value: "spacer" | |
// }, | |
// lex { | |
// key: type, value: "item" | |
// key: label, value: "Periapsis" | |
// key: prefix, value: "", | |
// key: postfix, value: "Km", | |
// key: decimaldigits, value: 2, | |
// key: value, value: {return ship:periapsis.} | |
// key: stringvalue, value: "{return ship:periapsis.}" | |
// } | |
// } | |
// } | |
// } | |
// TODO | |
// Colours low prio | |
// widget printer | |
// edit lines high prio | |
// documentation. | |
// Bugs | |
// spacers and seperators are not implemented | |
//------------------------------------------------------------------------------------------------- | |
// Helper Functions | |
global function FormatTime { | |
// Function to format a time in seconds to a 24 hour human-readable clock format | |
parameter input. | |
if (not input:typename = "scalar") return. | |
local result is choose "-" if input < 0 else "". | |
set input to abs(input). | |
local days is floor(input / (3600 * 24)). | |
local hours is floor(mod(input / 3600, 24)). | |
local minutes is floor((mod(input, 3600)) / 60). | |
local seconds is round(mod(input, 60), 1). | |
if (days <> 0) { | |
set result to result + days + "d ". | |
} | |
if (hours <> 0 OR days <> 0) { | |
set result to result + hours + "h ". | |
} | |
if ((minutes <> 0 OR hours <> 0) AND days = 0) { | |
set result to result + minutes + "m ". | |
} | |
if (hours = 0 AND days = 0 AND minutes <> 0) { | |
set result to result + round(seconds) + "s". | |
} | |
else if (hours = 0 AND days = 0 AND minutes = 0) { | |
set result to result + (seconds + ".0"):substring(0, choose 3 if seconds < 10 else 4) + "s". | |
} | |
return result. | |
} | |
//------------------------------------------------------------------------------------------------- | |
// Internal Helper Functions | |
function UD_Print { | |
// Function to allow printing of messages to the HUD for display with a closed terminal. | |
parameter message. | |
parameter type is "Info". | |
parameter short is true. | |
//print (choose "UD " if (short) else "Universal Display ") + type + ": " + message. | |
HUDTEXT((choose "UD " if (short) else "Universal Display ") + type + ": " + message | |
, 15 // Show for 5 seconds | |
, 2 // Upper right hand corner | |
, 24 // Font Size | |
, WHITE // Print in white | |
, true // Also print to the terminal for good measure | |
). | |
} | |
function UD_TestErrors { | |
// Function to test if there's any errors present and to print them. | |
parameter listing, type is "Error". | |
if (listing:length > 0) { | |
for li in listing { | |
UD_Print(li, type). | |
} | |
return false. | |
} | |
return true. | |
} | |
function UD_ValidateWidget { | |
// Function to test if a given widgetLex is valid. | |
parameter widget. | |
local errors is EmptyList:copy. | |
if (not(widget:haskey("DisplayName"))) errors:add("Item:DisplayName is empty"). | |
else if (widget["DisplayName"]:typename <> "string") errors:add("Item:DisplayName is not a string."). | |
if (not(widget:haskey("Background"))) set widget["Background"] to "". | |
else if (widget["Background"]:typename <> "string") errors:add("Item:Background is not a string."). | |
if (not(widget:haskey("Width"))) set widget["Width"] to 250. | |
else if (widget["Width"]:typename <> "scalar") errors:add("Item:Width is not a scalar."). | |
if (not(widget:haskey("X"))) set widget["X"] to -60. | |
else if (widget["X"]:typename <> "scalar") errors:add("Item:X is not a scalar."). | |
if (not(widget:haskey("Y"))) set widget["Y"] to 550. | |
else if (widget["Y"]:typename <> "scalar") errors:add("Item:Y is not a scalar."). | |
if (not(widget:haskey("FontSize"))) set widget["FontSize"] to 16. | |
else if (widget["FontSize"]:typename <> "scalar") errors:add("Item:FontSize is not a scalar."). | |
if (widget:haskey("Contents") AND widget["Contents"]:typename <> "list") errors:add("Item:Contents is not a list."). | |
return lex("widget", widget, "errors", errors). | |
} | |
function UD_ValidateLine { | |
// Function to test if a given lineLex is valid. | |
parameter line. | |
local errors is EmptyList:copy. | |
if (not(line:haskey("Type"))) set line["Type"] to "item". | |
else if (line["Type"]:typename <> "string") errors:add("Item:Type is not a string."). | |
if (line["Type"] = "item") { | |
if (not(line:haskey("Label"))) errors:add("Item:Label is empty"). | |
else if (line["Label"]:typename <> "string") errors:add("Item:Label is not a string."). | |
if (not(line:haskey("Prefix"))) set line["Prefix"] to "". | |
else if (line["Prefix"]:typename <> "string") errors:add("Item:Prefix is not a string."). | |
if (not(line:haskey("Postfix"))) set line["Postfix"] to "". | |
else if (line["Postfix"]:typename <> "string") errors:add("Item:Postfix is not a string."). | |
if (not(line:haskey("DecimalDigits"))) set line["DecimalDigits"] to 0. | |
else if (line["DecimalDigits"]:typename <> "scalar") errors:add("Item:DecimalDigits is not a scalar."). | |
// Validate delegate as much as possible. | |
if (line:haskey("Value") | |
AND line["Value"]:typename = "string" | |
AND line["Value"]:length >= 2 | |
AND line["Value"][0] = "{" | |
AND line["Value"][line["Value"]:length - 1] = "}" | |
) { | |
// Split delegate into components. | |
local knownDirectives is EmptyList:copy. | |
knownDirectives:add("set"). | |
knownDirectives:add("lock"). | |
knownDirectives:add("local"). | |
knownDirectives:add("return"). | |
local statements is EmptyList:copy. | |
statements:add(""). | |
local inString is false. | |
for char in line["Value"]:substring(1, line["Value"]:length - 2) { | |
set statements[statements:length-1] to statements[statements:length-1] + char. | |
if (char = char(34)) toggle inString. | |
if (not(inString) AND char = char(46)) { | |
set statements[statements:length-1] to statements[statements:length-1]:trim(). | |
statements:add(""). | |
} | |
} | |
if (statements[statements:length-1]:length = 0) | |
statements:remove(statements:length-1). | |
for statement in statements { | |
if (not(statement:endswith("."))) | |
errors:add("Item:Value does not end with a period"). | |
if (statement:contains("{") OR statement:contains("}")) { | |
errors:add("Item:Value statement contains a nested delegate"). | |
// Nested Delegates are currently unsupported | |
} | |
if not(knownDirectives:contains(statement:split(" ")[0])) { | |
errors:add("Item:Value statement has an unknown or disallowed directive."). | |
} | |
} | |
if (not(statements[statements:length-1]:startswith("return "))) { | |
errors:add("Item:Value does not end with a return statement."). | |
} | |
} | |
else { | |
if (line:haskey("Value")) errors:add("Item:Value is not a stringified delegate."). | |
else errors:add("Item:Value is empty."). | |
} | |
} | |
else if (line["Type"] <> "spacer" OR line["Type"] <> "seperator") errors:add("Item:Type " + line["Type"] + " is unkown."). | |
return lex("line", line, "errors", errors). | |
} | |
function UD_FindWidget { | |
// Function to find the widget that matches the provided index or display name, returns false if no or multiple matches exist. | |
parameter dub. | |
local matchingItems is EmptyList:copy. | |
for w in UD_Widgets:keys { | |
if (dub:typename = "scalar" AND w = dub) { | |
matchingItems:add(w). | |
} | |
else if (dub:typename = "string" and UD_Widgets[w]["DisplayName"] = dub) { | |
matchingItems:add(w). | |
} | |
} | |
if (matchingItems:length = 1) { | |
return matchingItems[0]. | |
} | |
else { | |
return false. | |
} | |
} | |
function UD_RunHelper { | |
// Function to write to and run the helper file. | |
parameter command. | |
log command to UD_Path + "UniversalDisplayHelper" + UD_HelperIndex + ".ks". | |
runpath(UD_Path + "UniversalDisplayHelper" + UD_HelperIndex + ".ks"). | |
deletePath(UD_Path + "UniversalDisplayHelper" + UD_HelperIndex + ".ks"). | |
set UD_HelperIndex to UD_HelperIndex + 1. | |
} | |
function UD_DeleteData { | |
// Function to help remove data from the saved file and the active list. | |
parameter widgetIndex, lineIndexes is EmptyList:copy, deleteWidget is false. | |
local widgetDub is "UD_Widgets:add(" + widgetIndex + ", ". | |
local lineDub is "UD_Widgets[" + widgetIndex + "][" + char(34) + "Contents" + char(34) + "]:add(". | |
local file is open(UD_Path + "UniversalDisplayValues.ks"). | |
local fileContents is file:readall(). | |
local index is 0. | |
file:clear(). | |
for line in fileContents { | |
if (line:contains(widgetDub) AND deleteWidget) { | |
// don't save. | |
} | |
else if (line:contains(lineDub)) { | |
if (deleteWidget OR lineIndexes:contains(index)) { | |
// don't save. | |
} | |
else { | |
file:writeln(line). | |
} | |
set index to index + 1. | |
} | |
else { | |
file:writeln(line). | |
} | |
} | |
if (deleteWidget) { | |
UD_Widgets[widgetIndex]["GUI"]["GUI"]:dispose(). | |
UD_Widgets:remove(widgetIndex). | |
} | |
else { | |
for i in lineIndexes { | |
UD_Widgets[widgetIndex]["GUI"]["Contents"][i]["Layout"]:dispose(). | |
UD_Widgets[widgetIndex]["GUI"]["Contents"]:remove(i). | |
UD_Widgets[widgetIndex]["Contents"]:remove(i). | |
} | |
} | |
} | |
function UD_EditData { | |
// function to edit one line of the saved file | |
parameter dub, newline. | |
local file is open(UD_Path + "UniversalDisplayValues.ks"). | |
local fileContents is file:readall(). | |
local index is 0. | |
file:clear(). | |
for line in fileContents { | |
if (line:contains(dub)) { | |
file:writeln(newline). | |
} | |
else { | |
file:writeln(line). | |
} | |
} | |
} | |
function UD_ConstructWidgetCommand { | |
// function to make a command to save the widget. | |
parameter index, commandLex. | |
local command is "". | |
set command to "UD_Widgets:add(" + index + ", lex(". | |
set command to command + char(34) + "DisplayName" + char(34) + ", " + char(34) + commandLex["DisplayName"] + char(34) + ", ". | |
set command to command + char(34) + "Background" + char(34) + ", " + char(34) + commandLex["Background"] + char(34) + ", ". | |
set command to command + char(34) + "Width" + char(34) + ", " + commandLex["Width"] + ", ". | |
set command to command + char(34) + "X" + char(34) + ", " + commandLex["X"] + ", ". | |
set command to command + char(34) + "Y" + char(34) + ", " + commandLex["Y"] + ", ". | |
set command to command + char(34) + "FontSize" + char(34) + ", " + commandLex["FontSize"] + ", ". | |
set command to command + char(34) + "Contents" + char(34) + ", " + "list()". | |
set command to command + ")).". | |
return command. | |
} | |
//------------------------------------------------------------------------------------------------- | |
// Internal Functions | |
function UD_Loop { | |
// Function to start the internal loop to that will call functions to continually update the widgets. | |
on floor(time:seconds * UD_RefreshRate) { | |
UD_HandleMessages(). | |
UD_UpdateWidgets(). | |
return UD_Active. | |
} | |
wait until (not(UD_Active)). | |
UD_Save(). | |
clearGuis(). | |
if (UD_Reboot) reboot. | |
} | |
function UD_Save { | |
// Function to save the settings to a json file for loading on the next reboot. | |
local settingsLex is lexicon( | |
"UD_WidgetIndex", UD_WidgetIndex, | |
"UD_RefreshRate", UD_RefreshRate, | |
"UD_HideOnInactive", UD_HideOnInactive | |
). | |
writeJson(settingsLex, UD_Path + "UniversalDisplaySettings.json"). | |
} | |
function UD_Load { | |
// Function to load the settings from the json file, validate the exit state and load the widgets from storage. | |
if (homeConnection:isconnected) { | |
if (core:bootfilename = "boot/UniversalDisplay.ks" AND exists("0:/UniversalDisplay.ks")) copypath("0:/UniversalDisplay.ks", "1:/boot/UniversalDisplay.ks"). | |
else if (exists("0:/UniversalDisplay.ksm")) { | |
copypath("0:/UniversalDisplay.ksm", "1:/boot/UniversalDisplay.ksm"). | |
if (not(core:bootfilename = "boot/UniversalDisplay.ksm")) set core:bootfilename to "boot/UniversalDisplay.ksm". | |
} | |
else { | |
UD_Print("Archive is accessible but source files were not found!", "Warning"). | |
} | |
} | |
if (exists(UD_Path)) { | |
cd(UD_Path). | |
list files in fileList. | |
for file in fileList { | |
if file:name:contains("UniversalDisplayHelper") and file:extension = "ks" { | |
UD_Print("Helper file detected indicating a possible syntax error on previous run!", "Warning"). | |
deletepath(UD_Path + file:name). | |
} | |
else if (file:name = "UniversalDisplaySettings.json") { | |
local settingsLex is readJson(UD_Path + "UniversalDisplaySettings.json"). | |
if (settingsLex:haskey("UD_WidgetIndex")) set UD_WidgetIndex to settingsLex["UD_WidgetIndex"]. | |
if (settingsLex:haskey("UD_RefreshRate")) set UD_RefreshRate to settingsLex["UD_RefreshRate"]. | |
if (settingsLex:haskey("UD_HideOnInactive")) set UD_HideOnInactive to settingsLex["UD_HideOnInactive"]. | |
UD_Print("Loaded settings from disk"). | |
} | |
else if (file:name = "UniversalDisplayValues.ks") { | |
runPath(UD_Path + "UniversalDisplayValues.ks"). | |
} | |
else if (file:name = "UniversalDisplayValues_Backup.ks") { | |
UD_Print("Backup file found without main file. Recovering from backup."). | |
runPath(UD_Path + "UniversalDisplayValues_Backup.ks"). | |
} | |
} | |
cd("1:/"). | |
} | |
} | |
function UD_Backup { | |
// Function to create a backup of the current UniversalDisplayValues, incase something goes terribly wrong. | |
if (exists(UD_Path + "UniversalDisplayValues.ks")) { | |
copyPath(UD_Path + "UniversalDisplayValues.ks", UD_Path + "UniversalDisplayValues_Backup.ks"). | |
} | |
} | |
function UD_HandleMessages { | |
// Function to handle incomming messages from other cores to update various things. | |
if (core:messages:empty) return. | |
local msg is core:messages:pop. | |
local errors is EmptyList:copy. | |
UD_Backup(). | |
if (msg:content:typename = "string") { | |
if (msg:content = "exit") { | |
UD_Print("Exiting"). | |
UD_Active off. | |
} | |
else if (msg:content = "reboot") { | |
UD_Print("Rebooting"). | |
UD_Reboot on. | |
UD_Active off. | |
} | |
else if (msg:content = "refresh") { | |
UD_Print("Refresing"). | |
for key in UD_Widgets:keys { | |
UD_Widgets[key]["GUI"]["GUI"]:dispose(). | |
UD_Widgets[key]:remove("GUI"). | |
} | |
} | |
else if (msg:content = "show") { | |
core:doevent("open terminal"). | |
} | |
else if (msg:content = "hide") { | |
core:doevent("close terminal"). | |
} | |
else if (msg:content = "reset") { | |
UD_Print("Resetting"). | |
if (exists(UD_Path + "UniversalDisplaySettings.json")) deletePath(UD_Path + "UniversalDisplaySettings.json"). | |
if (exists(UD_Path + "UniversalDisplayValues.ks")) deletePath(UD_Path + "UniversalDisplayValues.ks"). | |
clearguis(). | |
reboot. | |
} | |
} | |
else if (msg:content:typename = "lexicon") { | |
local receivedLex is msg:content. | |
if (receivedLex:haskey("RefreshRate")) { | |
if (receivedLex["RefreshRate"]:typename = "scalar") { | |
set UD_RefreshRate to receivedLex["RefreshRate"]. | |
UD_Print("Updating RefreshRate to " + UD_RefreshRate). | |
} | |
else { | |
UD_Print("Received RefreshRate is not a scalar.", "Warning"). | |
} | |
} | |
if (receivedLex:haskey("HideOnInactive")) { | |
if (receivedLex["HideOnInactive"]:typename = "boolean") { | |
set UD_HideOnInactive to receivedLex["HideOnInactive"]. | |
UD_Print("Updating HideOnInactive to " + UD_RefreshRate). | |
} | |
else { | |
UD_Print("Received HideOnInactive is not a boolean.", "Warning"). | |
} | |
} | |
if (receivedLex:haskey("AddWidget")) { | |
if (receivedLex["AddWidget"]:typename = "lexicon") { | |
UD_AddWidget(receivedLex["AddWidget"]). | |
} | |
else { | |
UD_Print("Received AddWidget is not a lexicon.", "Warning"). | |
} | |
} | |
else if (receivedLex:haskey("RemoveWidget")) { | |
if (receivedLex["RemoveWidget"]:typename = "scalar" OR receivedLex["RemoveWidget"]:typename = "string") { | |
UD_Print("Removing widget"). | |
UD_RemoveWidget(receivedLex["RemoveWidget"]). | |
} | |
else { | |
UD_Print("Received RemoveWidget is not a string or scalar.", "Warning"). | |
} | |
} | |
else if (receivedLex:haskey("EditWidget")) { | |
if (receivedLex["EditWidget"]:typename = "lexicon") { | |
UD_Print("Editing widget"). | |
UD_EditWidget(receivedLex["EditWidget"]). | |
} | |
else { | |
UD_Print("Received EditWidget is not a lexicon.", "Warning"). | |
} | |
} | |
else if (receivedLex:haskey("AddLine")) { | |
if (receivedLex["AddLine"]:typename = "lexicon") { | |
if (not(receivedLex["AddLine"]:haskey("Widget"))) errors:add("Item:Widget is empty"). | |
else if (not(receivedLex["AddLine"]["Widget"]:typename = "string" OR receivedLex["AddLine"]["Widget"]:typename = "scalar")) errors:add("Item:Widget is not a string or scalar."). | |
if (not(receivedLex["AddLine"]:haskey("Line"))) errors:add("Item:Line is empty"). | |
else if (receivedLex["AddLine"]["Line"]:typename <> "lexicon") errors:add("Item:Line is not a lexicon."). | |
if (not(UD_TestErrors(errors))) return false. | |
if (not(receivedLex["AddLine"]:haskey("Index"))) set receivedLex["AddLine"]["Index"] to -1. | |
else if (receivedLex["AddLine"]["Index"]:typename <> "scalar") errors:add("Item:Index is not a Scalar."). | |
local widgetIndex is UD_FindWidget(receivedLex["AddLine"]["Widget"]). | |
if (widgetIndex:typename <> "scalar" AND receivedLex["AddLine"]["Widget"]:typename = "scalar") errors:add("Item:Widget at index " + receivedLex["AddLine"]["Widget"] + " does not exist."). | |
else if (widgetIndex:typename <> "scalar") errors:add("Item:Widget with DisplayName " + receivedLex["AddLine"]["Widget"] + " does not exist, or there are multiple."). | |
if (not(UD_TestErrors(errors))) return false. | |
set receivedLex["AddLine"]["Index"] to choose receivedLex["AddLine"]["Index"] if UD_Widgets[widgetIndex]["Contents"]:length <> receivedLex["AddLine"]["Index"] else -1. | |
if (receivedLex["AddLine"]["Index"] <> -1) { | |
UD_Widgets[widgetIndex]["GUI"]["GUI"]:dispose(). | |
UD_Widgets[widgetIndex]:remove("GUI"). | |
} | |
local line is UD_AddLine(widgetIndex, receivedLex["AddLine"]["Line"], receivedLex["AddLine"]["Index"]). | |
if (line:typename <> "lexicon") { | |
errors:add("Failed to add line to widget"). | |
} | |
else { | |
if (line:haskey("command") AND line:haskey("checksum")) { | |
UD_RunHelper(line["checksum"]). | |
UD_Print("Checksum passed."). | |
UD_RunHelper(line["command"]). | |
UD_Print("Command Executed."). | |
} | |
else errors:add("Internal Error when adding line"). | |
} | |
if (not(UD_TestErrors(errors))) return false. | |
} | |
else { | |
UD_Print("Received AddWidget is not a lexicon.", "Warning"). | |
} | |
} | |
else if (receivedLex:haskey("RemoveLine")) { | |
UD_Print("Removing line"). | |
UD_RemoveLine(receivedLex["RemoveLine"]). | |
} | |
else if (receivedLex:haskey("EditLine")) { | |
UD_Print("Unsupported"). | |
} | |
} | |
} | |
function UD_AddWidget { | |
// Function to add a widget to the list | |
parameter addLex. | |
local errors is EmptyList:copy. | |
local widget is lex(). | |
local commands is EmptyList:copy. | |
commands:add(""). | |
local checksums is EmptyList:copy. | |
if (addLex:typename <> "lexicon") errors:add("Item is not a lexicon."). | |
if (not(UD_TestErrors(errors))) return false. | |
local validation is UD_ValidateWidget(addLex). | |
for e in validation["errors"] errors:add(e). | |
set addLex to validation["widget"]. | |
if (not(UD_TestErrors(errors))) return false. | |
set commands[0] to UD_ConstructWidgetCommand(UD_WidgetIndex, addLex). | |
widget:add("DisplayName", addLex["DisplayName"]). | |
widget:add("Background", addLex["Background"]). | |
widget:add("Width", addLex["Width"]). | |
widget:add("X", addLex["X"]). | |
widget:add("Y", addLex["Y"]). | |
widget:add("FontSize", addLex["FontSize"]). | |
widget:add("Contents", EmptyList:copy). | |
if (addLex:haskey("Contents")) { | |
for listItem in addLex["Contents"] { | |
local line is UD_addLine(UD_WidgetIndex, listItem). | |
if (line:typename <> "lexicon") { | |
errors:add("Failed to add line to widget"). | |
} | |
else { | |
if (line:haskey("command")) commands:add(line["command"]). else errors:add("Internal Error when adding line"). | |
if (line:haskey("checksum")) checksums:add(line["checksum"]). else errors:add("Internal Error when adding line"). | |
} | |
} | |
} | |
if (not(UD_TestErrors(errors))) return false. | |
log commands[0] to UD_Path + "UniversalDisplayValues.ks". | |
UD_Widgets:add(UD_WidgetIndex, widget). | |
if (checksums:length > 0) { | |
UD_RunHelper(checksums:join(" ")). | |
UD_Print(checksums:length + " Checksums passed."). | |
} | |
if (commands:length >= 2) { | |
local tmpcommand is "". | |
for i in range(1, commands:length) { | |
set tmpcommand to tmpcommand + commands[i] + " ". | |
} | |
UD_RunHelper(tmpcommand). | |
UD_Print("Commands Executed."). | |
} | |
set UD_WidgetIndex to UD_WidgetIndex + 1. | |
return true. | |
} | |
function UD_RemoveWidget { | |
// Function to remove a widget from the list. | |
parameter removeIndex. | |
local errors is EmptyList:copy. | |
local widgetIndex is UD_FindWidget(removeIndex). | |
if (widgetIndex:typename <> "scalar" AND removeIndex:typename = "scalar") errors:add("Item:Widget at index " + removeIndex + " does not exist."). | |
else if (widgetIndex:typename <> "scalar") errors:add("Item:Widget with DisplayName " + removeIndex + " does not exist, or there are multiple."). | |
if (not(UD_TestErrors(errors))) return false. | |
UD_DeleteData(widgetIndex, EmptyList:copy, true). | |
} | |
function UD_EditWidget { | |
// Function to edit an existing widget. | |
parameter editLex. | |
local errors is EmptyList:copy. | |
local replacementLex is lex(). | |
local command is "". | |
if (not(editLex:haskey("Index"))) errors:add("Item:Index is empty"). | |
else if (editLex["Index"]:typename <> "scalar" AND editLex["Index"]:typename <> "string") errors:add("Item:Index is not a string or scalar."). | |
if (not(editLex:haskey("Widget"))) errors:add("Item:Widget is empty"). | |
else if (editLex["Widget"]:typename <> "lexicon") errors:add("Item:Widget is not a lexicon."). | |
if (not(UD_TestErrors(errors))) return false. | |
local widgetIndex is UD_FindWidget(editLex["Index"]). | |
if (widgetIndex:typename <> "scalar" AND editLex["Widget"]:typename = "scalar") errors:add("Item:Widget at index " + editLex["Widget"] + " does not exist."). | |
else if (widgetIndex:typename <> "scalar") errors:add("Item:Widget with DisplayName " + editLex["Widget"] + " does not exist, or there are multiple."). | |
if (not(UD_TestErrors(errors))) return false. | |
if (editLex["Widget"]:haskey("DisplayName")) { | |
if (editLex["Widget"]["DisplayName"]:typename <> "string") errors:add("Item:DisplayName is not a string."). | |
set replacementLex["DisplayName"] to editLex["Widget"]["DisplayName"]. | |
} | |
else { | |
set replacementLex["DisplayName"] to UD_Widgets[widgetIndex]["DisplayName"]. | |
} | |
if (editLex["Widget"]:haskey("Background")) { | |
if (editLex["Widget"]["Background"]:typename <> "string") errors:add("Item:Background is not a string."). | |
set replacementLex["Background"] to editLex["Widget"]["Background"]. | |
} | |
else { | |
set replacementLex["Background"] to UD_Widgets[widgetIndex]["Background"]. | |
} | |
if (editLex["Widget"]:haskey("Width")) { | |
if (editLex["Widget"]["Width"]:typename <> "scalar") errors:add("Item:Width is not a string."). | |
set replacementLex["Width"] to editLex["Widget"]["Width"]. | |
} | |
else { | |
set replacementLex["Width"] to UD_Widgets[widgetIndex]["Width"]. | |
} | |
if (editLex["Widget"]:haskey("X")) { | |
if (editLex["Widget"]["X"]:typename <> "scalar") errors:add("Item:X is not a string."). | |
set replacementLex["X"] to editLex["Widget"]["X"]. | |
} | |
else { | |
set replacementLex["X"] to UD_Widgets[widgetIndex]["X"]. | |
} | |
if (editLex["Widget"]:haskey("Y")) { | |
if (editLex["Widget"]["Y"]:typename <> "scalar") errors:add("Item:Y is not a string."). | |
set replacementLex["Y"] to editLex["Widget"]["Y"]. | |
} | |
else { | |
set replacementLex["Y"] to UD_Widgets[widgetIndex]["Y"]. | |
} | |
if (editLex["Widget"]:haskey("FontSize")) { | |
if (editLex["Widget"]["FontSize"]:typename <> "scalar") errors:add("Item:FontSize is not a string."). | |
set replacementLex["FontSize"] to editLex["Widget"]["FontSize"]. | |
} | |
else { | |
set replacementLex["FontSize"] to UD_Widgets[widgetIndex]["FontSize"]. | |
} | |
if (not(UD_TestErrors(errors))) return false. | |
local isDifferent is false. | |
for key in replacementLex:keys { | |
if (not(replacementLex[key] = UD_Widgets[widgetIndex][key])) isDifferent on. | |
} | |
if (not(isDifferent)) errors:add("New widget is not different from existing widget"). | |
if (not(UD_TestErrors(errors))) return false. | |
local validation is UD_ValidateWidget(replacementLex). | |
for e in validation["errors"] errors:add(e). | |
set replacementLex to validation["widget"]. | |
if (not(UD_TestErrors(errors))) return false. | |
set command to UD_ConstructWidgetCommand(widgetIndex, replacementLex). | |
UD_EditData("UD_Widgets:add(" + widgetIndex + ", ", command). | |
for key in replacementLex:keys { | |
set UD_Widgets[widgetIndex][key] to replacementLex[key]. | |
} | |
} | |
function UD_AddLine { | |
// function to add a line to a widget. | |
parameter widgetIndex, addLex, lineIndex is -1. | |
local errors is EmptyList:copy. | |
local preCommand is "". | |
local lineLex is "". | |
local command is "". | |
local checksum is "". | |
if (widgetIndex:typename <> "scalar") errors:add("WidgetIndex is not a scalar."). | |
if (addLex:typename <> "lexicon") errors:add("Item is not a lexicon."). | |
if (lineIndex:typename <> "scalar") errors:add("LineIndex is not a scalar."). | |
local validation is UD_ValidateLine(addLex). | |
for e in validation["errors"] errors:add(e). | |
set addLex to validation["line"]. | |
if (not(UD_TestErrors(errors))) return false. | |
set preCommand to "UD_Widgets[" + widgetIndex + "][" + char(34) + "Contents" + char(34) + "]". | |
if (addLex["Type"] = "item") { | |
set checksum to "(" + addLex["value"] + "):call().". | |
set lineLex to "lex(". | |
set lineLex to lineLex + char(34) + "Type" + char(34) + ", " + char(34) + addLex["Type"] + char(34) + ", ". | |
set lineLex to lineLex + char(34) + "Label" + char(34) + ", " + char(34) + addLex["Label"] + char(34) + ", ". | |
set lineLex to lineLex + char(34) + "Prefix" + char(34) + ", " + char(34) + addLex["Prefix"] + char(34) + ", ". | |
set lineLex to lineLex + char(34) + "Postfix" + char(34) + ", " + char(34) + addLex["Postfix"] + char(34) + ", ". | |
set lineLex to lineLex + char(34) + "DecimalDigits" + char(34) + ", " + addLex["DecimalDigits"] + ", ". | |
set lineLex to lineLex + char(34) + "Value" + char(34) + ", " + addLex["Value"] + ", ". | |
set lineLex to lineLex + char(34) + "StringValue" + char(34) + ", " + char(34) + addLex["Value"] + char(34). | |
set lineLex to lineLex + ")". | |
} | |
else { | |
set lineLex to "lex(" + char(34) + "Type" + char(34) + ", " + char(34) + addLex["Type"] + char(34) + ")". | |
} | |
set command to "if (not(exists(" + char(34) + UD_Path + "UniversalDisplayValues.ks" + char(34) + "))) create(" + char(34) + UD_Path + "UniversalDisplayValues.ks" + char(34) + ").". | |
set command to command + "local index is 0. local file is open(" + char(34) + UD_Path + "UniversalDisplayValues.ks" + char(34) + "). local fileContents is file:readall().". | |
set command to command + "set addLine to {file:writeln(" + char(34) + (preCommand + ":add(" + lineLex + ")."):replace(char(34), char(34) + " + char(34) + " + char(34)) + char(34) + ").}.". | |
set command to command + "if (fileContents:length = 0) addLine(). else {". | |
if (lineIndex <> -1) { | |
set command to command + "local lines is list().". | |
set command to command + "for line in fileContents { if line:contains(" + char(34) + "UD_Widgets[" + widgetIndex + "][" + char(34) + " + char(34) + " + char(34) + "Contents" + char(34) + " + char(34) +" + char(34) + "]:add(" + char(34) + ") {". | |
set command to command + "lines:add(list(line, index)). set index to index + 1.}else lines:add(list(line)).} file:clear().". | |
set command to command + "for i in range(lines:length) { if (lines[i]:length = 2 AND lines[i][1] = " + lineIndex + ") addLine(). file:writeln(lines[i][0]).} }". | |
} | |
else { | |
set command to command + " addLine(). }". | |
} | |
set command to command + preCommand + (choose ":insert(" + lineIndex if lineIndex <> -1 else ":add(") + lineLex + ").". | |
return lex("command", command, "checksum", checksum). | |
} | |
function UD_RemoveLine { | |
// Function to remove a line from a widget. | |
parameter removeLex. | |
local errors is EmptyList:copy. | |
if (not(removeLex:haskey("Widget"))) errors:add("Item:Widget is empty"). | |
else if (not(removeLex["Widget"]:typename = "string" OR removeLex["Widget"]:typename = "scalar")) errors:add("Item:Widget is not a string or scalar."). | |
if (not(removeLex:haskey("Index"))) errors:add("Item:Index is empty"). | |
else if (not(removeLex["Index"]:typename = "scalar")) errors:add("Item:Index is not a scalar."). | |
if (not(UD_TestErrors(errors))) return false. | |
local widgetIndex is UD_FindWidget(removeLex["Widget"]). | |
if (widgetIndex:typename <> "scalar" AND removeLex["Widget"]:typename = "scalar") errors:add("Item:Widget at index " + removeLex["Widget"] + " does not exist."). | |
else if (widgetIndex:typename <> "scalar") errors:add("Item:Widget with DisplayName " + removeLex["Widget"] + " does not exist, or there are multiple."). | |
if (not(UD_TestErrors(errors))) return false. | |
If (removeLex["Index"] < 0 OR removeLex["Index"] >= UD_Widgets[widgetIndex]["Contents"]:length) errors:add("Item:Index is out of range."). | |
if (not(UD_TestErrors(errors))) return false. | |
local tmplist is EmptyList:copy. | |
tmplist:add(removeLex["Index"]). | |
UD_DeleteData(widgetIndex, tmplist, false). | |
} | |
function UD_UpdateWidgets { | |
for key in UD_Widgets:keys { | |
local widget is UD_Widgets[key]. | |
if (not(widget:haskey("GUI"))) set widget["GUI"] to lex(). | |
if (not(widget["GUI"]:haskey("GUI"))) { | |
set widget["GUI"]["GUI"] to gui(widget["Width"]). | |
widget["GUI"]["GUI"]:show(). | |
if widget["Background"] = "" set widget["GUI"]["GUI"]:Style:bg to "". | |
} | |
// Update the direct elements of the widget. | |
if (not(widget["GUI"]["GUI"]:Style:bg = widget["Background"])) set widget["GUI"]["GUI"]:Style:bg to widget["Background"]. | |
if (not(widget["GUI"]["GUI"]:X = widget["X"])) set widget["GUI"]["GUI"]:X to widget["X"]. | |
if (not(widget["GUI"]["GUI"]:Y = widget["Y"])) set widget["GUI"]["GUI"]:Y to widget["Y"]. | |
if (not(widget["GUI"]["GUI"]:Style:Width = widget["Width"])) set widget["GUI"]["GUI"]:Style:Width to widget["Width"]. | |
if (not(widget["GUI"]["GUI"]:Style:FontSize = widget["FontSize"])) set widget["GUI"]["GUI"]:Style:FontSize to widget["FontSize"]. | |
if (not(widget["GUI"]["GUI"]:visible) and kuniverse:activevessel = ship) widget["GUI"]["GUI"]:show(). | |
else if (widget["GUI"]["GUI"]:visible and UD_HideOnInactive and kuniverse:activevessel <> ship) widget["GUI"]["GUI"]:hide(). | |
if (not(widget["GUI"]["GUI"]:visible)) return. // Don't need to tick the lines if the widget isn't visible. | |
local index is 0. | |
for line in widget["Contents"] { | |
if (not(widget["GUI"]:haskey("Contents"))) set widget["GUI"]["Contents"] to EmptyList:copy. | |
if (not(widget["GUI"]["Contents"]:length > index)) widget["GUI"]["Contents"]:add(lex()). | |
if (not(widget["GUI"]["Contents"][index]:haskey("Layout"))) set widget["GUI"]["Contents"][index]["Layout"] to widget["GUI"]["GUI"]:addhlayout(). | |
if (not(widget["GUI"]["Contents"][index]:haskey("Contents"))) set widget["GUI"]["Contents"][index]["Contents"] to EmptyList:copy. | |
if (line["Type"] = "item") { | |
local labeltxt is "<color=white>" + line["Label"] + ":</color>". | |
local prefixtxt is "<color=white>" + line["Prefix"] + "</color>". | |
local postfixtxt is "<color=white> " + line["Postfix"] + "</color>". | |
local value is line["Value"]:call(). | |
local valuetxt is prefixtxt + "<color=yellow>" + (choose round(value, line["DecimalDigits"]) if value:typename = "scalar" else value) + "</color>" + postfixtxt. | |
if (not(widget["GUI"]["Contents"][index]["Contents"]:length > 0)) widget["GUI"]["Contents"][index]["Contents"]:add(widget["GUI"]["Contents"][index]["Layout"]:addlabel()). | |
if (not(widget["GUI"]["Contents"][index]["Contents"]:length > 1)) widget["GUI"]["Contents"][index]["Contents"]:add(widget["GUI"]["Contents"][index]["Layout"]:addlabel()). | |
// specifics for the two labels in an item | |
if (not(widget["GUI"]["Contents"][index]["Contents"][0]:text = labeltxt)) set widget["GUI"]["Contents"][index]["Contents"][0]:text to labeltxt. | |
if (not(widget["GUI"]["Contents"][index]["Contents"][1]:text = valuetxt)) set widget["GUI"]["Contents"][index]["Contents"][1]:text to valuetxt. | |
if (not(widget["GUI"]["Contents"][index]["Contents"][1]:style:align = "RIGHT")) set widget["GUI"]["Contents"][index]["Contents"][1]:style:align to "RIGHT". | |
} | |
// basic markup for all labels | |
for label in widget["GUI"]["Contents"][index]["Contents"] { | |
if (not(label:style:margin:top = 0)) set label:style:margin:top to 0. | |
if (not(label:style:margin:bottom = 0)) set label:style:margin:bottom to 0. | |
if (not(label:style:margin:left = 0)) set label:style:margin:left to 0. | |
if (not(label:style:margin:right = 0)) set label:style:margin:right to 0. | |
if (not(label:style:padding:top = round(Widget["FontSize"] / 12, 1))) set label:style:padding:top to round(Widget["FontSize"] / 12, 1). | |
if (not(label:style:padding:bottom = round(Widget["FontSize"] / 12, 1))) set label:style:padding:bottom to round(Widget["FontSize"] / 12, 1). | |
if (not(label:style:padding:left = round(Widget["FontSize"] / 12, 1))) set label:style:padding:left to round(Widget["FontSize"] / 12, 1). | |
if (not(label:style:padding:right = round(Widget["FontSize"] / 12, 1))) set label:style:padding:right to round(Widget["FontSize"] / 12, 1). | |
if (not(label:style:fontsize = Widget["FontSize"] * 0.8125)) set label:style:fontsize to Widget["FontSize"] * 0.8125. | |
if (not(label:style:wordwrap = false)) set label:style:wordwrap to false. | |
} | |
set index to index + 1. | |
} | |
} | |
} | |
//------------------------------------------------------------------------------------------------- | |
// Function Calls Post-Loading | |
clearGuis(). | |
UD_Load(). | |
UD_Loop(). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment