mirror of
https://github.com/seriocomedy/ShiftOS-C-.git
synced 2025-01-22 10:50:27 -05:00
98fe96c5d3
Also this is the first REAL AppVeyor build test.
1453 lines
53 KiB
C#
1453 lines
53 KiB
C#
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()
|
|
{
|
|
//Desktop environment
|
|
mod.on_unity_check += new Action<ShiftOSDesktop, string>((desktop, func) =>
|
|
{
|
|
desktop.OnUnityCheck += () =>
|
|
{
|
|
mod(func + "()");
|
|
};
|
|
});
|
|
mod.on_unity_set += new Action<ShiftOSDesktop, string>((desktop, func) =>
|
|
{
|
|
desktop.OnUnityToggle += () =>
|
|
{
|
|
mod(func + "()");
|
|
};
|
|
});
|
|
mod.on_desktop_panel_draw += new Action<ShiftOSDesktop, string>((desktop, func) =>
|
|
{
|
|
desktop.OnDesktopPanelDraw += (c) =>
|
|
{
|
|
mod(func + $"(get_panel_from_guid(\"{c}\"))");
|
|
};
|
|
});
|
|
mod.get_panel_from_guid = new Func<string, Control>((guid) =>
|
|
{
|
|
foreach(var kv in API.DEF_PanelGUIDs)
|
|
{
|
|
if (kv.Key == guid)
|
|
return kv.Value;
|
|
}
|
|
return null;
|
|
});
|
|
|
|
mod.on_desktop_reset += new Action<ShiftOSDesktop, string>((desktop, func) =>
|
|
{
|
|
desktop.OnDesktopReload += () =>
|
|
{
|
|
mod(func + "()");
|
|
};
|
|
});
|
|
mod.on_clock_skin += new Action<ShiftOSDesktop, string>((desktop, func) =>
|
|
{
|
|
desktop.OnClockSkin += () =>
|
|
{
|
|
mod(func + "()");
|
|
};
|
|
});
|
|
mod.on_window_open += new Action<ShiftOSDesktop, string>((desktop, func) =>
|
|
{
|
|
desktop.WindowOpened += (win) =>
|
|
{
|
|
mod(func + $"(\"{API.OpenGUIDs[win]}\")");
|
|
};
|
|
});
|
|
mod.get_window = new Func<string, Form>((guid) =>
|
|
{
|
|
Form frm = null;
|
|
foreach(var kv in API.OpenGUIDs)
|
|
{
|
|
if (kv.Value == guid)
|
|
frm = kv.Key;
|
|
}
|
|
return frm;
|
|
});
|
|
mod.on_window_close += new Action<ShiftOSDesktop, string>((desktop, func) =>
|
|
{
|
|
desktop.WindowClosed += (win) =>
|
|
{
|
|
mod(func + $"(\"{API.OpenGUIDs[win]}\")");
|
|
};
|
|
});
|
|
mod.on_window_titlebar_redraw += new Action<ShiftOSDesktop, string>((desktop, func) =>
|
|
{
|
|
desktop.TitlebarReset += (win) =>
|
|
{
|
|
mod.win = win;
|
|
mod(func + "(win)");
|
|
};
|
|
});
|
|
mod.on_window_border_redraw += new Action<ShiftOSDesktop, string>((desktop, func) =>
|
|
{
|
|
desktop.BorderReset += (win) =>
|
|
{
|
|
mod.win = win;
|
|
mod(func + "(win)");
|
|
};
|
|
});
|
|
mod.on_window_skin += new Action<ShiftOSDesktop, string>((desktop, func) =>
|
|
{
|
|
desktop.WindowSkinReset += (win) =>
|
|
{
|
|
mod.win = win;
|
|
mod(func + "(win)");
|
|
};
|
|
});
|
|
mod.get_border = new Func<Form, WindowBorder>((Form win) =>
|
|
{
|
|
WindowBorder b = null;
|
|
foreach(Control c in win.Controls)
|
|
{
|
|
if (c is WindowBorder)
|
|
b = c as WindowBorder;
|
|
}
|
|
return b;
|
|
});
|
|
mod.def_update = new Action(() => API.UpdateWindows());
|
|
mod.on_app_launcher_populate += new Action<ShiftOSDesktop, string>((desktop, func) =>
|
|
{
|
|
desktop.OnAppLauncherPopulate += (items) =>
|
|
{
|
|
mod.al_items = items;
|
|
mod(func + "(clr_to_table(al_items))");
|
|
};
|
|
});
|
|
mod.on_panelbutton_populate += new Action<ShiftOSDesktop, string>((desktop, func) =>
|
|
{
|
|
desktop.OnPanelButtonPopulate += (items) =>
|
|
{
|
|
mod.pb_items = items;
|
|
mod(func + "(clr_to_table(pb_items))");
|
|
};
|
|
});
|
|
mod.intercept_ctrlt += new Action<string>((func) =>
|
|
{
|
|
API.CurrentSession.AllowCtrlTIntercept();
|
|
API.CurrentSession.CtrlTPressed += () =>
|
|
{
|
|
mod(func + "()");
|
|
};
|
|
});
|
|
mod.stop_intercept_ctrlt += new Action(() =>
|
|
{
|
|
API.CurrentSession.DisableCtrlTIntercept();
|
|
|
|
});
|
|
|
|
mod.on_desktopicon_populate += new Action<ShiftOSDesktop, string>((desktop, func) =>
|
|
{
|
|
desktop.DesktopIconsPopulated += (items) =>
|
|
{
|
|
mod.dl_items = items;
|
|
mod(func + "(clr_to_table(dl_items))");
|
|
};
|
|
});
|
|
|
|
|
|
mod(@"function clr_to_table(clrlist)
|
|
local t = {}
|
|
local it = clrlist:GetEnumerator()
|
|
while it:MoveNext() do
|
|
t[#t+1] = it.Current
|
|
end
|
|
return t
|
|
end");
|
|
|
|
mod.httpget = new Func<string, string>((url) =>
|
|
{
|
|
WebRequest request = WebRequest.Create(url);
|
|
Stream requestStream = request.GetResponse().GetResponseStream();
|
|
StreamReader requestRead = new StreamReader(requestStream);
|
|
return requestRead.ReadToEnd();
|
|
});
|
|
//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.list_add = new Action<Control, string>((lst, itm) =>
|
|
{
|
|
if(lst is ListBox)
|
|
{
|
|
var box = lst as ListBox;
|
|
box.Items.Add(itm);
|
|
}
|
|
});
|
|
mod.list_get_selected = new Func<Control, string>((lst) =>
|
|
{
|
|
if(lst is ListBox)
|
|
{
|
|
return (lst as ListBox).SelectedItem?.ToString();
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
});
|
|
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.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_old(raw));
|
|
mod.decrypt = new Func<string, string>((raw) => API.Encryption.Decrypt_old(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) =>
|
|
{
|
|
mod(luacode);
|
|
return "success";
|
|
|
|
});
|
|
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.open_File = mod.fileskimmer_open;
|
|
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.save_File = mod.fileskimmer_save;
|
|
mod.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().Replace(Paths.SaveRoot, "").Replace("\\", "/")}\")");
|
|
};
|
|
} //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
/// <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().Replace(Paths.SaveRoot, "").Replace("\\", "/")}\")");
|
|
};
|
|
}
|
|
|
|
|
|
/// <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 "luatextbox":
|
|
var stxt = new SyntaxRichTextBox();
|
|
stxt.Text = text;
|
|
stxt.SetLanguage(SyntaxSettings.Language.Lua);
|
|
ctrl = stxt;
|
|
break;
|
|
case "list":
|
|
var lst = new ListBox();
|
|
ctrl = lst;
|
|
break;
|
|
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();
|
|
}
|
|
}
|
|
|
|
|
|
}
|