mirror of
https://github.com/Leonmmcoset/CMLeonOS.git
synced 2026-03-03 15:30:27 +00:00
Compare commits
5 Commits
f0a9223520
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c514df84e | ||
|
|
29a68b4ca9 | ||
|
|
5c952e7861 | ||
|
|
6a9d39abd9 | ||
|
|
1f385ac18a |
61
BootMenu.cs
61
BootMenu.cs
@@ -3,6 +3,7 @@ using Sys = Cosmos.System;
|
||||
using Cosmos.HAL;
|
||||
using Cosmos.Core;
|
||||
using System.Threading;
|
||||
using System.IO;
|
||||
|
||||
namespace CMLeonOS
|
||||
{
|
||||
@@ -16,6 +17,10 @@ namespace CMLeonOS
|
||||
|
||||
internal static class BootMenu
|
||||
{
|
||||
private static bool UserDatExists()
|
||||
{
|
||||
return File.Exists(@"0:\system\user.dat");
|
||||
}
|
||||
private static void PrintOption(string text, bool selected)
|
||||
{
|
||||
Console.SetCursorPosition(1, Console.GetCursorPosition().Top);
|
||||
@@ -35,8 +40,6 @@ namespace CMLeonOS
|
||||
|
||||
uint mem = Cosmos.Core.CPU.GetAmountOfRAM();
|
||||
Console.WriteLine($"{Version.DisplayVersion} [{mem} MB memory]");
|
||||
// 这里老显示 unknown,谁知道为啥
|
||||
// Console.WriteLine($"Git Commit: {Version.GitCommit}");
|
||||
Console.WriteLine($"Build Time: {GetBuildTime()}");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($"Auto-select in {remainingTime} seconds...");
|
||||
@@ -44,10 +47,16 @@ namespace CMLeonOS
|
||||
Console.WriteLine("Select an option:");
|
||||
Console.WriteLine();
|
||||
|
||||
PrintOption("Normal Boot", selIdx == 0);
|
||||
PrintOption("GUI Boot", selIdx == 1);
|
||||
PrintOption("Reboot", selIdx == 2);
|
||||
PrintOption("Shutdown", selIdx == 3);
|
||||
bool userDatExists = UserDatExists();
|
||||
int optionIndex = 0;
|
||||
|
||||
PrintOption("Normal Boot", selIdx == optionIndex++);
|
||||
if (userDatExists)
|
||||
{
|
||||
PrintOption("GUI Boot", selIdx == optionIndex++);
|
||||
}
|
||||
PrintOption("Reboot", selIdx == optionIndex++);
|
||||
PrintOption("Shutdown", selIdx == optionIndex++);
|
||||
}
|
||||
|
||||
private static BootMenuAction Confirm(int selIdx)
|
||||
@@ -61,21 +70,29 @@ namespace CMLeonOS
|
||||
|
||||
Console.CursorVisible = true;
|
||||
|
||||
switch (selIdx)
|
||||
bool userDatExists = UserDatExists();
|
||||
int optionIndex = 0;
|
||||
|
||||
if (selIdx == optionIndex++)
|
||||
{
|
||||
case 0:
|
||||
return BootMenuAction.NormalBoot;
|
||||
case 1:
|
||||
return BootMenuAction.GuiBoot;
|
||||
case 2:
|
||||
Sys.Power.Reboot();
|
||||
return BootMenuAction.Reboot;
|
||||
case 3:
|
||||
Sys.Power.Shutdown();
|
||||
return BootMenuAction.Shutdown;
|
||||
default:
|
||||
return BootMenuAction.NormalBoot;
|
||||
return BootMenuAction.NormalBoot;
|
||||
}
|
||||
if (userDatExists && selIdx == optionIndex++)
|
||||
{
|
||||
return BootMenuAction.GuiBoot;
|
||||
}
|
||||
if (selIdx == optionIndex++)
|
||||
{
|
||||
Sys.Power.Reboot();
|
||||
return BootMenuAction.Reboot;
|
||||
}
|
||||
if (selIdx == optionIndex++)
|
||||
{
|
||||
Sys.Power.Shutdown();
|
||||
return BootMenuAction.Shutdown;
|
||||
}
|
||||
|
||||
return BootMenuAction.NormalBoot;
|
||||
}
|
||||
|
||||
public static BootMenuAction Show()
|
||||
@@ -131,12 +148,14 @@ namespace CMLeonOS
|
||||
}
|
||||
}
|
||||
|
||||
int maxOptionIndex = UserDatExists() ? 3 : 2;
|
||||
|
||||
if (selIdx < 0)
|
||||
{
|
||||
selIdx = 3;
|
||||
selIdx = maxOptionIndex;
|
||||
}
|
||||
|
||||
if (selIdx > 3)
|
||||
if (selIdx > maxOptionIndex)
|
||||
{
|
||||
selIdx = 0;
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
2026-03-01 17:02:21
|
||||
2026-03-03 21:19:17
|
||||
@@ -1 +1 @@
|
||||
545f40c
|
||||
29a68b4
|
||||
@@ -120,6 +120,7 @@ namespace CMLeonOS.Gui
|
||||
RegisterApp(new AppMetadata("Stopwatch", () => { return new Stopwatch(); }, Icons.Icon_Stopwatch, Color.FromArgb(168, 55, 47)));
|
||||
RegisterApp(new AppMetadata("Paint", () => { return new Apps.Paint.Paint(); }, Icons.Icon_Paint, Color.FromArgb(0, 115, 186)));
|
||||
RegisterApp(new AppMetadata("Memory Statistics", () => { return new Apps.MemoryStatistics(); }, Icons.Icon_MemoryStatistics, Color.FromArgb(25, 25, 25)));
|
||||
RegisterApp(new AppMetadata("CodeStudio", () => { return new Apps.CodeStudio.CodeStudio(); }, Icons.Icon_CodeStudio, Color.FromArgb(14, 59, 76)));
|
||||
|
||||
Logger.Logger.Instance.Info("AppManager", $"{AppMetadatas.Count} apps were registered.");
|
||||
|
||||
|
||||
50
Gui/Apps/CodeStudio/CodeEditor.cs
Normal file
50
Gui/Apps/CodeStudio/CodeEditor.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using CMLeonOS.Gui.UILib;
|
||||
using Cosmos.System.Graphics;
|
||||
using System.Drawing;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace CMLeonOS.Gui.Apps.CodeStudio
|
||||
{
|
||||
internal class CodeEditor : TextBox
|
||||
{
|
||||
private bool enableSyntaxHighlighting = false;
|
||||
private string fileExtension = "";
|
||||
|
||||
public CodeEditor(Window parent, int x, int y, int width, int height) : base(parent, x, y, width, height)
|
||||
{
|
||||
}
|
||||
|
||||
internal void SetSyntaxHighlighting(bool enable, string extension = "")
|
||||
{
|
||||
enableSyntaxHighlighting = enable;
|
||||
fileExtension = extension.ToLower();
|
||||
MarkAllLines();
|
||||
Render();
|
||||
}
|
||||
|
||||
internal override void RenderLine(int lineIndex, string lineText, int lineY, int xOffset)
|
||||
{
|
||||
if (enableSyntaxHighlighting && fileExtension == ".lua")
|
||||
{
|
||||
var tokens = LuaSyntaxHighlighter.HighlightLine(lineText);
|
||||
int currentXOffset = xOffset;
|
||||
|
||||
foreach (var token in tokens)
|
||||
{
|
||||
if (currentXOffset + token.Text.Length * 8 > 0 && currentXOffset < Width)
|
||||
{
|
||||
DrawString(token.Text, token.Color, currentXOffset, lineY);
|
||||
}
|
||||
currentXOffset += token.Text.Length * 8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
base.RenderLine(lineIndex, lineText, lineY, xOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
47
Gui/Apps/CodeStudio/CodeStudio.cs
Normal file
47
Gui/Apps/CodeStudio/CodeStudio.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using CMLeonOS;
|
||||
using CMLeonOS.Gui.UILib;
|
||||
using System.Drawing;
|
||||
using Cosmos.System.Graphics;
|
||||
|
||||
namespace CMLeonOS.Gui.Apps.CodeStudio
|
||||
{
|
||||
internal class CodeStudio : Process
|
||||
{
|
||||
internal CodeStudio() : base("CodeStudio", ProcessType.Application) { }
|
||||
|
||||
Window splash;
|
||||
|
||||
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
|
||||
|
||||
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.CodeStudio.Splash.bmp")]
|
||||
private static byte[] _splashBytes;
|
||||
private static Bitmap splashBitmap = new Bitmap(_splashBytes);
|
||||
|
||||
private Ide ide;
|
||||
|
||||
private bool ideCreated = false;
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
base.Start();
|
||||
splash = new Window(this, 372, 250, 535, 300);
|
||||
wm.AddWindow(splash);
|
||||
|
||||
splash.DrawImage(splashBitmap, 0, 0);
|
||||
//splash.DrawString("Starting...", Color.White, 20, splash.Height - 16 - 20);
|
||||
|
||||
wm.Update(splash);
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
if (!ideCreated)
|
||||
{
|
||||
ide = new Ide(this, wm);
|
||||
ide.Start();
|
||||
wm.RemoveWindow(splash);
|
||||
ideCreated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
320
Gui/Apps/CodeStudio/Ide.cs
Normal file
320
Gui/Apps/CodeStudio/Ide.cs
Normal file
@@ -0,0 +1,320 @@
|
||||
using CMLeonOS;
|
||||
using CMLeonOS.Gui.UILib;
|
||||
using Cosmos.System.Graphics;
|
||||
using System.Drawing;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UniLua;
|
||||
|
||||
namespace CMLeonOS.Gui.Apps.CodeStudio
|
||||
{
|
||||
internal class Ide
|
||||
{
|
||||
internal Ide(Process process, WindowManager wm)
|
||||
{
|
||||
this.process = process;
|
||||
this.wm = wm;
|
||||
}
|
||||
|
||||
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.CodeStudio.Run.bmp")]
|
||||
private static byte[] _runBytes;
|
||||
private static Bitmap runBitmap = new Bitmap(_runBytes);
|
||||
|
||||
Process process;
|
||||
|
||||
WindowManager wm;
|
||||
|
||||
AppWindow mainWindow;
|
||||
|
||||
Button runButton;
|
||||
|
||||
CodeEditor editor;
|
||||
|
||||
TextBox problems;
|
||||
|
||||
TextBox output;
|
||||
|
||||
FileBrowser fileBrowser;
|
||||
|
||||
private const int headersHeight = 24;
|
||||
private const int problemsHeight = 128;
|
||||
private const int outputHeight = 128;
|
||||
|
||||
private string? path = null;
|
||||
|
||||
private bool modified = false;
|
||||
|
||||
private void TextChanged()
|
||||
{
|
||||
modified = true;
|
||||
|
||||
UpdateTitle();
|
||||
}
|
||||
|
||||
private static class Theme
|
||||
{
|
||||
internal static Color Background = Color.FromArgb(68, 76, 84);
|
||||
internal static Color CodeBackground = Color.FromArgb(41, 46, 51);
|
||||
}
|
||||
|
||||
private void UpdateTitle()
|
||||
{
|
||||
if (path == null)
|
||||
{
|
||||
mainWindow.Title = "Untitled - Lua CodeStudio";
|
||||
return;
|
||||
}
|
||||
|
||||
if (modified)
|
||||
{
|
||||
mainWindow.Title = $"{Path.GetFileName(path)}* - Lua CodeStudio";
|
||||
}
|
||||
else
|
||||
{
|
||||
mainWindow.Title = $"{Path.GetFileName(path)} - Lua CodeStudio";
|
||||
}
|
||||
}
|
||||
|
||||
internal void Open(string newPath, bool readFile = true)
|
||||
{
|
||||
if (newPath == null) return;
|
||||
|
||||
if (readFile && !File.Exists(newPath))
|
||||
{
|
||||
MessageBox messageBox = new MessageBox(process, "Lua CodeStudio", $"No such file '{Path.GetFileName(newPath)}'.");
|
||||
messageBox.Show();
|
||||
}
|
||||
|
||||
path = newPath;
|
||||
|
||||
if (readFile)
|
||||
{
|
||||
editor.Text = File.ReadAllText(path);
|
||||
|
||||
string extension = Path.GetExtension(path).ToLower();
|
||||
editor.SetSyntaxHighlighting(extension == ".lua", extension);
|
||||
|
||||
editor.MarkAllLines();
|
||||
editor.Render();
|
||||
|
||||
modified = false;
|
||||
}
|
||||
|
||||
UpdateTitle();
|
||||
}
|
||||
|
||||
private void OpenFilePrompt()
|
||||
{
|
||||
fileBrowser = new FileBrowser(process, wm, (string selectedPath) =>
|
||||
{
|
||||
if (selectedPath != null)
|
||||
{
|
||||
Open(selectedPath);
|
||||
}
|
||||
});
|
||||
fileBrowser.Show();
|
||||
}
|
||||
|
||||
private void SaveAsPrompt()
|
||||
{
|
||||
fileBrowser = new FileBrowser(process, wm, (string selectedPath) =>
|
||||
{
|
||||
if (selectedPath != null)
|
||||
{
|
||||
path = selectedPath;
|
||||
Save();
|
||||
}
|
||||
}, selectDirectoryOnly: true);
|
||||
fileBrowser.Show();
|
||||
}
|
||||
|
||||
private void Save()
|
||||
{
|
||||
if (path == null)
|
||||
{
|
||||
SaveAsPrompt();
|
||||
return;
|
||||
}
|
||||
|
||||
File.WriteAllText(path, editor.Text);
|
||||
|
||||
modified = false;
|
||||
UpdateTitle();
|
||||
}
|
||||
|
||||
private void RunClicked(int x, int y)
|
||||
{
|
||||
try
|
||||
{
|
||||
output.Text = "";
|
||||
|
||||
ILuaState lua = LuaAPI.NewState();
|
||||
lua.L_OpenLibs();
|
||||
|
||||
lua.PushCSharpFunction(L =>
|
||||
{
|
||||
int n = L.GetTop();
|
||||
string result = "";
|
||||
for (int i = 1; i <= n; i++)
|
||||
{
|
||||
if (i > 1) result += "\t";
|
||||
LuaType type = L.Type(i);
|
||||
if (type == LuaType.LUA_TSTRING)
|
||||
{
|
||||
result += L.ToString(i);
|
||||
}
|
||||
else if (type == LuaType.LUA_TBOOLEAN)
|
||||
{
|
||||
result += L.ToBoolean(i) ? "true" : "false";
|
||||
}
|
||||
else if (type == LuaType.LUA_TNUMBER)
|
||||
{
|
||||
result += L.ToNumber(i).ToString();
|
||||
}
|
||||
else if (type == LuaType.LUA_TNIL)
|
||||
{
|
||||
result += "nil";
|
||||
}
|
||||
}
|
||||
output.Text += result + "\n";
|
||||
return 0;
|
||||
});
|
||||
lua.SetGlobal("print");
|
||||
|
||||
UniLua.ThreadStatus loadResult = lua.L_LoadString(editor.Text);
|
||||
|
||||
if (loadResult == UniLua.ThreadStatus.LUA_OK)
|
||||
{
|
||||
UniLua.ThreadStatus callResult = lua.PCall(0, 0, 0);
|
||||
|
||||
if (callResult == UniLua.ThreadStatus.LUA_OK)
|
||||
{
|
||||
problems.Foreground = Color.LimeGreen;
|
||||
problems.Text = "Execution successful";
|
||||
}
|
||||
else
|
||||
{
|
||||
string errorMsg = lua.ToString(-1);
|
||||
problems.Foreground = Color.Pink;
|
||||
problems.Text = $"Script execution error: {errorMsg}";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string errorMsg = lua.ToString(-1);
|
||||
problems.Foreground = Color.Pink;
|
||||
problems.Text = $"Script load error: {errorMsg}";
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
problems.Foreground = Color.Pink;
|
||||
problems.Text = e.Message;
|
||||
}
|
||||
}
|
||||
|
||||
private void Evaluate()
|
||||
{
|
||||
try
|
||||
{
|
||||
ILuaState lua = LuaAPI.NewState();
|
||||
lua.L_OpenLibs();
|
||||
UniLua.ThreadStatus loadResult = lua.L_LoadString(editor.Text);
|
||||
|
||||
if (loadResult == UniLua.ThreadStatus.LUA_OK)
|
||||
{
|
||||
problems.Foreground = Color.LimeGreen;
|
||||
problems.Text = "No syntax errors";
|
||||
}
|
||||
else
|
||||
{
|
||||
string errorMsg = lua.ToString(-1);
|
||||
if (string.IsNullOrWhiteSpace(errorMsg))
|
||||
{
|
||||
problems.Foreground = Color.Pink;
|
||||
problems.Text = "Script load error: Unknown error";
|
||||
}
|
||||
else
|
||||
{
|
||||
problems.Foreground = Color.Pink;
|
||||
problems.Text = $"Script load error: {errorMsg}";
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
problems.Foreground = Color.Pink;
|
||||
problems.Text = e.Message;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Start()
|
||||
{
|
||||
mainWindow = new AppWindow(process, 96, 96, 800, 600);
|
||||
mainWindow.Clear(Theme.Background);
|
||||
mainWindow.Closing = process.TryStop;
|
||||
UpdateTitle();
|
||||
wm.AddWindow(mainWindow);
|
||||
|
||||
runButton = new Button(mainWindow, 0, 0, 60, headersHeight);
|
||||
runButton.Background = Theme.Background;
|
||||
runButton.Border = Theme.Background;
|
||||
runButton.Foreground = Color.White;
|
||||
runButton.Text = "Run";
|
||||
runButton.Image = runBitmap;
|
||||
runButton.ImageLocation = Button.ButtonImageLocation.Left;
|
||||
runButton.OnClick = RunClicked;
|
||||
wm.AddWindow(runButton);
|
||||
|
||||
editor = new CodeEditor(mainWindow, 0, headersHeight, mainWindow.Width, mainWindow.Height - headersHeight - problemsHeight - outputHeight - (headersHeight * 3))
|
||||
{
|
||||
Background = Theme.CodeBackground,
|
||||
Foreground = Color.White,
|
||||
Text = "print(\"Hello World!\")",
|
||||
Changed = TextChanged,
|
||||
MultiLine = true
|
||||
};
|
||||
editor.SetSyntaxHighlighting(true, ".lua");
|
||||
wm.AddWindow(editor);
|
||||
|
||||
problems = new TextBox(mainWindow, 0, headersHeight + editor.Height + headersHeight, mainWindow.Width, problemsHeight + (headersHeight * 2))
|
||||
{
|
||||
Background = Theme.CodeBackground,
|
||||
Foreground = Color.Gray,
|
||||
Text = "Click Evaluate to check your program for syntax errors.",
|
||||
ReadOnly = true,
|
||||
MultiLine = true
|
||||
};
|
||||
wm.AddWindow(problems);
|
||||
|
||||
mainWindow.DrawString("Problems", Color.White, 0, headersHeight + editor.Height);
|
||||
|
||||
output = new TextBox(mainWindow, 0, headersHeight + editor.Height + problemsHeight + (headersHeight * 2), mainWindow.Width, outputHeight + (headersHeight * 2))
|
||||
{
|
||||
Background = Theme.CodeBackground,
|
||||
Foreground = Color.White,
|
||||
Text = "Output will appear here...",
|
||||
ReadOnly = true,
|
||||
MultiLine = true
|
||||
};
|
||||
wm.AddWindow(output);
|
||||
|
||||
mainWindow.DrawString("Output", Color.White, 0, headersHeight + editor.Height + problemsHeight + headersHeight);
|
||||
|
||||
var shortcutBar = new ShortcutBar(mainWindow, runButton.Width, 0, mainWindow.Width - runButton.Width, headersHeight)
|
||||
{
|
||||
Background = Theme.Background,
|
||||
Foreground = Color.White
|
||||
};
|
||||
shortcutBar.Cells.Add(new ShortcutBarCell("Open", OpenFilePrompt));
|
||||
shortcutBar.Cells.Add(new ShortcutBarCell("Save", Save));
|
||||
shortcutBar.Cells.Add(new ShortcutBarCell("Save As", SaveAsPrompt));
|
||||
shortcutBar.Cells.Add(new ShortcutBarCell("Evaluate", Evaluate));
|
||||
shortcutBar.Render();
|
||||
wm.AddWindow(shortcutBar);
|
||||
|
||||
wm.Update(mainWindow);
|
||||
}
|
||||
}
|
||||
}
|
||||
180
Gui/Apps/CodeStudio/LuaSyntaxHighlighter.cs
Normal file
180
Gui/Apps/CodeStudio/LuaSyntaxHighlighter.cs
Normal file
@@ -0,0 +1,180 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
||||
namespace CMLeonOS.Gui.Apps.CodeStudio
|
||||
{
|
||||
internal static class LuaSyntaxHighlighter
|
||||
{
|
||||
private static readonly List<string> Keywords = new List<string>
|
||||
{
|
||||
"and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while",
|
||||
"goto", "self"
|
||||
};
|
||||
|
||||
private static readonly List<string> Builtins = new List<string>
|
||||
{
|
||||
"print", "type", "tostring", "tonumber", "ipairs", "pairs", "table", "string", "math", "io", "os", "coroutine", "debug", "package", "utf8", "bit32",
|
||||
"assert", "collectgarbage", "dofile", "error", "getmetatable", "load", "loadfile", "next", "pcall", "rawequal", "rawget", "rawlen", "rawset", "require", "select", "setmetatable", "xpcall",
|
||||
"byte", "char", "dump", "find", "format", "gmatch", "gsub", "len", "lower", "match", "rep", "reverse", "sub", "upper",
|
||||
"abs", "acos", "asin", "atan", "atan2", "ceil", "cos", "cosh", "deg", "exp", "floor", "fmod", "frexp", "huge", "ldexp", "log", "log10", "max", "min", "modf", "pi", "pow", "rad", "random", "randomseed", "sin", "sinh", "sqrt", "tan", "tanh",
|
||||
"close", "flush", "input", "lines", "open", "output", "popen", "read", "tmpfile", "type", "write",
|
||||
"clock", "date", "difftime", "execute", "exit", "getenv", "remove", "rename", "setlocale", "time", "tmpname",
|
||||
"create", "resume", "running", "status", "wrap", "yield",
|
||||
"concat", "insert", "maxn", "remove", "sort",
|
||||
"getinfo", "getlocal", "getmetatable", "setmetatable", "setlocal", "traceback",
|
||||
"loadlib", "seeall", "loaded", "loaders", "path", "cpath", "preload"
|
||||
};
|
||||
|
||||
private static readonly List<string> Operators = new List<string>
|
||||
{
|
||||
"+", "-", "*", "/", "%", "^", "#", "==", "~=", "<=", ">=", "<", ">", "=", "(", ")", "[", "]", "{", "}", ";", ":", ",", "..", "...", "."
|
||||
};
|
||||
|
||||
internal static class Colors
|
||||
{
|
||||
internal static Color Keyword = Color.FromArgb(255, 0, 128);
|
||||
internal static Color Builtin = Color.FromArgb(0, 128, 0);
|
||||
internal static Color String = Color.FromArgb(163, 21, 21);
|
||||
internal static Color Number = Color.FromArgb(0, 0, 255);
|
||||
internal static Color Comment = Color.FromArgb(128, 128, 128);
|
||||
internal static Color Operator = Color.FromArgb(255, 128, 0);
|
||||
internal static Color Default = Color.White;
|
||||
}
|
||||
|
||||
internal class HighlightedToken
|
||||
{
|
||||
internal string Text;
|
||||
internal Color Color;
|
||||
|
||||
internal HighlightedToken(string text, Color color)
|
||||
{
|
||||
Text = text;
|
||||
Color = color;
|
||||
}
|
||||
}
|
||||
|
||||
internal static List<HighlightedToken> HighlightLine(string line)
|
||||
{
|
||||
var tokens = new List<HighlightedToken>();
|
||||
int i = 0;
|
||||
|
||||
while (i < line.Length)
|
||||
{
|
||||
char c = line[i];
|
||||
|
||||
if (char.IsWhiteSpace(c))
|
||||
{
|
||||
int start = i;
|
||||
while (i < line.Length && char.IsWhiteSpace(line[i]))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
tokens.Add(new HighlightedToken(line.Substring(start, i - start), Colors.Default));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i + 3 < line.Length && line.Substring(i, 4) == "--[[")
|
||||
{
|
||||
int start = i;
|
||||
i += 4;
|
||||
|
||||
int endPos = line.IndexOf("--]]", i);
|
||||
if (endPos != -1)
|
||||
{
|
||||
i = endPos + 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = line.Length;
|
||||
}
|
||||
|
||||
tokens.Add(new HighlightedToken(line.Substring(start, i - start), Colors.Comment));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '-' && i + 1 < line.Length && line[i + 1] == '-')
|
||||
{
|
||||
int start = i;
|
||||
i += 2;
|
||||
while (i < line.Length && line[i] != '\n')
|
||||
{
|
||||
i++;
|
||||
}
|
||||
tokens.Add(new HighlightedToken(line.Substring(start, i - start), Colors.Comment));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '"' || c == '\'')
|
||||
{
|
||||
int start = i;
|
||||
i++;
|
||||
while (i < line.Length && line[i] != c)
|
||||
{
|
||||
if (line[i] == '\\' && i + 1 < line.Length)
|
||||
{
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (i < line.Length)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
tokens.Add(new HighlightedToken(line.Substring(start, i - start), Colors.String));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (char.IsDigit(c) || (c == '0' && i + 1 < line.Length && (line[i + 1] == 'x' || line[i + 1] == 'X')))
|
||||
{
|
||||
int start = i;
|
||||
i++;
|
||||
while (i < line.Length && (char.IsDigit(line[i]) || line[i] == '.' || line[i] == 'e' || line[i] == 'E' || line[i] == 'x' || line[i] == 'X' || line[i] == 'a' || line[i] == 'A' || line[i] == 'b' || line[i] == 'B' || line[i] == 'c' || line[i] == 'C' || line[i] == 'd' || line[i] == 'D' || line[i] == 'f' || line[i] == 'F'))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
tokens.Add(new HighlightedToken(line.Substring(start, i - start), Colors.Number));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (char.IsLetter(c) || c == '_')
|
||||
{
|
||||
int start = i;
|
||||
while (i < line.Length && (char.IsLetterOrDigit(line[i]) || line[i] == '_'))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
string word = line.Substring(start, i - start);
|
||||
|
||||
if (Keywords.Contains(word))
|
||||
{
|
||||
tokens.Add(new HighlightedToken(word, Colors.Keyword));
|
||||
}
|
||||
else if (Builtins.Contains(word))
|
||||
{
|
||||
tokens.Add(new HighlightedToken(word, Colors.Builtin));
|
||||
}
|
||||
else
|
||||
{
|
||||
tokens.Add(new HighlightedToken(word, Colors.Default));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Operators.Contains(c.ToString()))
|
||||
{
|
||||
tokens.Add(new HighlightedToken(c.ToString(), Colors.Operator));
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
tokens.Add(new HighlightedToken(c.ToString(), Colors.Default));
|
||||
i++;
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,6 @@ namespace CMLeonOS.Gui.Apps
|
||||
("CMLeonOS (0:)", @"0:\"),
|
||||
("My Home", @$"0:\user\{UserSystem.CurrentLoggedInUser.Username}"),
|
||||
("Users", @"0:\user"),
|
||||
("etc", @"0:\etc"),
|
||||
};
|
||||
|
||||
private Bitmap GetFileIcon(string path)
|
||||
|
||||
@@ -30,9 +30,8 @@ namespace CMLeonOS.Gui.Apps
|
||||
window.DrawString($"Memory: {Cosmos.Core.CPU.GetAmountOfRAM()} MB", Color.Black, 12, 80);
|
||||
|
||||
window.DrawString("Credits", Color.DarkBlue, 12, 108);
|
||||
window.DrawString("Cosmos Team - OS tooling", Color.Black, 12, 132);
|
||||
window.DrawString("Microsoft - .NET Runtime", Color.Black, 12, 156);
|
||||
window.DrawString("Google Fonts - Font", Color.Black, 12, 180);
|
||||
window.DrawString("Microsoft - .NET Runtime", Color.Black, 12, 132);
|
||||
window.DrawString("Google Fonts - Font", Color.Black, 12, 156);
|
||||
|
||||
Button button = new Button(window, window.Width - 80 - 12, window.Height - 20 - 12, 80, 20);
|
||||
button.Text = "OK";
|
||||
|
||||
@@ -19,13 +19,13 @@ namespace CMLeonOS.Gui.Apps
|
||||
AppWindow window;
|
||||
|
||||
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
|
||||
|
||||
SettingsService settingsService = ProcessManager.GetProcess<SettingsService>();
|
||||
|
||||
TextBox textBox;
|
||||
|
||||
ShortcutBar shortcutBar;
|
||||
|
||||
FileBrowser fileBrowser;
|
||||
|
||||
private string? path = null;
|
||||
|
||||
private bool modified = false;
|
||||
@@ -70,12 +70,6 @@ namespace CMLeonOS.Gui.Apps
|
||||
{
|
||||
if (newPath == null) return;
|
||||
|
||||
if (!FileSecurity.CanAccess(path))
|
||||
{
|
||||
MessageBox messageBox = new MessageBox(this, "Notepad", $"Access to '{Path.GetFileName(newPath)}' is unauthorised.");
|
||||
messageBox.Show();
|
||||
}
|
||||
|
||||
if (readFile && !File.Exists(newPath))
|
||||
{
|
||||
MessageBox messageBox = new MessageBox(this, "Notepad", $"No such file '{Path.GetFileName(newPath)}'.");
|
||||
@@ -99,35 +93,27 @@ namespace CMLeonOS.Gui.Apps
|
||||
|
||||
private void OpenFilePrompt()
|
||||
{
|
||||
PromptBox prompt = new PromptBox(this, "Open File", "Enter the path to open.", "Path", (string newPath) =>
|
||||
fileBrowser = new FileBrowser(this, wm, (string selectedPath) =>
|
||||
{
|
||||
if (!newPath.Contains(':'))
|
||||
if (selectedPath != null)
|
||||
{
|
||||
newPath = $@"0:\{newPath}";
|
||||
Open(selectedPath);
|
||||
}
|
||||
Open(newPath);
|
||||
});
|
||||
prompt.Show();
|
||||
fileBrowser.Show();
|
||||
}
|
||||
|
||||
private void SaveAsPrompt()
|
||||
{
|
||||
PromptBox prompt = new PromptBox(this, "Save As", "Enter the path to save to.", "Path", (string newPath) =>
|
||||
fileBrowser = new FileBrowser(this, wm, (string selectedPath) =>
|
||||
{
|
||||
if (!newPath.Contains(':'))
|
||||
{
|
||||
newPath = $@"0:\{newPath}";
|
||||
}
|
||||
|
||||
Open(newPath, readFile: false);
|
||||
|
||||
// Check if open succeeded.
|
||||
if (path != null)
|
||||
if (selectedPath != null)
|
||||
{
|
||||
path = selectedPath;
|
||||
Save();
|
||||
}
|
||||
});
|
||||
prompt.Show();
|
||||
}, selectDirectoryOnly: true);
|
||||
fileBrowser.Show();
|
||||
}
|
||||
|
||||
private void Save()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Cosmos.System.Graphics;
|
||||
using CMLeonOS;
|
||||
using CMLeonOS.Gui.UILib;
|
||||
using CMLeonOS.Settings;
|
||||
|
||||
using System.Drawing;
|
||||
|
||||
@@ -16,8 +17,6 @@ namespace CMLeonOS.Gui.Apps
|
||||
|
||||
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
|
||||
|
||||
SettingsService settingsService = ProcessManager.GetProcess<SettingsService>();
|
||||
|
||||
private static class Icons
|
||||
{
|
||||
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Settings.User.bmp")]
|
||||
@@ -59,22 +58,22 @@ namespace CMLeonOS.Gui.Apps
|
||||
|
||||
private void LeftStartButtonChanged(bool @checked)
|
||||
{
|
||||
settingsService.LeftHandStartButton = @checked;
|
||||
SettingsManager.GUI_LeftHandStartButton = @checked;
|
||||
}
|
||||
|
||||
private void TwelveHourClockChanged(bool @checked)
|
||||
{
|
||||
settingsService.TwelveHourClock = @checked;
|
||||
SettingsManager.GUI_TwelveHourClock = @checked;
|
||||
}
|
||||
|
||||
private void ShowFpsChanged(bool @checked)
|
||||
{
|
||||
settingsService.ShowFps = @checked;
|
||||
SettingsManager.GUI_ShowFps = @checked;
|
||||
}
|
||||
|
||||
private void MouseSensitivityChanged(float value)
|
||||
{
|
||||
settingsService.MouseSensitivity = value;
|
||||
SettingsManager.GUI_MouseSensitivity = value;
|
||||
}
|
||||
|
||||
private void ShowAppearanceCategory()
|
||||
@@ -90,13 +89,13 @@ namespace CMLeonOS.Gui.Apps
|
||||
|
||||
Switch leftStartButton = new Switch(appearance, 12, 40, 244, 16);
|
||||
leftStartButton.Text = "Left-hand start button";
|
||||
leftStartButton.Checked = settingsService.LeftHandStartButton;
|
||||
leftStartButton.Checked = SettingsManager.GUI_LeftHandStartButton;
|
||||
leftStartButton.CheckBoxChanged = LeftStartButtonChanged;
|
||||
wm.AddWindow(leftStartButton);
|
||||
|
||||
Switch showFps = new Switch(appearance, 12, 68, 244, 16);
|
||||
showFps.Text = "Show frames per second";
|
||||
showFps.Checked = settingsService.ShowFps;
|
||||
showFps.Checked = SettingsManager.GUI_ShowFps;
|
||||
showFps.CheckBoxChanged = ShowFpsChanged;
|
||||
wm.AddWindow(showFps);
|
||||
|
||||
@@ -116,7 +115,7 @@ namespace CMLeonOS.Gui.Apps
|
||||
|
||||
Switch twelveHourClock = new Switch(dateTime, 12, 40, 244, 16);
|
||||
twelveHourClock.Text = "12-hour clock";
|
||||
twelveHourClock.Checked = settingsService.TwelveHourClock;
|
||||
twelveHourClock.Checked = SettingsManager.GUI_TwelveHourClock;
|
||||
twelveHourClock.CheckBoxChanged = TwelveHourClockChanged;
|
||||
wm.AddWindow(twelveHourClock);
|
||||
|
||||
@@ -152,7 +151,7 @@ namespace CMLeonOS.Gui.Apps
|
||||
{
|
||||
Mode mode = wm.AvailableModes[i];
|
||||
resolutionsTable.Cells.Add(new TableCell($"{mode.Width}x{mode.Height}"));
|
||||
if (mode.Equals(settingsService.Mode))
|
||||
if (mode.Width == SettingsManager.GUI_ScreenWidth && mode.Height == SettingsManager.GUI_ScreenHeight)
|
||||
{
|
||||
resolutionsTable.SelectedCellIndex = i;
|
||||
}
|
||||
@@ -161,8 +160,8 @@ namespace CMLeonOS.Gui.Apps
|
||||
resolutionsTable.TableCellSelected = (int index) =>
|
||||
{
|
||||
Mode mode = wm.AvailableModes[index];
|
||||
settingsService.Mode = mode;
|
||||
settingsService.Flush();
|
||||
SettingsManager.GUI_ScreenWidth = (int)mode.Width;
|
||||
SettingsManager.GUI_ScreenHeight = (int)mode.Height;
|
||||
|
||||
MessageBox messageBox = new MessageBox(this, "Restart Required", "Restart your PC to apply changes.");
|
||||
messageBox.Show();
|
||||
@@ -242,7 +241,7 @@ namespace CMLeonOS.Gui.Apps
|
||||
|
||||
mouse.DrawString("Mouse sensitivity", Color.Gray, 12, 40);
|
||||
|
||||
RangeSlider mouseSensitivity = new RangeSlider(mouse, 12, 68, 244, 30, min: 0.25f, value: settingsService.MouseSensitivity, max: 2f);
|
||||
RangeSlider mouseSensitivity = new RangeSlider(mouse, 12, 68, 244, 30, min: 0.25f, value: SettingsManager.GUI_MouseSensitivity, max: 2f);
|
||||
mouseSensitivity.Changed = MouseSensitivityChanged;
|
||||
wm.AddWindow(mouseSensitivity);
|
||||
|
||||
@@ -254,7 +253,11 @@ namespace CMLeonOS.Gui.Apps
|
||||
{
|
||||
base.Start();
|
||||
window = new AppWindow(this, 256, 256, 448, 272);
|
||||
window.Closing = TryStop;
|
||||
window.Closing = () =>
|
||||
{
|
||||
SettingsManager.FlushSettings();
|
||||
TryStop();
|
||||
};
|
||||
window.Icon = AppManager.GetAppMetadata("Settings").Icon;
|
||||
wm.AddWindow(window);
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ namespace CMLeonOS.Gui.ShellComponents
|
||||
}
|
||||
|
||||
window = new AppWindow(this, (int)(wm.ScreenWidth / 2 - width / 2), (int)(wm.ScreenHeight / 2 - height / 2), width, height);
|
||||
window.Title = "CMLeonOS Logon";
|
||||
window.Title = "CMLeonOS Login";
|
||||
window.Icon = Images.Icon_Key;
|
||||
window.CanMove = false;
|
||||
window.CanClose = false;
|
||||
|
||||
@@ -3,6 +3,7 @@ using Cosmos.System.Graphics;
|
||||
using CMLeonOS;
|
||||
using CMLeonOS.Gui.UILib;
|
||||
using CMLeonOS.UILib.Animations;
|
||||
using CMLeonOS.Settings;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
@@ -55,13 +56,8 @@ namespace CMLeonOS.Gui.ShellComponents
|
||||
|
||||
internal void UpdateTime()
|
||||
{
|
||||
if (settingsService == null)
|
||||
{
|
||||
settingsService = ProcessManager.GetProcess<SettingsService>();
|
||||
}
|
||||
|
||||
string timeText;
|
||||
if (settingsService.TwelveHourClock)
|
||||
if (SettingsManager.GUI_TwelveHourClock)
|
||||
{
|
||||
timeText = DateTime.Now.ToString("ddd h:mm tt");
|
||||
}
|
||||
@@ -120,6 +116,8 @@ namespace CMLeonOS.Gui.ShellComponents
|
||||
start.OnClick = StartClicked;
|
||||
wm.AddWindow(start);
|
||||
|
||||
SetLeftHandStartButton(SettingsManager.GUI_LeftHandStartButton);
|
||||
|
||||
UpdateTime();
|
||||
|
||||
MovementAnimation animation = new MovementAnimation(window)
|
||||
|
||||
313
Gui/UILib/FileBrowser.cs
Normal file
313
Gui/UILib/FileBrowser.cs
Normal file
@@ -0,0 +1,313 @@
|
||||
using CMLeonOS;
|
||||
using CMLeonOS.Gui.UILib;
|
||||
using Cosmos.System.Graphics;
|
||||
using System.Drawing;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace CMLeonOS.Gui.UILib
|
||||
{
|
||||
internal class FileBrowser
|
||||
{
|
||||
private Process process;
|
||||
private WindowManager wm;
|
||||
private Window window;
|
||||
private Table fileTable;
|
||||
private TextBox pathBox;
|
||||
private TextBox fileNameBox;
|
||||
private Button upButton;
|
||||
private Button selectButton;
|
||||
private Button cancelButton;
|
||||
|
||||
private string currentPath = @"0:\";
|
||||
private string selectedPath = null;
|
||||
private Action<string> onFileSelected;
|
||||
private bool selectDirectoryOnly = false;
|
||||
|
||||
private const int headerHeight = 32;
|
||||
private const int buttonHeight = 28;
|
||||
private const int buttonWidth = 80;
|
||||
private const int fileNameBoxHeight = 24;
|
||||
|
||||
internal FileBrowser(Process process, WindowManager wm, Action<string> onFileSelected, bool selectDirectoryOnly = false)
|
||||
{
|
||||
this.process = process;
|
||||
this.wm = wm;
|
||||
this.onFileSelected = onFileSelected;
|
||||
this.selectDirectoryOnly = selectDirectoryOnly;
|
||||
}
|
||||
|
||||
private static class Icons
|
||||
{
|
||||
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Files.Directory.bmp")]
|
||||
private static byte[] _iconBytes_Directory;
|
||||
internal static Bitmap Icon_Directory = new Bitmap(_iconBytes_Directory);
|
||||
|
||||
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Files.File.bmp")]
|
||||
private static byte[] _iconBytes_File;
|
||||
internal static Bitmap Icon_File = new Bitmap(_iconBytes_File);
|
||||
|
||||
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Files.File_Text.bmp")]
|
||||
private static byte[] _iconBytes_File_Text;
|
||||
internal static Bitmap Icon_File_Text = new Bitmap(_iconBytes_File_Text);
|
||||
|
||||
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Files.Up.bmp")]
|
||||
private static byte[] _iconBytes_Up;
|
||||
internal static Bitmap Icon_Up = new Bitmap(_iconBytes_Up);
|
||||
}
|
||||
|
||||
private Bitmap GetFileIcon(string path)
|
||||
{
|
||||
string extension = Path.GetExtension(path).ToLower();
|
||||
|
||||
return extension switch
|
||||
{
|
||||
".txt" or ".md" or ".log" or ".lua" or ".rs" => Icons.Icon_File_Text,
|
||||
_ => Icons.Icon_File
|
||||
};
|
||||
}
|
||||
|
||||
private void PopulateFileTable()
|
||||
{
|
||||
fileTable.Cells.Clear();
|
||||
fileTable.SelectedCellIndex = -1;
|
||||
|
||||
bool empty = true;
|
||||
|
||||
foreach (string path in Directory.GetDirectories(currentPath))
|
||||
{
|
||||
fileTable.Cells.Add(new TableCell(Icons.Icon_Directory, Path.GetFileName(path), tag: "Directory"));
|
||||
empty = false;
|
||||
}
|
||||
|
||||
foreach (string path in Directory.GetFiles(currentPath))
|
||||
{
|
||||
fileTable.Cells.Add(new TableCell(GetFileIcon(path), Path.GetFileName(path), tag: "File"));
|
||||
empty = false;
|
||||
}
|
||||
|
||||
if (empty)
|
||||
{
|
||||
fileTable.Clear(fileTable.Background);
|
||||
fileTable.DrawString("This folder is empty.", Color.Black, (fileTable.Width / 2) - 80, 12);
|
||||
wm.Update(fileTable);
|
||||
}
|
||||
else
|
||||
{
|
||||
fileTable.Render();
|
||||
}
|
||||
}
|
||||
|
||||
private void PathBoxChanged()
|
||||
{
|
||||
string inputPath = pathBox.Text;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(inputPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!inputPath.Contains(':'))
|
||||
{
|
||||
inputPath = $@"0:\{inputPath}";
|
||||
}
|
||||
|
||||
if (Directory.Exists(inputPath))
|
||||
{
|
||||
currentPath = inputPath;
|
||||
PopulateFileTable();
|
||||
}
|
||||
else if (File.Exists(inputPath))
|
||||
{
|
||||
currentPath = Path.GetDirectoryName(inputPath);
|
||||
PopulateFileTable();
|
||||
}
|
||||
}
|
||||
|
||||
private void PathBoxSubmitted()
|
||||
{
|
||||
string inputPath = pathBox.Text;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(inputPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!inputPath.Contains(':'))
|
||||
{
|
||||
inputPath = $@"0:\{inputPath}";
|
||||
}
|
||||
|
||||
if (File.Exists(inputPath) || (selectDirectoryOnly && Directory.Exists(inputPath)))
|
||||
{
|
||||
selectedPath = inputPath;
|
||||
onFileSelected?.Invoke(selectedPath);
|
||||
Close();
|
||||
}
|
||||
else if (Directory.Exists(inputPath))
|
||||
{
|
||||
currentPath = inputPath;
|
||||
PopulateFileTable();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpClicked(int x, int y)
|
||||
{
|
||||
if (currentPath.Length > 3)
|
||||
{
|
||||
string parentPath = Path.GetDirectoryName(currentPath);
|
||||
if (!string.IsNullOrEmpty(parentPath))
|
||||
{
|
||||
currentPath = @"0:\";
|
||||
}
|
||||
else
|
||||
{
|
||||
currentPath = parentPath;
|
||||
}
|
||||
PopulateFileTable();
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectClicked(int x, int y)
|
||||
{
|
||||
if (fileTable.SelectedCellIndex >= 0)
|
||||
{
|
||||
TableCell selectedCell = fileTable.Cells[fileTable.SelectedCellIndex];
|
||||
string selectedName = selectedCell.Text;
|
||||
string fullPath = Path.Combine(currentPath, selectedName);
|
||||
|
||||
string tag = selectedCell.Tag as string;
|
||||
if (tag == "Directory")
|
||||
{
|
||||
currentPath = fullPath;
|
||||
PopulateFileTable();
|
||||
}
|
||||
else if (tag == "File")
|
||||
{
|
||||
if (selectDirectoryOnly)
|
||||
{
|
||||
string fileName = fileNameBox.Text;
|
||||
if (string.IsNullOrWhiteSpace(fileName))
|
||||
{
|
||||
fileName = selectedName;
|
||||
}
|
||||
selectedPath = Path.Combine(currentPath, fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedPath = fullPath;
|
||||
}
|
||||
onFileSelected?.Invoke(selectedPath);
|
||||
Close();
|
||||
}
|
||||
}
|
||||
else if (selectDirectoryOnly)
|
||||
{
|
||||
string fileName = fileNameBox.Text;
|
||||
if (!string.IsNullOrWhiteSpace(fileName))
|
||||
{
|
||||
selectedPath = Path.Combine(currentPath, fileName);
|
||||
onFileSelected?.Invoke(selectedPath);
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void FileTableSelected(int index)
|
||||
{
|
||||
SelectClicked(0, 0);
|
||||
}
|
||||
|
||||
private void CancelClicked(int x, int y)
|
||||
{
|
||||
selectedPath = null;
|
||||
onFileSelected?.Invoke(null);
|
||||
Close();
|
||||
}
|
||||
|
||||
private void FileTableDoubleClicked(int index)
|
||||
{
|
||||
SelectClicked(0, 0);
|
||||
}
|
||||
|
||||
internal void Show()
|
||||
{
|
||||
window = new Window(process, 100, 100, 500, 400);
|
||||
wm.AddWindow(window);
|
||||
|
||||
window.DrawString(selectDirectoryOnly ? "Save As" : "Open File", Color.DarkBlue, 12, 12);
|
||||
|
||||
pathBox = new TextBox(window, 8, 40, window.Width - 16, 24)
|
||||
{
|
||||
Background = Color.White,
|
||||
Foreground = Color.Black,
|
||||
Text = currentPath,
|
||||
ReadOnly = false
|
||||
};
|
||||
pathBox.Changed = PathBoxChanged;
|
||||
pathBox.Submitted = PathBoxSubmitted;
|
||||
wm.AddWindow(pathBox);
|
||||
|
||||
if (selectDirectoryOnly)
|
||||
{
|
||||
window.DrawString("File name:", Color.Black, 8, 72);
|
||||
|
||||
fileNameBox = new TextBox(window, 8, 96, window.Width - 16, fileNameBoxHeight)
|
||||
{
|
||||
Background = Color.White,
|
||||
Foreground = Color.Black,
|
||||
Text = "",
|
||||
ReadOnly = false
|
||||
};
|
||||
wm.AddWindow(fileNameBox);
|
||||
}
|
||||
|
||||
upButton = new Button(window, 8, selectDirectoryOnly ? 128 : 72, 60, buttonHeight)
|
||||
{
|
||||
Text = "Up",
|
||||
Image = Icons.Icon_Up,
|
||||
ImageLocation = Button.ButtonImageLocation.Left
|
||||
};
|
||||
upButton.OnClick = UpClicked;
|
||||
wm.AddWindow(upButton);
|
||||
|
||||
int tableY = selectDirectoryOnly ? 128 + buttonHeight + 8 : 72 + buttonHeight + 8;
|
||||
int tableHeight = window.Height - tableY - buttonHeight - 8 - buttonHeight - 16;
|
||||
|
||||
fileTable = new Table(window, 8, tableY, window.Width - 16, tableHeight)
|
||||
{
|
||||
AllowDeselection = false
|
||||
};
|
||||
fileTable.TableCellSelected = FileTableSelected;
|
||||
PopulateFileTable();
|
||||
wm.AddWindow(fileTable);
|
||||
|
||||
int buttonY = window.Height - buttonHeight - 8;
|
||||
selectButton = new Button(window, window.Width - buttonWidth - 8, buttonY, buttonWidth, buttonHeight)
|
||||
{
|
||||
Text = selectDirectoryOnly ? "Save" : "Open"
|
||||
};
|
||||
selectButton.OnClick = SelectClicked;
|
||||
wm.AddWindow(selectButton);
|
||||
|
||||
cancelButton = new Button(window, window.Width - buttonWidth * 2 - 16, buttonY, buttonWidth, buttonHeight)
|
||||
{
|
||||
Text = "Cancel"
|
||||
};
|
||||
cancelButton.OnClick = CancelClicked;
|
||||
wm.AddWindow(cancelButton);
|
||||
|
||||
wm.Update(window);
|
||||
}
|
||||
|
||||
internal void Close()
|
||||
{
|
||||
if (window != null)
|
||||
{
|
||||
wm.RemoveWindow(window);
|
||||
window = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,11 @@ namespace CMLeonOS.Gui.UILib
|
||||
internal Action Submitted;
|
||||
internal Action Changed;
|
||||
|
||||
internal virtual void RenderLine(int lineIndex, string lineText, int lineY, int xOffset)
|
||||
{
|
||||
DrawString(lineText, Foreground, xOffset, lineY);
|
||||
}
|
||||
|
||||
internal string Text
|
||||
{
|
||||
get
|
||||
@@ -355,7 +360,8 @@ namespace CMLeonOS.Gui.UILib
|
||||
|
||||
if (i < lines.Count)
|
||||
{
|
||||
DrawString(Shield ? new string('*', lines[i].Length) : lines[i], Foreground, -scrollX, lineY);
|
||||
string lineText = Shield ? new string('*', lines[i].Length) : lines[i];
|
||||
RenderLine(i, lineText, lineY, -scrollX);
|
||||
|
||||
if (caretLine == i)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@ using Cosmos.System;
|
||||
using Cosmos.System.Graphics;
|
||||
using CMLeonOS;
|
||||
using CMLeonOS.Gui.ShellComponents;
|
||||
using CMLeonOS.Settings;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
@@ -381,7 +382,7 @@ namespace CMLeonOS.Gui
|
||||
RenderWallpaper();
|
||||
|
||||
fpsCounter = new Window(this, (int)(ScreenWidth) - 64, (int)(ScreenHeight - 16), 64, 16);
|
||||
if (settingsService.ShowFps)
|
||||
if (SettingsManager.GUI_ShowFps)
|
||||
{
|
||||
AddWindow(fpsCounter);
|
||||
}
|
||||
|
||||
@@ -421,7 +421,7 @@ namespace CMLeonOS
|
||||
}
|
||||
}
|
||||
|
||||
// 我他妈居然成功了,我在没有任何文档的情况下研究出来了
|
||||
// 我居然成功了,我在没有任何文档的情况下研究出来了
|
||||
private void CreateMBRandPartitionTable(Disk disk)
|
||||
{
|
||||
disk.Clear();
|
||||
|
||||
@@ -8,11 +8,21 @@ namespace CMLeonOS.Settings
|
||||
{
|
||||
private static string settingsFilePath = @"0:\system\settings.dat";
|
||||
private static Dictionary<string, string> settings = new Dictionary<string, string>();
|
||||
private static bool savePending = false;
|
||||
private static int pendingSaveCount = 0;
|
||||
private const int MAX_PENDING_SAVES = 5;
|
||||
|
||||
private static Dictionary<string, string> defaultSettings = new Dictionary<string, string>
|
||||
{
|
||||
{ "LoggerEnabled", "true" },
|
||||
{ "MaxLoginAttempts", "3" }
|
||||
{ "MaxLoginAttempts", "3" },
|
||||
{ "GUI_LeftHandStartButton", "false" },
|
||||
{ "GUI_ShowFps", "true" },
|
||||
{ "GUI_TwelveHourClock", "false" },
|
||||
{ "GUI_MouseSensitivity", "1.0" },
|
||||
{ "GUI_ScreenWidth", "1280" },
|
||||
{ "GUI_ScreenHeight", "800" },
|
||||
{ "GUI_DarkNotepad", "false" }
|
||||
};
|
||||
|
||||
public static bool LoggerEnabled
|
||||
@@ -52,6 +62,134 @@ namespace CMLeonOS.Settings
|
||||
}
|
||||
}
|
||||
|
||||
public static bool GUI_LeftHandStartButton
|
||||
{
|
||||
get
|
||||
{
|
||||
if (settings.TryGetValue("GUI_LeftHandStartButton", out string value))
|
||||
{
|
||||
return value.ToLower() == "true";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
set
|
||||
{
|
||||
settings["GUI_LeftHandStartButton"] = value ? "true" : "false";
|
||||
SaveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool GUI_ShowFps
|
||||
{
|
||||
get
|
||||
{
|
||||
if (settings.TryGetValue("GUI_ShowFps", out string value))
|
||||
{
|
||||
return value.ToLower() == "true";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
set
|
||||
{
|
||||
settings["GUI_ShowFps"] = value ? "true" : "false";
|
||||
SaveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool GUI_TwelveHourClock
|
||||
{
|
||||
get
|
||||
{
|
||||
if (settings.TryGetValue("GUI_TwelveHourClock", out string value))
|
||||
{
|
||||
return value.ToLower() == "true";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
set
|
||||
{
|
||||
settings["GUI_TwelveHourClock"] = value ? "true" : "false";
|
||||
SaveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
public static float GUI_MouseSensitivity
|
||||
{
|
||||
get
|
||||
{
|
||||
if (settings.TryGetValue("GUI_MouseSensitivity", out string value))
|
||||
{
|
||||
if (float.TryParse(value, out float result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return 1.0f;
|
||||
}
|
||||
set
|
||||
{
|
||||
settings["GUI_MouseSensitivity"] = value.ToString();
|
||||
SaveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
public static int GUI_ScreenWidth
|
||||
{
|
||||
get
|
||||
{
|
||||
if (settings.TryGetValue("GUI_ScreenWidth", out string value))
|
||||
{
|
||||
if (int.TryParse(value, out int result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return 1280;
|
||||
}
|
||||
set
|
||||
{
|
||||
settings["GUI_ScreenWidth"] = value.ToString();
|
||||
SaveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
public static int GUI_ScreenHeight
|
||||
{
|
||||
get
|
||||
{
|
||||
if (settings.TryGetValue("GUI_ScreenHeight", out string value))
|
||||
{
|
||||
if (int.TryParse(value, out int result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return 800;
|
||||
}
|
||||
set
|
||||
{
|
||||
settings["GUI_ScreenHeight"] = value.ToString();
|
||||
SaveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool GUI_DarkNotepad
|
||||
{
|
||||
get
|
||||
{
|
||||
if (settings.TryGetValue("GUI_DarkNotepad", out string value))
|
||||
{
|
||||
return value.ToLower() == "true";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
set
|
||||
{
|
||||
settings["GUI_DarkNotepad"] = value ? "true" : "false";
|
||||
SaveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
public static void LoadSettings()
|
||||
{
|
||||
settings.Clear();
|
||||
@@ -91,6 +229,8 @@ namespace CMLeonOS.Settings
|
||||
}
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
FlushSettings();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -100,6 +240,22 @@ namespace CMLeonOS.Settings
|
||||
|
||||
public static void SaveSettings()
|
||||
{
|
||||
savePending = true;
|
||||
pendingSaveCount++;
|
||||
|
||||
if (pendingSaveCount >= MAX_PENDING_SAVES)
|
||||
{
|
||||
FlushSettings();
|
||||
}
|
||||
}
|
||||
|
||||
public static void FlushSettings()
|
||||
{
|
||||
if (!savePending)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(settingsFilePath));
|
||||
@@ -115,6 +271,9 @@ namespace CMLeonOS.Settings
|
||||
writer.WriteLine($"{setting.Key}={setting.Value}");
|
||||
}
|
||||
}
|
||||
|
||||
savePending = false;
|
||||
pendingSaveCount = 0;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -15,18 +15,26 @@ namespace CMLeonOS.Utils
|
||||
|
||||
string sanitized = path;
|
||||
|
||||
sanitized = sanitized.Replace('\\', '/');
|
||||
sanitized = sanitized.Replace(':', '_');
|
||||
sanitized = sanitized.Replace('*', '_');
|
||||
sanitized = sanitized.Replace('?', '_');
|
||||
sanitized = sanitized.Replace('"', '_');
|
||||
sanitized = sanitized.Replace('<', '_');
|
||||
sanitized = sanitized.Replace('>', '_');
|
||||
sanitized = sanitized.Replace('|', '_');
|
||||
// 保留驱动器字母和冒号(如 0:)
|
||||
// 检查格式:X:\ 其中 X 是单个字符(字母或数字)
|
||||
bool hasDrive = sanitized.Length >= 2 && sanitized[1] == ':';
|
||||
string drive = hasDrive ? sanitized.Substring(0, 2) : "";
|
||||
string rest = hasDrive ? sanitized.Substring(2) : sanitized;
|
||||
|
||||
sanitized = sanitized.Trim('/', '\\');
|
||||
// 不替换反斜杠,因为 Cosmos 文件系统需要反斜杠
|
||||
rest = rest.Replace(':', '_');
|
||||
rest = rest.Replace('*', '_');
|
||||
rest = rest.Replace('?', '_');
|
||||
rest = rest.Replace('"', '_');
|
||||
rest = rest.Replace('<', '_');
|
||||
rest = rest.Replace('>', '_');
|
||||
rest = rest.Replace('|', '_');
|
||||
|
||||
return sanitized;
|
||||
// 只移除结尾的斜杠,保留开头的斜杠(因为驱动器后面需要斜杠)
|
||||
rest = rest.TrimEnd('/');
|
||||
rest = rest.TrimEnd('\\');
|
||||
|
||||
return drive + rest;
|
||||
}
|
||||
|
||||
public static string Combine(string path1, string path2)
|
||||
|
||||
Reference in New Issue
Block a user