mirror of
https://github.com/seriocomedy/ShiftOS-C-.git
synced 2025-01-23 09:32:14 +00:00
f1856e8ed3
This glitch has been prevelant ever since ShiftOS first had Knowledge Input. And I don't mean 0.1.0, I mean all the way back before 0.0.5 when OSFirstTimer was developing it. Basically, buttons would show light gray backgrounds when you click on them. Now they show black (and it's skinnable :D)
1474 lines
53 KiB
C#
1474 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 ShiftUI;
|
|
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 ShiftUI.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 ShiftUI.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, Widget>((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(Widget c in win.Widgets)
|
|
{
|
|
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<Widget, string>((lst, itm) =>
|
|
{
|
|
if(lst is ListBox)
|
|
{
|
|
var box = lst as ListBox;
|
|
box.Items.Add(itm);
|
|
}
|
|
});
|
|
mod.list_get_selected = new Func<Widget, 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, Widget>((type, text, x, y, width, height, dark_mode) => ConstructWidget(type, text, x, y, width, height, dark_mode));
|
|
mod.screen_get_width = new Func<int>(() =>
|
|
{
|
|
return ShiftUI.Screen.PrimaryScreen.Bounds.Width;
|
|
});
|
|
mod.screen_get_height = new Func<int>(() =>
|
|
{
|
|
return ShiftUI.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<Widget, 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<Widget, string>((ctrl, funcname) => RegClick(ctrl, funcname));
|
|
mod.add_widget_to_window = new Action<Form, Widget>((win, ctrl) => AddCtrl(win, ctrl));
|
|
mod.open_file = new Action<string, string>((filters, function) => OpenFile(filters, function));
|
|
mod.panel_add_widget = new Action<Widget, Widget>((ctrl, parent) =>
|
|
{
|
|
try {
|
|
var p = (Panel)parent;
|
|
p.Widgets.Add(ctrl);
|
|
} catch(Exception ex)
|
|
{
|
|
Errors.Add(ex.Message);
|
|
}
|
|
});
|
|
mod.flow_add_widget = new Action<Widget, Widget>((ctrl, parent) =>
|
|
{
|
|
try
|
|
{
|
|
var p = (FlowLayoutPanel)parent;
|
|
p.Widgets.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, ShiftUI.Timer>((interval) =>
|
|
{
|
|
var t = new ShiftUI.Timer();
|
|
t.Interval = interval;
|
|
return t;
|
|
});
|
|
mod.timer_on_tick = new Action<ShiftUI.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<Widget>((ctrl) => AddToDesktop(ctrl));
|
|
mod.set_dock = new Action<Widget, 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<Widget, 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">Widget to assign the event to.</param>
|
|
/// <param name="action">Function to call on keydown.</param>
|
|
public void RegKeyDown(Widget 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(Widget 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(Widget ctrl)
|
|
{
|
|
API.CurrentSession.Widgets.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">Widget type.</param>
|
|
/// <param name="text">Widget 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 Widget ConstructWidget(string type, string text, int x, int y, int width, int height, bool darkmode)
|
|
{
|
|
var ctrl = new Widget();
|
|
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.Standard;
|
|
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 = (Widget)btn;
|
|
break;
|
|
case "webview":
|
|
var g = new Gecko.GeckoWebBrowser();
|
|
g.NoDefaultContextMenu = true;
|
|
ctrl = g.ToWidget();
|
|
//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 Widget();
|
|
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">Widget to add.</param>
|
|
public void AddCtrl(Form win, Widget ctrl)
|
|
{
|
|
|
|
List<WindowBorder> borders = new List<WindowBorder>();
|
|
foreach(Widget c in win.Widgets)
|
|
{
|
|
if(c.Name == "api_brdr")
|
|
{
|
|
var b = (WindowBorder)c;
|
|
b.pgcontents.Widgets.Add(ctrl);
|
|
ctrl.BringToFront();
|
|
borders.Add(b);
|
|
}
|
|
}
|
|
if(borders.Count == 0)
|
|
{
|
|
win.Widgets.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(Widget 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();
|
|
}
|
|
}
|
|
|
|
public static class Extensions
|
|
{
|
|
/// <summary>
|
|
/// Attempts to convert a Windows Forms control to a ShiftUI widget
|
|
/// using JSON.NET.
|
|
///
|
|
/// This may fail due to architecture differences in the WinForms and
|
|
/// ShiftUI code.
|
|
///
|
|
/// Exceptions:
|
|
/// - JsonSerializationException: Occurs when a control has some
|
|
/// data that JSON.NET can't serialize.
|
|
/// </summary>
|
|
/// <param name="ctrl">The Windows Forms control to convert</param>
|
|
/// <returns>The converted widget.</returns>
|
|
public static Widget ToWidget(this System.Windows.Forms.Control ctrl)
|
|
{
|
|
string json = JsonConvert.SerializeObject(ctrl);
|
|
json = json.Replace("Control", "Widget");
|
|
return JsonConvert.DeserializeObject<Widget>(json);
|
|
}
|
|
}
|
|
}
|