aboutsummaryrefslogtreecommitdiff
path: root/source/WindowsFormsApplication1/Engine/Lua_Interp.cs
diff options
context:
space:
mode:
Diffstat (limited to 'source/WindowsFormsApplication1/Engine/Lua_Interp.cs')
-rw-r--r--source/WindowsFormsApplication1/Engine/Lua_Interp.cs1280
1 files changed, 1280 insertions, 0 deletions
diff --git a/source/WindowsFormsApplication1/Engine/Lua_Interp.cs b/source/WindowsFormsApplication1/Engine/Lua_Interp.cs
new file mode 100644
index 0000000..ab87fa7
--- /dev/null
+++ b/source/WindowsFormsApplication1/Engine/Lua_Interp.cs
@@ -0,0 +1,1280 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using DynamicLua;
+using System.IO;
+using System.Drawing;
+using System.Windows.Forms;
+using Gecko;
+using System.Net;
+using System.IO.Compression;
+using System.ComponentModel;
+using System.Threading;
+using Newtonsoft.Json;
+
+namespace ShiftOS
+{
+ public class Lua_API
+ {
+ public static List<LuaInterpreter> RunningMods = new List<LuaInterpreter>();
+ public static bool UseLuaAPI = false;
+ }
+
+ public class LuaInterpreter
+ {
+ public dynamic mod = new DynamicLua.DynamicLua();
+ public List<string> Errors = new List<string>();
+
+ /// <summary>
+ /// Creates a new Lua interpreter and interprets a .lua file.
+ /// </summary>
+ /// <param name="modfile">The file to interpret.</param>
+ public LuaInterpreter(string modfile)
+ {
+ Errors.Clear();
+ //Initiate the interpreter
+ mod = new DynamicLua.DynamicLua();
+ //Register core functions with the interpreter
+ RegisterCore();
+ //Parse the file contents.
+ var lua = File.ReadAllText(modfile);
+ var t = new System.Windows.Forms.Timer();
+ ThisDirectory = Directory.GetParent(modfile).FullName;
+ t.Interval = 50;
+ t.Tick += (object se, EventArgs ea) =>
+ {
+ if (Errors.Count > 0)
+ {
+ if (API.LoggerTerminal != null)
+ {
+ API.LoggerTerminal.WriteLine(Errors[0]);
+ Errors.Remove(Errors[0]);
+ }
+ else
+ {
+ API.CreateInfoboxSession("Script Error", $"An error has occurred in your script: {Errors[0]}", infobox.InfoboxMode.Info);
+ Errors.Remove(Errors[0]);
+ }
+ ExitScript();
+ }
+ };
+ t.Start();
+ try
+ {
+ mod(lua);
+ }
+ catch (Exception ex)
+ {
+ API.CreateInfoboxSession("Mod Interpretation Error", "An error has occurred in your mod." + Environment.NewLine + Environment.NewLine + ex.Message, infobox.InfoboxMode.Info);
+ }
+ }
+
+ /// <summary>
+ /// Creates a new Lua Interpreter but doesn't interpret a file.
+ /// </summary>
+ public LuaInterpreter()
+ {
+ Errors.Clear();
+ //Initiate the interpreter
+ mod = new DynamicLua.DynamicLua();
+ //Register core functions with the interpreter
+ RegisterCore();
+ var t = new System.Windows.Forms.Timer();
+ t.Interval = 50;
+ ThisDirectory = Paths.SaveRoot;
+ t.Tick += (object se, EventArgs ea) =>
+ {
+ if (Errors.Count > 0)
+ {
+ if (API.LoggerTerminal != null)
+ {
+ API.LoggerTerminal.WriteLine(Errors[0]);
+ Errors.Remove(Errors[0]);
+ }
+ else
+ {
+ API.CreateInfoboxSession("Script Error", $"An error has occurred in your script: {Errors[0]}", infobox.InfoboxMode.Info);
+ Errors.Remove(Errors[0]);
+ }
+ ExitScript();
+ }
+ };
+ t.Start();
+ }
+
+ /// <summary>
+ /// Registers all core ShiftOS Lua functions with their C# counterparts.
+ ///
+ /// This is so we don't have to expose the entire source code to the interpreter. Add new functions here.
+ /// </summary>
+ public void RegisterCore()
+ {
+ //Shifter Extension API
+ mod.shifter_add_category = new Action<string>((name) =>
+ {
+ bool add = true;
+ if(API.LuaShifterRegistry == null)
+ {
+ API.LuaShifterRegistry = new Dictionary<string, Dictionary<string, object>>();
+ }
+ foreach(var kv in API.LuaShifterRegistry)
+ {
+ if (kv.Key == name)
+ add = false;
+ }
+ if(add == true)
+ {
+ API.LuaShifterRegistry.Add(name, new Dictionary<string, object>());
+ }
+ else
+ {
+ Errors.Add($"shifter_add_category(\"{name}\"): Error: Category already exists!");
+ }
+ });
+ mod.shifter_remove_category = new Action<string>((name) =>
+ {
+ if(API.LuaShifterRegistry.ContainsKey(name))
+ {
+ API.LuaShifterRegistry.Remove(name);
+ }
+ else
+ {
+ Errors.Add($"shifter_remove_category(\"{name}\"): No such category.");
+ }
+ });
+ mod.shifter_add_value = new Action<string, string, object>((cat, name, in_value) =>
+ {
+ if(API.LuaShifterRegistry.ContainsKey(cat))
+ {
+ var lst = API.LuaShifterRegistry[cat];
+ if(!lst.ContainsKey(name))
+ {
+ lst.Add(name, in_value);
+ }
+ else
+ {
+ Errors.Add($"shifter_add_value(\"{cat}\", \"{name}\", in_value): Category was found, but it already contained a value with the specified name.");
+ }
+ }
+ else
+ {
+ Errors.Add($"shifter_add_value(\"{cat}\", \"{name}\", in_value): Category not found.");
+ }
+ });
+ mod.shifter_get_value = new Func<string, string, object>((cat, name) =>
+ {
+ if (API.LuaShifterRegistry.ContainsKey(cat))
+ {
+ var lst = API.LuaShifterRegistry[cat];
+ if (lst.ContainsKey(name))
+ {
+ return lst[name];
+ }
+ else
+ {
+ Errors.Add($"shifter_add_value(\"{cat}\", \"{name}\", in_value): Category was found, but it already contained a value with the specified name.");
+ return null;
+ }
+ }
+ else
+ {
+ Errors.Add($"shifter_add_value(\"{cat}\", \"{name}\", in_value): Category not found.");
+ return null;
+ }
+ });
+
+
+ //APIs.
+ mod.load_api = new Action<string>((name) =>
+ {
+ if(File.Exists(Paths.APIs + name + ".lua"))
+ {
+ mod(File.ReadAllText(Paths.APIs + name + ".lua"));
+ }
+ });
+
+ //Functions with Return Values
+ mod.get_app_launcher_items = new Func<List<ApplauncherItem>>(() =>
+ {
+ var lst = new List<ApplauncherItem>();
+ API.GetAppLauncherItems();
+ foreach(var itm in API.AppLauncherItems)
+ {
+ if(itm.Display == true)
+ {
+ lst.Add(itm);
+ }
+ }
+ return lst;
+ });
+ mod.local_image = new Func<string, Image>((filepath) => OpenLocalImage(filepath));
+ mod.json_serialize = new Func<object, string>((objectToSerialize) => Newtonsoft.Json.JsonConvert.SerializeObject(objectToSerialize));
+ mod.json_unserialize = new Func<string, object>((json_string) => Newtonsoft.Json.JsonConvert.DeserializeObject(json_string));
+ mod.open_image = new Func<string, Image>((filename) => OpenImage(filename));
+ mod.get_skin = new Func<Skinning.Skin>(() =>
+ {
+ return API.CurrentSkin;
+ });
+ mod.get_skin_images = new Func<Skinning.Images>(() =>
+ {
+ return API.CurrentSkinImages;
+ });
+ mod.upgrades = new Func<string, bool>((id) => GetUpgrade(id));
+ mod.create_widget = new Func<string, string, int, int, int, int, bool, Control>((type, text, x, y, width, height, dark_mode) => ConstructControl(type, text, x, y, width, height, dark_mode));
+ mod.screen_get_width = new Func<int>(() =>
+ {
+ return System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width;
+ });
+ mod.screen_get_height = new Func<int>(() =>
+ {
+ return System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height;
+ });
+ mod.create_window_borderless = new Func<int, int, int, int, Form>((x, y, width, height) => CreateForm(x, y, width, height));
+
+ mod.random = new Func<int, int, int>((min, max) =>
+ {
+ return new Random().Next(min, max);
+ });
+ mod.color = new Func<int, int, int, Color>((r, g, b) =>
+ {
+ try
+ {
+ return Color.FromArgb(r, g, b);
+ }
+ catch
+ {
+ Errors.Add("Invalid color values. Values must be a minimum of 0 and a maximum of 255.");
+ return new Color();
+ }
+ });
+ mod.speechrec_create = new Func<SpeechListener>(() =>
+ {
+ return new SpeechListener();
+ });
+ mod.speechrec_on_recognize = new Action<SpeechListener, string>((obj, func) =>
+ {
+ obj.OnRecognize += (object s, EventArgs a) =>
+ {
+ mod($"{func}('{s.ToString()}')");
+ };
+ obj.Engine.RecognizeAsync();
+ });
+ mod.get_desktop_session = new Func<Form>(() =>
+ {
+ return API.CurrentSession;
+ });
+ mod.get_icon = new Func<string, Image>((id) => API.GetIcon(id));
+ mod.add_icon = new Action<string, Image>((id, img) =>
+ {
+ if(!API.IconRegistry.ContainsKey(id))
+ {
+ API.IconRegistry.Add(id, img);
+ Skinning.Utilities.saveimages();
+ }
+ });
+ mod.icon_exists = new Func<string, bool>((id) =>
+ {
+ return API.IconRegistry.ContainsKey(id);
+ });
+ mod.create_window = new Func<string, Image, int, int, Form>((title, icon, width, height) => CreateForm(title, icon, width, height));
+ mod.get_codepoints = new Func<int>(() => GetCP());
+ mod.buy_upgrade = new Func<string, bool>((id) => BuyUPG(id));
+ mod.time = new Func<string>(() => API.GetTime());
+ mod.encrypt = new Func<string, string>((raw) => API.Encryption.Encrypt(raw));
+ mod.decrypt = new Func<string, string>((raw) => API.Encryption.Decrypt(raw));
+ mod.fread = new Func<string, string>((filepath) => SafeFileRead(filepath));
+ mod.terminal = new Action<string>((command) =>
+ {
+ var t = new Terminal();
+ API.CreateForm(t, API.LoadedNames.TerminalName, API.GetIcon("Terminal"));
+ t.command = command;
+ t.DoCommand();
+ });
+ mod.fwrite = new Action<string, string>((path, contents) =>
+ {
+ if (path.StartsWith("/"))
+ {
+ var real_path = $"{Paths.SaveRoot}{path.Replace("/", OSInfo.DirectorySeparator)}";
+ if(!Directory.Exists(real_path))
+ {
+ File.WriteAllText(real_path, contents);
+ }
+ }
+ });
+ mod.add_menu_item = new Func<string, MenuStrip, ToolStripMenuItem>((text, parent) => AddMenuItem(text, parent));
+ mod.add_child_menu_item = new Func<string, ToolStripMenuItem, ToolStripMenuItem>((text, parent) =>
+ {
+ try
+ {
+ var i = new ToolStripMenuItem();
+ i.Text = text;
+ parent.DropDownItems.Add(i);
+ return i;
+ }
+ catch(Exception ex)
+ {
+ Errors.Add("add_child_menu_item(): Error adding child item to parent. " + ex.Message);
+ return null;
+ }
+ });
+ mod.set_anchor = new Action<Control, string>((ctrl, anchorstyle) => SetAnchor(ctrl, anchorstyle));
+
+ //Standard API Functions
+ mod.include = new Action<string>((filepath) => IncludeScript(filepath));
+ mod.log = new Action<string>((msg) => API.Log(msg));
+ mod.add_codepoints = new Action<int>((amount) => API.AddCodepoints(amount));
+ mod.remove_codepoints = new Action<int>((amount) => API.RemoveCodepoints(amount));
+ mod.launch_mod = new Action<string>((modSAA) => API.LaunchMod(Paths.SaveRoot + modSAA.Replace("/", OSInfo.DirectorySeparator)));
+ mod.open_program = new Action<string>((progname) => API.OpenProgram(progname));
+ mod.close_program = new Action<string>((progname) => API.CloseProgram(progname));
+ mod.close_everything = new Action(() => API.CloseEverything());
+ mod.shutdown = new Action(() => API.ShutDownShiftOS());
+ mod.update_ui = new Action(() => { API.UpdateWindows(); API.CurrentSession.SetupDesktop(); });
+ mod.load_skin = new Action<string>((filepath) => Skinning.Utilities.loadsknfile(filepath));
+ mod.save_to_skin_file = new Action<string>((filepath) => Skinning.Utilities.saveskintofile(filepath));
+ mod.on_click = new Action<Control, string>((ctrl, funcname) => RegClick(ctrl, funcname));
+ mod.add_widget_to_window = new Action<Form, Control>((win, ctrl) => AddCtrl(win, ctrl));
+ mod.open_file = new Action<string, string>((filters, function) => OpenFile(filters, function));
+ mod.panel_add_widget = new Action<Control, Control>((ctrl, parent) =>
+ {
+ try {
+ var p = (Panel)parent;
+ p.Controls.Add(ctrl);
+ } catch(Exception ex)
+ {
+ Errors.Add(ex.Message);
+ }
+ });
+ mod.flow_add_widget = new Action<Control, Control>((ctrl, parent) =>
+ {
+ try
+ {
+ var p = (FlowLayoutPanel)parent;
+ p.Controls.Add(ctrl);
+ }
+ catch (Exception ex)
+ {
+ Errors.Add(ex.Message);
+ }
+ });
+ mod.info = new Action<string, string>((title, message) =>
+
+ API.CreateInfoboxSession(title, message, infobox.InfoboxMode.Info)
+
+ );
+ mod.on_menu_item_activate = new Action<ToolStripMenuItem, string>((item, function) =>
+ {
+ item.Click += (object s, EventArgs a) =>
+ {
+ mod($"{function}()");
+ };
+ });
+ mod.create_timer = new Func<int, System.Windows.Forms.Timer>((interval) =>
+ {
+ var t = new System.Windows.Forms.Timer();
+ t.Interval = interval;
+ return t;
+ });
+ mod.timer_on_tick = new Action<System.Windows.Forms.Timer, string>((tmr, func) =>
+ {
+ try
+ {
+ tmr.Tick += (object s, EventArgs a) =>
+ {
+ mod($"{func}()");
+ };
+ }
+ catch(Exception ex)
+ {
+ Errors.Add(ex.Message);
+ }
+ });
+ mod.add_widget_to_desktop = new Action<Control>((ctrl) => AddToDesktop(ctrl));
+ mod.set_dock = new Action<Control, string>((ctrl, dstyle) =>
+ {
+ API.CurrentSession.Invoke(new Action(() =>
+ {
+ switch (dstyle.ToLower())
+ {
+ case "fill":
+ ctrl.Dock = DockStyle.Fill;
+ break;
+ case "top":
+ ctrl.Dock = DockStyle.Top;
+ break;
+ case "bottom":
+ ctrl.Dock = DockStyle.Bottom;
+ break;
+ case "left":
+ ctrl.Dock = DockStyle.Left;
+ break;
+ case "right":
+ ctrl.Dock = DockStyle.Right;
+ break;
+ case "none":
+ ctrl.Dock = DockStyle.None;
+ break;
+
+
+
+
+ }
+ }));
+ });
+ mod.webview_navigate = new Action<GeckoWebBrowser, string>((wv, url) => Navigate(wv, url));
+ mod.open_terminal = new Action(() =>
+ {
+ var t = new Terminal();
+ API.CreateForm(t, API.LoadedNames.TerminalName, API.GetIcon("Terminal"));
+ });
+ mod.create_directory = new Action<string>((path) =>
+ {
+ path = $"{Paths.SaveRoot}{path.Replace("/", OSInfo.DirectorySeparator)}";
+ if (!Directory.Exists(path))
+ {
+ Directory.CreateDirectory(path);
+ }
+ });
+ mod.exists = new Func<string, bool>((path) =>
+ {
+ path = $"{Paths.SaveRoot}{path.Replace("/", OSInfo.DirectorySeparator)}";
+ if(Directory.Exists(path))
+ {
+ return true;
+ }
+ else if(File.Exists(path))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ });
+ mod.notify = new Action<string, string>((title, message) => API.CurrentSession.AddNotification(title, message));
+ mod.download_file = new Action<string, string>((web_address, local) => DownloadFile(web_address, local));
+ mod.on_key_down = new Action<Control, string>((ctrl, action) => RegKeyDown(ctrl, action));
+ mod.get_files = new Func<string, List<string>>((path) => GetFiles(path));
+ mod.get_folders = new Func<string, List<string>>((path) => GetFolders(path));
+ mod.zip = new Action<string, string>((source, destination) =>
+ {
+ var real = $"{Paths.SaveRoot}{source.Replace("/", OSInfo.DirectorySeparator)}";
+ if(Directory.Exists(real))
+ {
+ var real_dest = $"{Paths.SaveRoot}{destination.Replace("/", OSInfo.DirectorySeparator)}";
+ ZipFile.CreateFromDirectory(real, real_dest);
+ }
+ else
+ {
+ mod.info("Script Error", "Your script tried to zip up a non-existent folder.");
+ }
+ });
+ mod.beep = new Action<int, int>((freq, dur) => Beep(freq, dur));
+ mod.color_picker += new Action<string, Color, string>((title, oldcolor, func) =>
+ {
+ API.CreateColorPickerSession(title, oldcolor);
+ API.ColorPickerSession.FormClosing += (object s, FormClosingEventArgs a) =>
+ {
+ var c = API.GetLastColorFromSession();
+ mod($"{func}(color({c.R}, {c.G}, {c.B}))");
+ };
+ });
+ mod.info_yes_no += new Action<string, string, string>((title, message, func) =>
+ {
+ API.CreateInfoboxSession(title, message, infobox.InfoboxMode.YesNo);
+ API.InfoboxSession.FormClosing += (object s, FormClosingEventArgs a) =>
+ {
+ var res = API.GetInfoboxResult();
+ if(res == "Yes" || res == "No")
+ {
+ mod($"{func}(\"{res}\")");
+ }
+ };
+ });
+
+
+ //Script Management
+ mod.exit = new Action(() => ExitScript());
+ mod.shutdown = new Action(() => API.ShutDownShiftOS());
+ mod.toggle_unity = new Action(() => API.CurrentSession.SetUnityMode());
+ mod.lua = new Func<string, string>((luacode) =>
+ {
+ var li = new LuaInterpreter();
+ try
+ {
+ li.mod(luacode);
+ return "success";
+ }
+ catch (Exception ex)
+ {
+ return ex.Message;
+ }
+ });
+ mod.fileskimmer_open += new Action<string, string>((filters, func) =>
+ {
+ API.CreateFileSkimmerSession(filters, File_Skimmer.FileSkimmerMode.Open);
+ API.FileSkimmerSession.FormClosing += (object s, FormClosingEventArgs a) =>
+ {
+ var res = API.GetFSResult();
+ if(res != "fail")
+ {
+ var real_path = res.Replace(Paths.SaveRoot, "/").Replace("\\", "/");
+ mod($"{func}(\"{real_path}\")");
+ }
+ };
+ });
+ mod.fileskimmer_save += new Action<string, string>((filters, func) =>
+ {
+ API.CreateFileSkimmerSession(filters, File_Skimmer.FileSkimmerMode.Save);
+ API.FileSkimmerSession.FormClosing += (object s, FormClosingEventArgs a) =>
+ {
+ var res = API.GetFSResult();
+ if (res != "fail")
+ {
+ var real_path = res.Replace(Paths.SaveRoot, "/").Replace("\\", "/");
+ mod($"{func}(\"{real_path}\")");
+ }
+ };
+ });
+ mod.gen_font = new Func<string, int, Font>((style, size) => {
+ return new Font(style, size);
+ });
+
+
+ //other
+ mod.fileskimmer = new Action<string>((folder) => OpenFS(folder));
+ mod.fopen = new Action<string>((file) => OpenFile(file));
+ mod.loadstring = new Action<string>((code) => { mod(code); });
+
+ //Multithreading
+ mod.new_thread = new Func<string, Thread>((code) =>
+ {
+ return new Thread(() =>
+ {
+ mod(code);
+ });
+ });
+ mod.start_async = new Action<Thread>((t) => { t.Start(); });
+
+ mod.add_applauncher_item = new Action<string, string>((name, lua) =>
+ {
+ var m = new ModApplauncherItem();
+ m.Name = name;
+ m.Lua = lua;
+ File.WriteAllText(Paths.Mod_AppLauncherEntries + m.Name, JsonConvert.SerializeObject(m));
+ API.UpdateWindows();
+ API.CurrentSession.SetupDesktop();
+ });
+ mod.get_loaded_skin = new Func<Skinning.Skin>(() => { return API.CurrentSkin; });
+ mod.reload_skin = new Action(() => { API.CurrentSession.SetupDesktop(); API.UpdateWindows(); });
+ mod.get_applauncher_item = new Func<string, ToolStripMenuItem>((name) =>
+ {
+ ToolStripMenuItem i = null;
+ foreach(var item in API.CurrentSession.ApplicationsToolStripMenuItem.DropDownItems)
+ {
+ try {
+ ToolStripMenuItem it = (ToolStripMenuItem)item;
+ if (it.Text == name)
+ {
+ i = it;
+ }
+ }
+ catch
+ {
+
+ }
+ }
+ return i;
+ });
+ mod.get_menu_item = new Func<ToolStripMenuItem, string, ToolStripMenuItem>((parent, name) =>
+ {
+ ToolStripMenuItem i = null;
+ foreach (ToolStripMenuItem item in parent.DropDownItems)
+ {
+ if (item.Text == name)
+ {
+ i = item;
+ }
+ }
+ return i;
+ });
+ GC.Collect();
+ }
+
+
+ /// <summary>
+ /// Sends a keydown event to Lua when you press a key on the specified control.
+ /// </summary>
+ /// <param name="ctrl">Control to assign the event to.</param>
+ /// <param name="action">Function to call on keydown.</param>
+ public void RegKeyDown(Control ctrl, string action)
+ { /* */
+ ctrl.KeyDown += (object s, KeyEventArgs a) =>
+ {
+ mod($"{action}(\"{a.KeyCode.ToString().ToLower()}\")");
+ };
+ }
+
+ /// <summary>
+ /// Gets a list of files.
+ /// </summary>
+ /// <param name="dir">Directory to scan.</param>
+ /// <returns>A System.Collections.Generic.List of all files.</returns>
+ public List<string> GetFiles(string dir)
+ {
+ if (Directory.Exists($"{Paths.SaveRoot}{dir.Replace("/", OSInfo.DirectorySeparator)}"))
+ {
+ var luatable = new List<string>();
+ foreach (string val in Directory.GetFiles($"{Paths.SaveRoot}{dir.Replace("/", OSInfo.DirectorySeparator)}"))
+ {
+ luatable.Add(val);
+ }
+ return luatable;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// Gets a list of folders.
+ /// </summary>
+ /// <param name="dir">Directory to scan.</param>
+ /// <returns>A System.Collections.Generic.List of all folders.</returns>
+
+ public List<string> GetFolders(string dir)
+ {
+ if (Directory.Exists($"{Paths.SaveRoot}{dir.Replace("/", OSInfo.DirectorySeparator)}"))
+ {
+ var luatable = new List<string>();
+ foreach(string val in Directory.GetDirectories($"{Paths.SaveRoot}{dir.Replace("/", OSInfo.DirectorySeparator)}"))
+ {
+ luatable.Add(val);
+ }
+
+
+ return luatable;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public string ThisDirectory = null;
+
+ /// <summary>
+ /// Downloads a file.
+ /// </summary>
+ /// <param name="web">Web URL to download</param>
+ /// <param name="local">A ShiftOS path to download to.</param>
+ public void DownloadFile(string web, string local)
+ {
+ var wc = new WebClient();
+ try
+ {
+ var real_path = $"{Paths.SaveRoot}{local.Replace("/", OSInfo.DirectorySeparator)}";
+ wc.DownloadFile(web, real_path);
+ mod.notify("Download complete", "Successfully downloaded file " + web + " from the Internet.");
+ }
+ catch(Exception ex)
+ {
+ mod.print("Could not download remote file " + web + ", " + ex.Message);
+ }
+ }
+
+ /// <summary>
+ /// Interprets a script within this interpreter.
+ /// </summary>
+ /// <param name="filename">Script file.</param>
+ public void IncludeScript(string filename)
+ {
+ var real_file = $"{ThisDirectory}{filename.Replace("/", OSInfo.DirectorySeparator)}";
+ var lua = File.ReadAllText(real_file);
+ try {
+ mod(lua);
+ }
+ catch(Exception ex)
+ {
+ mod.info("Script Error", "An error has occurred in your script: " + ex.Message);
+ }
+ }
+
+ /// <summary>
+ /// Open a file skimmer in the specified directory.
+ /// </summary>
+ /// <param name="dir">Directory to open in.</param>
+ public void OpenFS(string dir)
+ {
+ var f = new File_Skimmer();
+ API.CreateForm(f, API.LoadedNames.FileSkimmerName, Properties.Resources.iconFileSkimmer);
+ if(dir.StartsWith("/"))
+ {
+ var real = dir;
+ var real_slash = real.Replace("/", OSInfo.DirectorySeparator);
+ var real_path = $"{Paths.SaveRoot}{real_slash}";
+ f.CurrentFolder = real_path;
+ f.ListFiles();
+ }
+ }
+
+ /// <summary>
+ /// Opens a file in the right program.
+ /// </summary>
+ /// <param name="dir">The file path. Why this is named "dir", which means DIRECTORY, not FILE, by the way, is beyond me.</param>
+ public void OpenFile(string dir)
+ {
+ var f = new File_Skimmer();
+ if (dir.StartsWith("/"))
+ {
+ var real = dir;
+ var real_slash = real.Replace("/", OSInfo.DirectorySeparator);
+ var real_path = $"{Paths.SaveRoot}{real_slash}";
+ f.OpenFile(real_path);
+ }
+ }
+
+ public List<Form> OpenForms = new List<Form>();
+
+ /// <summary>
+ /// Exits the script. What did you think it would do?
+ /// </summary>
+ public void ExitScript()
+ {
+ foreach(Form f in OpenForms)
+ {
+ f.Close();
+ }
+ }
+
+ /// <summary>
+ /// Set control anchor from Lua.
+ /// </summary>
+ /// <param name="ctrl">Target control</param>
+ /// <param name="anchor">Anchor string (for example "top;left;bottom;right" or "top;left" or "top")</param>
+ public void SetAnchor(Control ctrl, string anchor)
+ {
+ var a = AnchorStyles.None;
+ var l = anchor.ToLower();
+ if(l.Contains("left"))
+ {
+ a = a | AnchorStyles.Left;
+ }
+ if (l.Contains("right"))
+ {
+ a = a | AnchorStyles.Right;
+ }
+ if (l.Contains("bottom"))
+ {
+ a = a | AnchorStyles.Bottom;
+ }
+ if (l.Contains("top"))
+ {
+ a = a | AnchorStyles.Bottom;
+ }
+ ctrl.Anchor = a;
+ }
+
+ /// <summary>
+ /// Navigate a webview to the specified URL.
+ /// </summary>
+ /// <param name="wv">The webview control. YES, We use Gecko, not Internet Exploder.</param>
+ /// <param name="url">The target URL, for example "http://playshiftos.ml/forum"</param>
+ public void Navigate(GeckoWebBrowser wv, string url)
+ {
+ wv.Navigate(url);
+ }
+
+ /// <summary>
+ /// Add a control to the desktop.
+ /// </summary>
+ /// <param name="ctrl">The control to add.</param>
+ public void AddToDesktop(Control ctrl)
+ {
+ API.CurrentSession.Controls.Add(ctrl);
+ }
+
+ /// <summary>
+ /// Add a child to a menu item.
+ /// </summary>
+ /// <param name="text">New item's text</param>
+ /// <param name="parent">New item's parent.</param>
+ /// <returns>The new item.</returns>
+ public ToolStripMenuItem AddMenuItem(string text, MenuStrip parent)
+ {
+ var itm = new ToolStripMenuItem();
+ itm.Text = text;
+ itm.Tag = "menu_item";
+ parent.Items.Add(itm);
+ return itm;
+ }
+
+ /// <summary>
+ /// Allows the user to get a user to open a file.
+ /// </summary>
+ /// <param name="fi">File filter.</param>
+ /// <param name="fu">Function to call on select.</param>
+ public void OpenFile(string fi, string fu)
+ {
+ API.CreateFileSkimmerSession(fi, File_Skimmer.FileSkimmerMode.Open);
+ API.FileSkimmerSession.FormClosing += (object s, FormClosingEventArgs a) =>
+ {
+ mod($"{fu}({API.GetFSResult()})");
+ };
+ }
+
+ /// <summary>
+ /// Prompt user to save a file.
+ /// </summary>
+ /// <param name="fi">File filters.</param>
+ /// <param name="fu">Function to call.</param>
+ public void SaveFile(string fi, string fu)
+ {
+ API.CreateFileSkimmerSession(fi, File_Skimmer.FileSkimmerMode.Save);
+ API.FileSkimmerSession.FormClosing += (object s, FormClosingEventArgs a) =>
+ {
+ mod($"{fu}({API.GetFSResult()})");
+ };
+ }
+
+
+ /// <summary>
+ /// Safely read a file.
+ /// </summary>
+ /// <param name="path">File to read.</param>
+ /// <returns>Contents of the file.</returns>
+ public string SafeFileRead(string path)
+ {
+ string contents = "";
+ if(path.StartsWith("/"))
+ {
+ var real = $"{Paths.SaveRoot}{path.Replace("\\", "/")}";
+ if(File.Exists(real))
+ {
+ contents = File.ReadAllText(real);
+
+ }
+ else
+ {
+ Errors.Add("fread(): File not found.");
+ }
+ }
+ else
+ {
+ Errors.Add("fread(): Path not valid.");
+ }
+ return contents;
+ }
+
+ /// <summary>
+ /// Buy a shiftorium upgrade.
+ /// </summary>
+ /// <param name="id">Upgrade ID.</param>
+ /// <returns>Did the upgrade get bought successfully?</returns>
+ public bool BuyUPG(string id)
+ {
+ if(API.Upgrades.ContainsKey(id))
+ {
+ bool bought = false;
+ foreach(Shiftorium.Upgrade upg in SaveSystem.ShiftoriumRegistry.DefaultUpgrades)
+ {
+ if(upg.id == id)
+ {
+ bought = Shiftorium.Utilities.Buy(upg);
+ }
+ }
+ return bought;
+ }
+ else
+ {
+ //Upgrade doesn't exist.
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Checks if an upgrade is bought.
+ /// </summary>
+ /// <param name="id">Upgrade ID.</param>
+ /// <returns>Whether or not it is bought</returns>
+ public bool GetUpgrade(string id)
+ {
+ if(API.Upgrades.ContainsKey(id))
+ {
+ return API.Upgrades[id];
+ }
+ else
+ {
+ //Upgrade doesn't exist.
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Gets the current amount of Codepoints.
+ /// </summary>
+ /// <returns>Can you read? Sorry, it's just... I don't feel like typing the same thing twice...</returns>
+ public int GetCP()
+ {
+ return API.CurrentSave.codepoints;
+ }
+
+ /// <summary>
+ /// Constructs a WinForms control.
+ /// </summary>
+ /// <param name="type">Control type.</param>
+ /// <param name="text">Control text.</param>
+ /// <param name="x">X coordinate.</param>
+ /// <param name="y">Y coordinate.</param>
+ /// <param name="width">Width.</param>
+ /// <param name="height">Height.</param>
+ /// <param name="darkmode">Is it dark?</param>
+ /// <returns>The control, all ShiftOS-ified for you.</returns>
+ public Control ConstructControl(string type, string text, int x, int y, int width, int height, bool darkmode)
+ {
+ var ctrl = new Control();
+ switch(type.ToLower())
+ {
+ case "button":
+ var btn = new Button();
+ btn.FlatStyle = FlatStyle.Flat;
+ if(darkmode)
+ {
+ //Set dark button
+ btn.ForeColor = API.CurrentSkin.titletextcolour;
+ btn.BackColor = API.CurrentSkin.titlebarcolour;
+ }
+ else
+ {
+ btn.BackColor = Color.White;
+ btn.ForeColor = Color.Black;
+ }
+ ctrl = (Control)btn;
+ break;
+ case "webview":
+ var g = new Gecko.GeckoWebBrowser();
+ g.NoDefaultContextMenu = true;
+ ctrl = (Gecko.GeckoWebBrowser)g;
+ //This control renders HTML, so therefore a dark theme is futile.
+ break;
+ case "menustrip":
+ ctrl = new MenuStrip();
+ ctrl.Tag = "menustrip";
+ //Menu Strips are rendered using a custom renderer, thus, DarkMode is not required.
+ break;
+ case "panel":
+ ctrl = new Panel();
+ if(darkmode)
+ {
+ ctrl.BackColor = API.CurrentSkin.titlebarcolour;
+ ctrl.ForeColor = API.CurrentSkin.titletextcolour;
+ }
+ else
+ {
+ ctrl.BackColor = Color.White;
+ ctrl.ForeColor = Color.Black;
+ }
+ break;
+ case "flow":
+ ctrl = new FlowLayoutPanel();
+ if(darkmode)
+ {
+ ctrl.BackColor = API.CurrentSkin.titlebarcolour;
+ ctrl.ForeColor = API.CurrentSkin.titletextcolour;
+ }
+ else
+ {
+ ctrl.BackColor = Color.White;
+ ctrl.ForeColor = Color.Black;
+ }
+ break;
+ case "label":
+ ctrl = new Label();
+ //Text Color and Back Color inherited from parent.
+ break;
+ case "textbox":
+ ctrl = new TextBox();
+ if(darkmode)
+ {
+ ctrl.BackColor = API.CurrentSkin.titlebarcolour;
+ ctrl.ForeColor = API.CurrentSkin.titletextcolour;
+ }
+ else
+ {
+ ctrl.BackColor = Color.White;
+ ctrl.ForeColor = Color.Black;
+ }
+ break;
+ case "richtextbox":
+ ctrl = new RichTextBox();
+ if(darkmode)
+ {
+ ctrl.BackColor = API.CurrentSkin.titlebarcolour;
+ ctrl.ForeColor = API.CurrentSkin.titletextcolour;
+ }
+ else
+ {
+ ctrl.BackColor = Color.White;
+ ctrl.ForeColor = Color.Black;
+ }
+ break;
+ default:
+ ctrl = new Control();
+ if(darkmode)
+ {
+ ctrl.BackColor = API.CurrentSkin.titlebarcolour;
+ ctrl.ForeColor = API.CurrentSkin.titletextcolour;
+ }
+ else
+ {
+ ctrl.BackColor = Color.White;
+ ctrl.ForeColor = Color.Black;
+ }
+ break;
+ }
+ ctrl.Text = text;
+ ctrl.Name = text.ToLower().Replace(" ", "_");
+ ctrl.Location = new Point(x, y);
+ ctrl.Size = new Size(width, height);
+ ctrl.Visible = true;
+ return ctrl;
+ }
+
+
+ /// <summary>
+ /// Broken, piece of dump beep function.
+ /// </summary>
+ /// <param name="freq">Frequency.</param>
+ /// <param name="duration">Length.</param>
+ public void Beep(int freq, int duration)
+ {
+ Beeper.Play(freq, duration);
+
+ }
+
+ /// <summary>
+ /// Adds a control to a window.
+ /// </summary>
+ /// <param name="win">Target window</param>
+ /// <param name="ctrl">Control to add.</param>
+ public void AddCtrl(Form win, Control ctrl)
+ {
+
+ List<WindowBorder> borders = new List<WindowBorder>();
+ foreach(Control c in win.Controls)
+ {
+ if(c.Name == "api_brdr")
+ {
+ var b = (WindowBorder)c;
+ b.pgcontents.Controls.Add(ctrl);
+ ctrl.BringToFront();
+ borders.Add(b);
+ }
+ }
+ if(borders.Count == 0)
+ {
+ win.Controls.Add(ctrl);
+ }
+
+ }
+
+ /// <summary>
+ /// Fire a click event when you click the control.
+ /// </summary>
+ /// <param name="ctrl">Target control</param>
+ /// <param name="funcname">Function to call.</param>
+ public void RegClick(Control ctrl, string funcname)
+ {
+ ctrl.MouseDown += (object s, MouseEventArgs a) =>
+ {
+ if (a.Button == MouseButtons.Left)
+ {
+ mod($"{funcname}()");
+ }
+ };
+ }
+
+ /// <summary>
+ /// Creates a ShiftOS window.
+ /// </summary>
+ /// <param name="title">Window title.</param>
+ /// <param name="img">Window icon</param>
+ /// <param name="width">Width</param>
+ /// <param name="height">Height</param>
+ /// <returns>The new window</returns>
+ public Form CreateForm(string title, Image img, int width, int height)
+ {
+ GC.Collect();
+ //Create new Form instance.
+ var f = new Form();
+ //Set size of form
+ if(width < 100)
+ {
+ width = 100;
+ }
+ if(height < 100)
+ {
+ height = 100;
+ }
+ f.Size = new Size(width, height);
+ //ShiftOSify it.
+ API.CreateForm(f, title, img);
+ //Add to list of forms that should be closed on script exit
+ OpenForms.Add(f);
+ //Return it.
+ return f;
+ }
+
+ /// <summary>
+ /// Creates a borderless window.
+ /// </summary>
+ /// <param name="x">Starting X coordinate.</param>
+ /// <param name="y">Starting Y coordinate</param>
+ /// <param name="width">Width</param>
+ /// <param name="height">Height</param>
+ /// <returns>The new window.</returns>
+ public Form CreateForm(int x, int y, int width, int height)
+ {
+ GC.Collect();
+ //Create new Form instance.
+ var f = new Form();
+ //Set size of form
+ if (width < 100)
+ {
+ width = 100;
+ }
+ if (height < 100)
+ {
+ height = 100;
+ }
+ f.Size = new Size(width, height);
+ f.FormBorderStyle = FormBorderStyle.None;
+ f.Location = new Point(x, y);
+ f.Show();
+ //Add to list of forms that should be closed on script exit
+ OpenForms.Add(f);
+ //Return it.
+ return f;
+ }
+
+ /// <summary>
+ /// Opens an image file.
+ /// </summary>
+ /// <param name="filepath">File path</param>
+ /// <returns>Loaded image</returns>
+ public Image OpenLocalImage(string filepath)
+ {
+ if (filepath.StartsWith("/"))
+ {
+ var real = $"{ThisDirectory}{filepath.Replace("/", OSInfo.DirectorySeparator)}";
+ if (File.Exists(real))
+ {
+ try
+ {
+ return Image.FromFile(real);
+ }
+ catch (Exception ex)
+ {
+ Errors.Add(ex.Message);
+ return null;
+ }
+
+ }
+ else
+ {
+ Errors.Add($"open_image({filepath}): File not found.");
+ return null;
+ }
+ }
+ else
+ {
+ Errors.Add($"open_image({filepath}): Not a valid file path.");
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// Opens an image file.
+ /// </summary>
+ /// <param name="filepath">File path</param>
+ /// <returns>Loaded image</returns>
+ public Image OpenImage(string filepath)
+ {
+ if (filepath.StartsWith("/"))
+ {
+ var real = $"{Paths.SaveRoot}{filepath.Replace("/", OSInfo.DirectorySeparator)}";
+ if(File.Exists(real))
+ {
+ try
+ {
+ return Image.FromFile(real);
+ }
+ catch (Exception ex)
+ {
+ Errors.Add(ex.Message);
+ return null;
+ }
+
+ }
+ else
+ {
+ Errors.Add($"open_image({filepath}): File not found.");
+ return null;
+ }
+ }
+ else
+ {
+ Errors.Add($"open_image({filepath}): Not a valid file path.");
+ return null;
+ }
+ }
+ }
+
+ public class Beeper
+ {
+ static Thread _beepThread;
+ static AutoResetEvent _signalBeep;
+ static bool _beeping = false;
+
+ static Beeper()
+ {
+ _signalBeep = new AutoResetEvent(false);
+ _beepThread = new Thread(() =>
+ {
+ for (;;)
+ {
+ while(_beeping == true)
+ {
+
+ }
+ _beeping = true;
+ Thread.Sleep(_freq);
+ Console.Beep(_freq, _dur);
+ _beeping = false;
+ }
+
+ }, 1);
+ _beepThread.IsBackground = true;
+ _beepThread.Start();
+ }
+ static int _freq = 38;
+ static int _dur = 1000;
+
+ public static void Play(int freq, int dur)
+ {
+ _freq = freq;
+ if (_freq <= 37)
+ {
+ _freq = 38;
+ }
+
+ _dur = dur;
+ _signalBeep.Set();
+ }
+ }
+
+
+}