GUI桌面环境

This commit is contained in:
2026-03-01 17:03:49 +08:00
parent 545f40cf95
commit f0a9223520
162 changed files with 9170 additions and 135 deletions

View File

@@ -9,6 +9,7 @@ namespace CMLeonOS
public enum BootMenuAction public enum BootMenuAction
{ {
NormalBoot, NormalBoot,
GuiBoot,
Reboot, Reboot,
Shutdown Shutdown
} }
@@ -44,8 +45,9 @@ namespace CMLeonOS
Console.WriteLine(); Console.WriteLine();
PrintOption("Normal Boot", selIdx == 0); PrintOption("Normal Boot", selIdx == 0);
PrintOption("Reboot", selIdx == 1); PrintOption("GUI Boot", selIdx == 1);
PrintOption("Shutdown", selIdx == 2); PrintOption("Reboot", selIdx == 2);
PrintOption("Shutdown", selIdx == 3);
} }
private static BootMenuAction Confirm(int selIdx) private static BootMenuAction Confirm(int selIdx)
@@ -64,9 +66,11 @@ namespace CMLeonOS
case 0: case 0:
return BootMenuAction.NormalBoot; return BootMenuAction.NormalBoot;
case 1: case 1:
return BootMenuAction.GuiBoot;
case 2:
Sys.Power.Reboot(); Sys.Power.Reboot();
return BootMenuAction.Reboot; return BootMenuAction.Reboot;
case 2: case 3:
Sys.Power.Shutdown(); Sys.Power.Shutdown();
return BootMenuAction.Shutdown; return BootMenuAction.Shutdown;
default: default:
@@ -129,10 +133,10 @@ namespace CMLeonOS
if (selIdx < 0) if (selIdx < 0)
{ {
selIdx = 2; selIdx = 3;
} }
if (selIdx > 2) if (selIdx > 3)
{ {
selIdx = 0; selIdx = 0;
} }

View File

@@ -1 +1 @@
2026-02-28 19:35:58 2026-03-01 17:02:21

View File

@@ -70,7 +70,68 @@
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="font.psf" /> <EmbeddedResource Include="font.psf" />
<EmbeddedResource Include="Wallpapers\wallpaper.bmp" /> <EmbeddedResource Include="Gui\Resources\AppIcons\Calculator.bmp" />
<EmbeddedResource Include="Gui\Resources\AppIcons\Calendar.bmp" />
<EmbeddedResource Include="Gui\Resources\AppIcons\Clock.bmp" />
<EmbeddedResource Include="Gui\Resources\AppIcons\CodeStudio.bmp" />
<EmbeddedResource Include="Gui\Resources\AppIcons\Default.bmp" />
<EmbeddedResource Include="Gui\Resources\AppIcons\DemoLauncher.bmp" />
<EmbeddedResource Include="Gui\Resources\AppIcons\Demos\Mandelbrot.bmp" />
<EmbeddedResource Include="Gui\Resources\AppIcons\Demos\Starfield.bmp" />
<EmbeddedResource Include="Gui\Resources\AppIcons\Files.bmp" />
<EmbeddedResource Include="Gui\Resources\AppIcons\Info.bmp" />
<EmbeddedResource Include="Gui\Resources\AppIcons\Logs.bmp" />
<EmbeddedResource Include="Gui\Resources\AppIcons\MemoryStatistics.bmp" />
<EmbeddedResource Include="Gui\Resources\AppIcons\Notepad.bmp" />
<EmbeddedResource Include="Gui\Resources\AppIcons\Paint.bmp" />
<EmbeddedResource Include="Gui\Resources\AppIcons\Settings.bmp" />
<EmbeddedResource Include="Gui\Resources\AppIcons\Stopwatch.bmp" />
<EmbeddedResource Include="Gui\Resources\AppIcons\Tasks.bmp" />
<EmbeddedResource Include="Gui\Resources\ButtonBackground.bmp" />
<EmbeddedResource Include="Gui\Resources\Calculator\Display.bmp" />
<EmbeddedResource Include="Gui\Resources\Calculator\GridButton.bmp" />
<EmbeddedResource Include="Gui\Resources\Check.bmp" />
<EmbeddedResource Include="Gui\Resources\Clock\ClockBackground.bmp" />
<EmbeddedResource Include="Gui\Resources\Close.bmp" />
<EmbeddedResource Include="Gui\Resources\CodeStudio\Run.bmp" />
<EmbeddedResource Include="Gui\Resources\CodeStudio\Splash.bmp" />
<EmbeddedResource Include="Gui\Resources\Cursor.bmp" />
<EmbeddedResource Include="Gui\Resources\Dock\StartMenu.bmp" />
<EmbeddedResource Include="Gui\Resources\Files\Directory.bmp" />
<EmbeddedResource Include="Gui\Resources\Files\Drive.bmp" />
<EmbeddedResource Include="Gui\Resources\Files\File.bmp" />
<EmbeddedResource Include="Gui\Resources\Files\File_Config.bmp" />
<EmbeddedResource Include="Gui\Resources\Files\File_Rs.bmp" />
<EmbeddedResource Include="Gui\Resources\Files\File_Text.bmp" />
<EmbeddedResource Include="Gui\Resources\Files\Home.bmp" />
<EmbeddedResource Include="Gui\Resources\Files\Up.bmp" />
<EmbeddedResource Include="Gui\Resources\Lock\Background.bmp" />
<EmbeddedResource Include="Gui\Resources\Lock\Gradient.bmp" />
<EmbeddedResource Include="Gui\Resources\Lock\Key.bmp" />
<EmbeddedResource Include="Gui\Resources\Lock\ShutDown.bmp" />
<EmbeddedResource Include="Gui\Resources\Lock\User.bmp" />
<EmbeddedResource Include="Gui\Resources\Lock\UserArrow.bmp" />
<EmbeddedResource Include="Gui\Resources\Logs\Error.bmp" />
<EmbeddedResource Include="Gui\Resources\Logs\Info.bmp" />
<EmbeddedResource Include="Gui\Resources\Logs\Warning.bmp" />
<EmbeddedResource Include="Gui\Resources\Maximise.bmp" />
<EmbeddedResource Include="Gui\Resources\Minimise.bmp" />
<EmbeddedResource Include="Gui\Resources\Restore.bmp" />
<EmbeddedResource Include="Gui\Resources\ScrollbarDown.bmp" />
<EmbeddedResource Include="Gui\Resources\ScrollbarUp.bmp" />
<EmbeddedResource Include="Gui\Resources\Settings\Admin.bmp" />
<EmbeddedResource Include="Gui\Resources\Settings\Info.bmp" />
<EmbeddedResource Include="Gui\Resources\Settings\User.bmp" />
<EmbeddedResource Include="Gui\Resources\Sounds\Alert.wav" />
<EmbeddedResource Include="Gui\Resources\Sounds\Login.wav" />
<EmbeddedResource Include="Gui\Resources\Start.bmp" />
<EmbeddedResource Include="Gui\Resources\StartMenu\User.bmp" />
<EmbeddedResource Include="Gui\Resources\SwitchKnob.bmp" />
<EmbeddedResource Include="Gui\Resources\SwitchOff.bmp" />
<EmbeddedResource Include="Gui\Resources\SwitchOn.bmp" />
<EmbeddedResource Include="Gui\Resources\TitlebarBackground.bmp" />
<EmbeddedResource Include="Gui\Resources\WaitCursor.bmp" />
<EmbeddedResource Include="Gui\Resources\Wallpaper_1280_800.bmp" />
<EmbeddedResource Include="GitCommit.txt" /> <EmbeddedResource Include="GitCommit.txt" />
<EmbeddedResource Include="BuildTime.txt" /> <EmbeddedResource Include="BuildTime.txt" />
<EmbeddedResource Include="LuaApps\*.lua" /> <EmbeddedResource Include="LuaApps\*.lua" />

View File

@@ -1 +1 @@
c5fc081 545f40c

36
Gui/App.cs Normal file
View File

@@ -0,0 +1,36 @@
using Cosmos.System.Graphics;
using CMLeonOS;
using System;
using System.Drawing;
namespace CMLeonOS.Gui
{
internal class AppMetadata
{
public AppMetadata(string name, Func<Process> createProcess, Bitmap icon, Color themeColor)
{
Name = name;
CreateProcess = createProcess;
Icon = icon;
ThemeColor = themeColor;
}
internal void Start(Process parent)
{
ProcessManager.AddProcess(parent, CreateProcess()).Start();
}
internal void Start()
{
ProcessManager.AddProcess(CreateProcess()).Start();
}
internal string Name { get; private set; }
internal Func<Process> CreateProcess { get; private set; }
internal Bitmap Icon { get; private set; }
internal Color ThemeColor { get; private set; }
}
}

129
Gui/AppManager.cs Normal file
View File

@@ -0,0 +1,129 @@
using Cosmos.System.Graphics;
using CMLeonOS.Gui.Apps;
using CMLeonOS.Logger;
using CMLeonOS.Utils;
using System.Collections.Generic;
using System.Drawing;
namespace CMLeonOS.Gui
{
internal static class AppManager
{
internal static List<AppMetadata> AppMetadatas { get; private set; } = new List<AppMetadata>();
private static bool appsLoaded = false;
internal static Bitmap DefaultAppIcon
{
get
{
return Icons.Icon_Default;
}
}
private static class Icons
{
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.AppIcons.Default.bmp")]
private static byte[] _iconBytes_Default;
internal static Bitmap Icon_Default = new Bitmap(_iconBytes_Default);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.AppIcons.Info.bmp")]
private static byte[] _iconBytes_Info;
internal static Bitmap Icon_Info = new Bitmap(_iconBytes_Info);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.AppIcons.Settings.bmp")]
private static byte[] _iconBytes_Settings;
internal static Bitmap Icon_Settings = new Bitmap(_iconBytes_Settings);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.AppIcons.Clock.bmp")]
private static byte[] _iconBytes_Clock;
internal static Bitmap Icon_Clock = new Bitmap(_iconBytes_Clock);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.AppIcons.Tasks.bmp")]
private static byte[] _iconBytes_Tasks;
internal static Bitmap Icon_Tasks = new Bitmap(_iconBytes_Tasks);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.AppIcons.Calculator.bmp")]
private static byte[] _iconBytes_Calculator;
internal static Bitmap Icon_Calculator = new Bitmap(_iconBytes_Calculator);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.AppIcons.CodeStudio.bmp")]
private static byte[] _iconBytes_CodeStudio;
internal static Bitmap Icon_CodeStudio = new Bitmap(_iconBytes_CodeStudio);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.AppIcons.Notepad.bmp")]
private static byte[] _iconBytes_Notepad;
internal static Bitmap Icon_Notepad = new Bitmap(_iconBytes_Notepad);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.AppIcons.Calendar.bmp")]
private static byte[] _iconBytes_Calendar;
internal static Bitmap Icon_Calendar = new Bitmap(_iconBytes_Calendar);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.AppIcons.Files.bmp")]
private static byte[] _iconBytes_Files;
internal static Bitmap Icon_Files = new Bitmap(_iconBytes_Files);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.AppIcons.Logs.bmp")]
private static byte[] _iconBytes_Logs;
internal static Bitmap Icon_Logs = new Bitmap(_iconBytes_Logs);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.AppIcons.DemoLauncher.bmp")]
private static byte[] _iconBytes_DemoLauncher;
internal static Bitmap Icon_DemoLauncher = new Bitmap(_iconBytes_DemoLauncher);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.AppIcons.Stopwatch.bmp")]
private static byte[] _iconBytes_Stopwatch;
internal static Bitmap Icon_Stopwatch = new Bitmap(_iconBytes_Stopwatch);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.AppIcons.Paint.bmp")]
private static byte[] _iconBytes_Paint;
internal static Bitmap Icon_Paint = new Bitmap(_iconBytes_Paint);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.AppIcons.MemoryStatistics.bmp")]
private static byte[] _iconBytes_MemoryStatistics;
internal static Bitmap Icon_MemoryStatistics = new Bitmap(_iconBytes_MemoryStatistics);
}
internal static void RegisterApp(AppMetadata app)
{
AppMetadatas.Add(app);
}
internal static AppMetadata GetAppMetadata(string name)
{
foreach (AppMetadata app in AppMetadatas)
{
if (app.Name == name)
{
return app;
}
}
return null;
}
internal static void LoadAllApps()
{
if (appsLoaded)
{
return;
}
RegisterApp(new AppMetadata("Files", () => { return new Files(); }, Icons.Icon_Files, Color.FromArgb(25, 84, 97)));
RegisterApp(new AppMetadata("Clock", () => { return new Clock(); }, Icons.Icon_Clock, Color.FromArgb(168, 55, 47)));
RegisterApp(new AppMetadata("Notepad", () => { return new Notepad(); }, Icons.Icon_Notepad, Color.FromArgb(14, 59, 76)));
RegisterApp(new AppMetadata("Settings", () => { return new Apps.Settings(); }, Icons.Icon_Settings, Color.FromArgb(0, 115, 186)));
RegisterApp(new AppMetadata("Tasks", () => { return new Tasks(); }, Icons.Icon_Tasks, Color.FromArgb(204, 241, 255)));
RegisterApp(new AppMetadata("Calculator", () => { return new Calculator(); }, Icons.Icon_Calculator, Color.FromArgb(0, 115, 186)));
RegisterApp(new AppMetadata("Event Log", () => { return new Logs(); }, Icons.Icon_Logs, Color.FromArgb(14, 59, 76)));
RegisterApp(new AppMetadata("Demos", () => { return new DemoLauncher(); }, Icons.Icon_DemoLauncher, Color.FromArgb(25, 25, 25)));
RegisterApp(new AppMetadata("Info", () => { return new Info(); }, Icons.Icon_Info, Color.FromArgb(0, 115, 186)));
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)));
Logger.Logger.Instance.Info("AppManager", $"{AppMetadatas.Count} apps were registered.");
appsLoaded = true;
}
}
}

290
Gui/Apps/Calculator.cs Normal file
View File

@@ -0,0 +1,290 @@
using Cosmos.System.Graphics;
using CMLeonOS;
using CMLeonOS.Gui.UILib;
using System;
using System.Drawing;
namespace CMLeonOS.Gui.Apps
{
internal class Calculator : Process
{
internal Calculator() : base("Calculator", ProcessType.Application) { }
AppWindow window;
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
private enum Operator
{
None,
Add,
Subtract,
Multiply,
Divide
}
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Calculator.GridButton.bmp")]
private static byte[] gridButtonBytes;
private static Bitmap gridButtonBitmap = new Bitmap(gridButtonBytes);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Calculator.Display.bmp")]
private static byte[] displayBytes;
private static Bitmap displayBitmap = new Bitmap(displayBytes);
private const int padding = 16;
private const int gridButtonSize = 40;
private const int resultHeight = 40;
private long num1 = 0;
private long num2 = 0;
private Operator op = Operator.None;
private void RenderGridButton(string text, int x, int y)
{
int buttonX = (x * gridButtonSize);
int buttonY = (y * gridButtonSize) + resultHeight;
window.DrawImage(gridButtonBitmap, buttonX, buttonY);
window.DrawString(text, Color.Black, buttonX + (gridButtonSize / 2) - ((text.Length * 8) / 2), buttonY + (gridButtonSize / 2) - (16 / 2));
}
private void WindowClick(int x, int y)
{
int gridX = x / gridButtonSize;
int gridY = (y - resultHeight) / gridButtonSize;
if (gridY < 0)
{
return;
}
switch (gridY)
{
case 0:
switch (gridX)
{
case 0:
InputNum("7");
break;
case 1:
InputNum("8");
break;
case 2:
InputNum("9");
break;
case 3:
InputOp(Operator.Add);
break;
}
break;
case 1:
switch (gridX)
{
case 0:
InputNum("4");
break;
case 1:
InputNum("5");
break;
case 2:
InputNum("6");
break;
case 3:
InputOp(Operator.Subtract);
break;
}
break;
case 2:
switch (gridX)
{
case 0:
InputNum("1");
break;
case 1:
InputNum("2");
break;
case 2:
InputNum("3");
break;
case 3:
InputOp(Operator.Multiply);
break;
}
break;
case 3:
switch (gridX)
{
case 0:
InputNum("0");
break;
case 1:
InputBksp();
break;
case 2:
InputEquals();
break;
case 3:
InputOp(Operator.Divide);
break;
}
break;
}
}
private void RenderDisplay(bool updateWindow = true)
{
window.DrawImage(displayBitmap, 0, 0);
string text;
if (op != Operator.None)
{
char opChar;
opChar = op switch
{
Operator.Add => '+',
Operator.Subtract => '-',
Operator.Multiply => '*',
Operator.Divide => '/',
_ => throw new Exception("Unrecognised operator.")
};
text = num1.ToString().TrimEnd('.') + opChar + num2.ToString().TrimEnd('.');
}
else
{
text = num1.ToString().TrimEnd('.');
}
window.DrawString(text, Color.Black, window.Width - 12 - (text.Length * 8), 12);
if (updateWindow)
{
wm.Update(window);
}
}
private void InputNum(string num)
{
if (op != Operator.None)
{
num2 = long.Parse(num2.ToString() + num);
}
else
{
num1 = long.Parse(num1.ToString() + num);
}
RenderDisplay();
}
private void InputOp(Operator @operator)
{
if (op != Operator.None)
{
num1 = num2;
}
op = @operator;
num2 = 0;
RenderDisplay();
}
private void InputBksp()
{
long num = op != Operator.None ? num2 : num1;
string numStr = num.ToString();
if (numStr.Length > 1)
{
num = long.Parse(numStr.Substring(0, numStr.Length - 1));
}
else
{
num = 0;
}
if (op != Operator.None)
{
num2 = num;
}
else
{
num1 = num;
}
RenderDisplay();
}
private void InputEquals()
{
if (op == Operator.None) return;
switch (op)
{
case Operator.Add:
num1 = num1 + num2;
break;
case Operator.Subtract:
num1 = num1 - num2;
break;
case Operator.Multiply:
num1 = num1 * num2;
break;
case Operator.Divide:
if (num2 == 0)
{
MessageBox messageBox = new MessageBox(this, "Calculator", "Cannot divide by zero.");
messageBox.Show();
return;
}
num1 = num1 / num2;
break;
default:
throw new Exception("Unrecognised operator.");
}
num2 = 0;
op = Operator.None;
RenderDisplay();
}
private void RenderGridButtons()
{
RenderGridButton("7", 0, 0);
RenderGridButton("8", 1, 0);
RenderGridButton("9", 2, 0);
RenderGridButton("+", 3, 0);
RenderGridButton("4", 0, 1);
RenderGridButton("5", 1, 1);
RenderGridButton("6", 2, 1);
RenderGridButton("-", 3, 1);
RenderGridButton("1", 0, 2);
RenderGridButton("2", 1, 2);
RenderGridButton("3", 2, 2);
RenderGridButton("*", 3, 2);
RenderGridButton("0", 0, 3);
RenderGridButton("<-", 1, 3);
RenderGridButton("=", 2, 3);
RenderGridButton("/", 3, 3);
}
public override void Start()
{
base.Start();
window = new AppWindow(this, 256, 256, gridButtonSize * 4, (gridButtonSize * 4) + resultHeight);
wm.AddWindow(window);
window.Title = "Calculator";
window.Clear(Color.Gray);
window.Icon = AppManager.GetAppMetadata("Calculator").Icon;
window.OnClick = WindowClick;
window.Closing = TryStop;
/*inputTextBlock = new TextBlock(window, padding / 2, padding / 2, window.Width - padding, resultHeight - padding);
inputTextBlock.Background = Color.Gray;
inputTextBlock.Foreground = Color.White;
wm.AddWindow(inputTextBlock);*/
RenderDisplay(updateWindow: false);
RenderGridButtons();
wm.Update(window);
}
public override void Run()
{
}
}
}

88
Gui/Apps/Calendar.cs Normal file
View File

@@ -0,0 +1,88 @@
using CMLeonOS;
using CMLeonOS.Gui.UILib;
using System;
namespace CMLeonOS.Gui.Apps
{
internal class Calendar : Process
{
internal Calendar() : base("Calendar", ProcessType.Application) { }
AppWindow window;
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
UILib.Calendar cal;
Button nextButton;
Button prevButton;
private void PrevClicked(int x, int y)
{
if (cal.Month == 1)
{
cal.SetCalendar(cal.Year - 1, 12);
}
else
{
cal.SetCalendar(cal.Year, cal.Month - 1);
}
}
private void NextClicked(int x, int y)
{
if (cal.Month == 12)
{
cal.SetCalendar(cal.Year + 1, 1);
}
else
{
cal.SetCalendar(cal.Year, cal.Month + 1);
}
}
private void WindowResized()
{
cal.Resize(window.Width, window.Height);
cal.Render();
}
public override void Start()
{
base.Start();
window = new AppWindow(this, 320, 256, 384, 288);
wm.AddWindow(window);
window.Title = "Calendar";
window.Icon = AppManager.GetAppMetadata("Calendar").Icon;
window.CanResize = true;
window.UserResized = WindowResized;
window.Closing = TryStop;
cal = new UILib.Calendar(window, 0, 0, window.Width, window.Height);
wm.AddWindow(cal);
DateTime now = DateTime.Now;
cal.Year = now.Year;
cal.Month = now.Month;
prevButton = new Button(window, 8, 8, 24, 24);
prevButton.Text = "<";
prevButton.OnClick = PrevClicked;
wm.AddWindow(prevButton);
nextButton = new Button(window, 40, 8, 24, 24);
nextButton.Text = ">";
nextButton.OnClick = NextClicked;
wm.AddWindow(nextButton);
wm.Update(window);
}
public override void Run()
{
}
}
}

122
Gui/Apps/Clock.cs Normal file
View File

@@ -0,0 +1,122 @@
using Cosmos.System.Graphics;
using CMLeonOS;
using CMLeonOS.Gui.UILib;
using System;
using System.Drawing;
namespace CMLeonOS.Gui.Apps
{
internal class Clock : Process
{
internal Clock() : base("Clock", ProcessType.Application) { }
AppWindow window;
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
private int lastSecond = DateTime.Now.Second;
private SettingsService settingsService;
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Clock.ClockBackground.bmp")]
private static byte[] clockBackgroundBytes;
private static Bitmap clockBackgroundBitmap = new Bitmap(clockBackgroundBytes);
private void RenderHand(int originX, int originY, int handLength, double radians, Color color)
{
int x = originX + (int)(handLength * Math.Sin(radians));
int y = originY - (int)(handLength * Math.Cos(radians));
window.DrawLine(originX, originY, x, y, color);
}
private void RenderClock()
{
if (settingsService == null)
{
settingsService = ProcessManager.GetProcess<SettingsService>();
}
DateTime now = DateTime.Now;
string timeText;
if (settingsService.TwelveHourClock)
{
timeText = DateTime.Now.ToString("h:mm:ss tt");
}
else
{
timeText = DateTime.Now.ToString("HH:mm:ss");
}
int originX = window.Width / 2;
int originY = window.Height / 2;
int diameter = (int)(Math.Min(window.Width, window.Height) * 0.75f);
int radius = diameter / 2;
/* Background */
if (window.Width == 192 && window.Height == 192)
{
window.DrawImage(clockBackgroundBitmap, 0, 0);
}
else
{
window.Clear(Color.White);
window.DrawCircle(originX, originY, radius, Color.Black);
for (int i = 1; i <= 12; i++)
{
int numX = (int)(originX + (Math.Sin(i * Math.PI / 6) * radius * 0.8)) - 4;
int numY = (int)(originY - Math.Cos(i * Math.PI / 6) * radius * 0.8) - 8;
window.DrawString(i.ToString(), Color.Black, numX, numY);
}
}
window.DrawString(timeText, Color.Black, (window.Width / 2) - ((timeText.Length * 8) / 2), 4);
/* Second hand */
double second = now.Second;
double secondRad = second * Math.PI / 30;
RenderHand(originX, originY, radius, secondRad, Color.Red);
/* Minute hand*/
double minute = now.Minute + (second / 60);
double minuteRad = minute * Math.PI / 30;
RenderHand(originX, originY, (int)(radius * 0.75f), minuteRad, Color.Black);
/* Hour hand */
double hour = now.Hour + (minute / 60);
double hourRad = hour * Math.PI / 6;
RenderHand(originX, originY, (int)(radius * 0.5f), hourRad, Color.Black);
wm.Update(window);
}
#region Process
public override void Start()
{
base.Start();
window = new AppWindow(this, 256, 256, 192, 192);
window.Icon = AppManager.GetAppMetadata("Clock").Icon;
window.CanResize = true;
window.UserResized = RenderClock;
window.Closing = TryStop;
wm.AddWindow(window);
window.Title = "Clock";
RenderClock();
}
public override void Run()
{
DateTime now = DateTime.Now;
if (lastSecond != now.Second)
{
RenderClock();
lastSecond = now.Second;
}
}
#endregion Process
}
}

86
Gui/Apps/DemoLauncher.cs Normal file
View File

@@ -0,0 +1,86 @@
using Cosmos.System.Graphics;
using CMLeonOS;
using CMLeonOS.Gui.SmoothMono;
using CMLeonOS.Gui.UILib;
using System.Collections.Generic;
using System.Drawing;
namespace CMLeonOS.Gui.Apps
{
internal class DemoLauncher : Process
{
internal DemoLauncher() : base("DemoLauncher", ProcessType.Application) { }
AppWindow window;
Table table;
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
private static class Icons
{
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.AppIcons.Demos.Starfield.bmp")]
private static byte[] _iconBytes_Starfield;
internal static Bitmap Icon_Starfield = new Bitmap(_iconBytes_Starfield);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.AppIcons.Demos.Mandelbrot.bmp")]
private static byte[] _iconBytes_Mandelbrot;
internal static Bitmap Icon_Mandelbrot = new Bitmap(_iconBytes_Mandelbrot);
}
List<AppMetadata> demoApps = new()
{
new AppMetadata("Starfield", () => { return new Apps.Demos.Starfield(); }, Icons.Icon_Starfield, Color.Black ),
new AppMetadata("Mandelbrot", () => { return new Apps.Demos.Mandelbrot(); }, Icons.Icon_Mandelbrot, Color.Black ),
};
private const string message = "Demo Launcher";
private void PopulateTable()
{
table.Cells.Clear();
foreach (AppMetadata app in demoApps)
{
table.Cells.Add(new TableCell(app.Icon.Resize(32, 32), app.Name));
}
table.Render();
}
public override void Start()
{
base.Start();
window = new AppWindow(this, 256, 256, 384, 256);
wm.AddWindow(window);
window.Title = "Demos";
window.Icon = AppManager.GetAppMetadata("Demos").Icon;
window.Closing = TryStop;
window.Clear(Color.FromArgb(56, 56, 71));
window.DrawString(message, Color.White, (window.Width / 2) - ((FontData.Width * message.Length) / 2), 12);
table = new Table(window, 12, 40, window.Width - 24, window.Height - 52);
table.Background = Color.FromArgb(56, 56, 71);
table.Border = Color.FromArgb(56, 56, 71);
table.Foreground = Color.White;
table.CellHeight = 32;
table.OnDoubleClick = (int x, int y) =>
{
if (table.SelectedCellIndex != -1)
{
AppMetadata app = demoApps[table.SelectedCellIndex];
ProcessManager.AddProcess(app.CreateProcess()).Start();
}
};
PopulateTable();
wm.AddWindow(table);
wm.Update(window);
}
public override void Run()
{
}
}
}

View File

@@ -0,0 +1,91 @@
using CMLeonOS;
using CMLeonOS.Gui.UILib;
using System;
using System.Drawing;
namespace CMLeonOS.Gui.Apps.Demos
{
internal class Mandelbrot : Process
{
internal Mandelbrot() : base("Mandelbrot", ProcessType.Application) { }
AppWindow window;
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
private Color GetColor(double v)
{
int red = Math.Clamp((int)(255 * v), 0, 255);
int green = 0;
int blue = Math.Clamp((int)(255 * (1 - v)), 0, 255);
return Color.FromArgb(red, green, blue);
}
private void RenderMandelbrot()
{
window.Clear(Color.Black);
wm.Update(window);
int width = window.Width;
int height = window.Height;
const int max = 20;
const double bail = 2.0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
double zx = 0;
double zy = 0;
double cx = (x - width / 2.0) / (width / 4.0);
double cy = (y - height / 2.0) / (height / 4.0);
int iteration = 0;
while (zx * zx + zy * zy < bail && iteration < max)
{
double zxNew = zx * zx - zy * zy + cx;
zy = 2 * zx * zy + cy;
zx = zxNew;
iteration++;
}
double smooth = iteration + 1 - Math.Log(Math.Log(Math.Sqrt(zx * zx + zy * zy)) / Math.Log(bail)) / Math.Log(2);
window.DrawPoint(x, y, GetColor(smooth / max));
if (x % 32 == 0)
{
ProcessManager.Yield();
}
}
if (y % 8 == 0)
{
wm.Update(window);
}
}
wm.Update(window);
}
public override void Start()
{
base.Start();
window = new AppWindow(this, 256, 256, 256, 256);
wm.AddWindow(window);
window.Title = "Mandelbrot";
window.CanResize = true;
window.Closing = TryStop;
window.UserResized = RenderMandelbrot;
RenderMandelbrot();
}
public override void Run()
{
}
}
}

105
Gui/Apps/Demos/Starfield.cs Normal file
View File

@@ -0,0 +1,105 @@
using CMLeonOS;
using CMLeonOS.Gui.UILib;
using System;
using System.Collections.Generic;
using System.Drawing;
namespace CMLeonOS.Gui.Apps.Demos
{
internal class Starfield : Process
{
internal Starfield() : base("Starfield", ProcessType.Application) { }
AppWindow window;
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
private readonly Random random = new Random();
private readonly List<Star> stars = new List<Star>();
private int timerId;
private class Star
{
internal double X { get; set; }
internal double Y { get; set; }
internal double Z { get; set; }
internal double Velocity { get; set; }
internal Star(double x, double y, double z, double velocity)
{
X = x;
Y = y;
Z = z;
Velocity = velocity;
}
}
internal (double, double) TransformCoordinates(double x, double y, double z, double fov)
{
double screenX = x / (z * Math.Tan(fov / 2)) + 0.5;
double screenY = y / (z * Math.Tan(fov / 2)) + 0.5;
return (screenX, screenY);
}
public override void Start()
{
base.Start();
window = new AppWindow(this, 256, 256, 256, 256);
wm.AddWindow(window);
window.Title = "Starfield";
window.CanResize = true;
window.Closing = TryStop;
for (int i = 0; i < 100; i++)
{
stars.Add(new Star(
x: random.NextDouble() * 2 - 1.5,
y: random.NextDouble() * 2 - 1.5,
z: 3,
velocity: random.NextDouble() * 0.05 + 0.05));
}
timerId = Cosmos.HAL.Global.PIT.RegisterTimer(new Cosmos.HAL.PIT.PITTimer(() =>
{
foreach (var star in stars)
{
star.Z -= star.Velocity;
if (star.Z < 0)
{
star.X = random.NextDouble() * 2 - 1.5;
star.Y = random.NextDouble() * 2 - 1.5;
star.Z = 3;
}
}
}, (ulong)((1000 /* ms */ / 30) * 1e+6 /* ms -> ns */ ), true));
}
public override void Run()
{
window.Clear(Color.Black);
foreach (var star in stars)
{
(double X, double Y) pos = TransformCoordinates(star.X, star.Y, star.Z, Math.PI / 2);
int screenX = (int)((pos.X + 1) * (window.Width / 2));
int screenY = (int)((pos.Y + 1) * (window.Height / 2));
window.DrawPoint(screenX, screenY, Color.White);
}
wm.Update(window);
}
public override void Stop()
{
base.Stop();
Cosmos.HAL.Global.PIT.UnregisterTimer(timerId);
}
}
}

330
Gui/Apps/Files.cs Normal file
View File

@@ -0,0 +1,330 @@
using Cosmos.System.Graphics;
using CMLeonOS;
using CMLeonOS.Gui.UILib;
using CMLeonOS.Logger;
using CMLeonOS.Utils;
using System;
using System.Drawing;
using System.IO;
namespace CMLeonOS.Gui.Apps
{
internal class Files : Process
{
internal Files() : base("Files", ProcessType.Application) { }
AppWindow window;
Table entryTable;
Table shortcutsTable;
ImageBlock up;
TextBox pathBox;
Window header;
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
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_Config.bmp")]
private static byte[] _iconBytes_File_Config;
internal static Bitmap Icon_File_Config = new Bitmap(_iconBytes_File_Config);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Files.File_Rs.bmp")]
private static byte[] _iconBytes_File_Rs;
internal static Bitmap Icon_File_Rs = new Bitmap(_iconBytes_File_Rs);
[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.Drive.bmp")]
private static byte[] _iconBytes_Drive;
internal static Bitmap Icon_Drive = new Bitmap(_iconBytes_Drive);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Files.Home.bmp")]
private static byte[] _iconBytes_Home;
internal static Bitmap Icon_Home = new Bitmap(_iconBytes_Home);
[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 string currentDir = @"0:\";
private const int pathBoxMargin = 4;
private const int pathBoxHeight = 24;
private const int shortcutsWidth = 128;
private const int headerHeight = 32;
private const string dirEmptyMessage = "This folder is empty.";
private readonly (string Name, string Path)[] shortcuts = new (string, string)[]
{
("CMLeonOS (0:)", @"0:\"),
("My Home", @$"0:\user\{UserSystem.CurrentLoggedInUser.Username}"),
("Users", @"0:\user"),
("etc", @"0:\etc"),
};
private Bitmap GetFileIcon(string path)
{
string extension = Path.GetExtension(path).ToLower();
return extension switch
{
".txt" or ".md" or ".log" => Icons.Icon_File_Text,
".rs" => Icons.Icon_File_Rs,
".ini" or ".cfg" => Icons.Icon_File_Config,
_ => Icons.Icon_File
};
}
private Bitmap GetDirectoryIcon(string path)
{
if (Path.TrimEndingDirectorySeparator(path).StartsWith(@"0:\user\"))
{
return Icons.Icon_Home;
}
switch (path)
{
case @"0:\":
return Icons.Icon_Drive;
default:
return Icons.Icon_Directory;
}
}
private void PopulateEntryTable()
{
entryTable.Cells.Clear();
entryTable.SelectedCellIndex = -1;
bool empty = true;
foreach (string path in Directory.GetDirectories(currentDir))
{
entryTable.Cells.Add(new TableCell(GetDirectoryIcon(path), Path.GetFileName(path), tag: "Directory"));
empty = false;
}
foreach (string path in Directory.GetFiles(currentDir))
{
entryTable.Cells.Add(new TableCell(GetFileIcon(path), Path.GetFileName(path), tag: "File"));
empty = false;
}
if (empty)
{
entryTable.Clear(entryTable.Background);
entryTable.DrawString(dirEmptyMessage, Color.Black, (entryTable.Width / 2) - ((dirEmptyMessage.Length * 8) / 2), 12);
wm.Update(entryTable);
}
else
{
entryTable.Render();
}
}
private void PopulateShortcutTable()
{
shortcutsTable.Cells.Clear();
foreach ((string Name, string Path) item in shortcuts)
{
shortcutsTable.Cells.Add(new TableCell(GetDirectoryIcon(item.Path), item.Name, tag: item.Path));
}
shortcutsTable.Render();
}
private bool NavigateTo(string path)
{
string sanitised = PathUtil.Sanitize(path);
if (!Directory.Exists(sanitised))
{
MessageBox messageBox = new MessageBox(this, "Files", $"CMLeonOS can't find that folder.\nCheck the spelling and try again.");
messageBox.Show();
return false;
}
currentDir = sanitised;
pathBox.Text = sanitised;
PopulateEntryTable();
UpdateSelectedShortcut();
RenderHeader();
if (sanitised == @"0:\")
{
window.Title = "Files";
}
else
{
window.Title = Path.GetDirectoryName(sanitised);
}
return true;
}
private void UpdateSelectedShortcut()
{
for (int i = 0; i < shortcuts.Length; i++)
{
if (shortcuts[i].Path == currentDir)
{
shortcutsTable.SelectedCellIndex = i;
return;
}
}
shortcutsTable.SelectedCellIndex = -1;
}
private void EntryTableDoubleClicked(int x, int y)
{
if (entryTable.SelectedCellIndex != -1)
{
TableCell cell = entryTable.Cells[entryTable.SelectedCellIndex];
string path = PathUtil.Combine(currentDir, cell.Text);
if ((string)cell.Tag == "Directory")
{
NavigateTo(path);
}
else if ((string)cell.Tag == "File")
{
try
{
string extension = Path.GetExtension(path).ToLower();
if (extension == ".txt" || extension == ".md")
{
var notepad = new Notepad(path);
var metadata = AppManager.GetAppMetadata("Notepad");
metadata.Start();
}
else
{
Logger.Logger.Instance.Warning("Files", $"Cannot open file: {path}");
}
}
catch (Exception ex)
{
Logger.Logger.Instance.Error("Files", $"Error opening file: {ex.Message}");
}
}
}
}
private void ShortcutsTableCellSelected(int index)
{
if (index != -1)
{
bool success = NavigateTo(shortcuts[index].Path);
if (!success)
{
UpdateSelectedShortcut();
}
}
}
private void PathBoxSubmitted()
{
bool success = NavigateTo(pathBox.Text);
if (!success)
{
pathBox.Text = currentDir;
}
}
private void UpClicked()
{
DirectoryInfo parent = Directory.GetParent(currentDir);
if (parent != null)
{
NavigateTo(parent.FullName);
}
}
private void RenderHeader(bool updateWindow = true)
{
header.Clear(Color.DarkBlue);
header.DrawImageAlpha(GetDirectoryIcon(currentDir), 8, 8);
DirectoryInfo info = new DirectoryInfo(currentDir);
string currentDirFriendlyName = Path.GetFileName(currentDir);
if (currentDir == $@"0:\user\{UserSystem.CurrentLoggedInUser.Username}")
{
currentDirFriendlyName = "My Home";
}
header.DrawString(info.Parent == null ? currentDir : currentDirFriendlyName, Color.White, 32, 8);
if (updateWindow)
{
wm.Update(header);
}
}
private void WindowClicked(int x, int y)
{
if (x < pathBoxHeight && y < pathBoxHeight)
{
UpClicked();
}
}
public override void Start()
{
base.Start();
window = new AppWindow(this, 288, 240, 512, 304);
wm.AddWindow(window);
window.Title = "Files";
window.Icon = AppManager.GetAppMetadata("Files").Icon;
window.OnClick = WindowClicked;
window.Closing = TryStop;
window.Clear(Color.DarkGray);
window.DrawImageAlpha(Icons.Icon_Up, 0, 0);
pathBox = new TextBox(window, (pathBoxMargin / 2) + pathBoxHeight, pathBoxMargin / 2, window.Width - pathBoxMargin - pathBoxHeight, 24 - pathBoxMargin);
pathBox.Text = currentDir;
pathBox.Submitted = PathBoxSubmitted;
wm.AddWindow(pathBox);
entryTable = new Table(window, shortcutsWidth, pathBoxHeight + headerHeight, window.Width - shortcutsWidth, window.Height - pathBoxHeight - headerHeight);
entryTable.OnDoubleClick = EntryTableDoubleClicked;
PopulateEntryTable();
wm.AddWindow(entryTable);
header = new Window(this, window, shortcutsWidth, pathBoxHeight, window.Width - shortcutsWidth, headerHeight);
wm.AddWindow(header);
RenderHeader(updateWindow: false);
shortcutsTable = new Table(window, 0, pathBoxHeight, shortcutsWidth, window.Height - pathBoxHeight);
shortcutsTable.AllowDeselection = false;
shortcutsTable.Background = Color.DarkGray;
shortcutsTable.Foreground = Color.White;
PopulateShortcutTable();
shortcutsTable.SelectedCellIndex = 0;
shortcutsTable.TableCellSelected = ShortcutsTableCellSelected;
wm.AddWindow(shortcutsTable);
wm.Update(window);
}
public override void Run()
{
}
}
}

53
Gui/Apps/Info.cs Normal file
View File

@@ -0,0 +1,53 @@
using CMLeonOS;
using CMLeonOS.Gui.UILib;
using CMLeonOS.Utils;
using System.Drawing;
namespace CMLeonOS.Gui.Apps
{
internal class Info : Process
{
internal Info() : base("Info", ProcessType.Application) { }
AppWindow window;
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
public override void Start()
{
base.Start();
window = new AppWindow(this, 256, 256, 320, 256);
wm.AddWindow(window);
window.Title = "Info";
window.Icon = AppManager.GetAppMetadata("Info").Icon;
window.Closing = TryStop;
window.Clear(Color.LightGray);
window.DrawFilledRectangle(0, 0, window.Width, 40, Color.Black);
window.DrawString("CMLeonOS", System.Drawing.Color.White, 12, 12);
window.DrawString($"OS: CMLeonOS {Kernel.Version}", Color.Black, 12, 52);
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);
Button button = new Button(window, window.Width - 80 - 12, window.Height - 20 - 12, 80, 20);
button.Text = "OK";
button.OnClick = (int x, int y) =>
{
wm.RemoveWindow(window);
};
wm.AddWindow(button);
wm.Update(window);
}
public override void Run()
{
}
}
}

138
Gui/Apps/Logs.cs Normal file
View File

@@ -0,0 +1,138 @@
using Cosmos.System.Graphics;
using CMLeonOS;
using CMLeonOS.Gui.SmoothMono;
using CMLeonOS.Gui.UILib;
using CMLeonOS.Logger;
using System.Drawing;
using System.Text;
namespace CMLeonOS.Gui.Apps
{
internal class Logs : Process
{
internal Logs() : base("Logs", ProcessType.Application) { }
AppWindow window;
Table table;
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
private static class Icons
{
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Logs.Info.bmp")]
private static byte[] _iconBytes_Info;
internal static Bitmap Icon_Info = new Bitmap(_iconBytes_Info);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Logs.Warning.bmp")]
private static byte[] _iconBytes_Warning;
internal static Bitmap Icon_Warning = new Bitmap(_iconBytes_Warning);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Logs.Error.bmp")]
private static byte[] _iconBytes_Error;
internal static Bitmap Icon_Error = new Bitmap(_iconBytes_Error);
}
private void AddLogToTable(LogEntry log)
{
Bitmap icon;
switch (log.Priority)
{
case LogLevel.Info:
icon = Icons.Icon_Info;
break;
case LogLevel.Warning:
icon = Icons.Icon_Warning;
break;
case LogLevel.Error:
icon = Icons.Icon_Error;
break;
default:
icon = null;
break;
}
table.Cells.Add(new TableCell(icon, $"{log.Date.ToString("HH:mm")} - {log.Source}: {log.Message}", log));
}
private void Update()
{
window.Clear(Color.Gray);
string text = $"{Log.Logs.Count} messages";
window.DrawString(text, Color.White, window.Width - (FontData.Width * text.Length) - 12, window.Height - FontData.Height - 12);
table.Render();
table.ScrollToBottom();
wm.Update(window);
}
public override void Start()
{
base.Start();
if (UserSystem.CurrentLoggedInUser == null || !UserSystem.CurrentLoggedInUser.Admin)
{
MessageBox messageBox = new MessageBox(Parent, Name, "You must be an admin to run this app.");
messageBox.Show();
TryStop();
return;
}
window = new AppWindow(this, 256, 256, 512, 352);
wm.AddWindow(window);
window.Icon = AppManager.GetAppMetadata("Event Log").Icon;
window.Title = "Event Log";
window.Closing = TryStop;
table = new Table(window, 12, 12, window.Width - 24, window.Height - 24 - 16 - 12);
table.OnDoubleClick = (int x, int y) =>
{
if (table.SelectedCellIndex != -1)
{
LogEntry log = (LogEntry)table.Cells[table.SelectedCellIndex].Tag;
string priority = log.Priority switch
{
LogLevel.Info => "Info",
LogLevel.Warning => "Warning",
LogLevel.Error => "Error",
_ => "Unknown"
};
StringBuilder builder = new StringBuilder();
builder.AppendLine($"Date: {log.Date.ToLongDateString()} {log.Date.ToLongTimeString()}");
builder.AppendLine($"Source: {log.Source}");
builder.AppendLine($"Priority: {priority}");
builder.AppendLine();
builder.Append(log.Message);
MessageBox messageBox = new MessageBox(this, $"{log.Source}: Log Event", builder.ToString());
messageBox.Show();
}
};
wm.AddWindow(table);
table.Cells.Clear();
foreach (LogEntry log in Log.Logs)
{
AddLogToTable(log);
}
Log.LogEmittedReceivers.Add((LogEntry log) =>
{
AddLogToTable(log);
Update();
});
Update();
}
public override void Run()
{
}
}
}

View File

@@ -0,0 +1,71 @@
using CMLeonOS;
using CMLeonOS.Utils;
using CMLeonOS.Gui.SmoothMono;
using CMLeonOS.Gui.UILib;
using System;
using System.Drawing;
namespace CMLeonOS.Gui.Apps
{
internal class MemoryStatistics : Process
{
internal MemoryStatistics() : base("MemoryStatistics", ProcessType.Application) { }
AppWindow window;
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
private int lastSecond;
private static int padding = 12;
private static int barHeight = 12;
private static Color barColour = Color.FromArgb(0, 155, 254);
private void Update()
{
window.Clear(Color.LightGray);
var statistics = MemoryStatisticsProvider.GetMemoryStatistics();
window.DrawString("Memory Statistics", Color.DarkBlue, padding, padding);
window.DrawString(string.Format(@"Total: {0} MB
Unavailable: {1} MB
Used: {2:d1} MB
Free: {3} MB
Percentage Used: {4:d1}%",
statistics.TotalMB,
statistics.UnavailableMB,
statistics.UsedMB,
statistics.FreeMB,
statistics.PercentUsed), Color.Black, padding, padding + FontData.Height + padding);
window.DrawFilledRectangle(0, window.Height - barHeight, window.Width, barHeight, Color.Black);
window.DrawFilledRectangle(0, window.Height - barHeight, (int)(window.Width * ((float)statistics.PercentUsed / 100f)), barHeight, barColour);
wm.Update(window);
}
public override void Start()
{
base.Start();
window = new AppWindow(this, 256, 256, 256, 192);
wm.AddWindow(window);
window.Title = "Memory Statistics";
window.Icon = AppManager.GetAppMetadata("Memory Statistics").Icon;
window.Closing = TryStop;
Update();
}
public override void Run()
{
int second = DateTime.Now.Second;
if (lastSecond != second)
{
lastSecond = second;
Update();
}
}
}
}

226
Gui/Apps/Notepad.cs Normal file
View File

@@ -0,0 +1,226 @@
using CMLeonOS;
using CMLeonOS.Gui.SmoothMono;
using CMLeonOS.Gui.UILib;
using CMLeonOS.Utils;
using System.Drawing;
using System.IO;
namespace CMLeonOS.Gui.Apps
{
internal class Notepad : Process
{
internal Notepad() : base("Notepad", ProcessType.Application) { }
internal Notepad(string path) : base("Notepad", ProcessType.Application)
{
this.path = path;
}
AppWindow window;
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
SettingsService settingsService = ProcessManager.GetProcess<SettingsService>();
TextBox textBox;
ShortcutBar shortcutBar;
private string? path = null;
private bool modified = false;
private void TextChanged()
{
modified = true;
UpdateTitle();
}
private void WindowResized()
{
textBox.Resize(window.Width, window.Height - 20);
shortcutBar.Resize(window.Width, 20);
shortcutBar.Render();
textBox.MarkAllLines();
textBox.Render();
}
private void UpdateTitle()
{
if (path == null)
{
window.Title = "Untitled - Notepad";
return;
}
if (modified)
{
window.Title = $"{Path.GetFileName(path)}* - Notepad";
}
else
{
window.Title = $"{Path.GetFileName(path)} - Notepad";
}
}
internal void Open(string newPath, bool readFile = true)
{
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)}'.");
messageBox.Show();
}
path = newPath;
if (readFile)
{
textBox.Text = File.ReadAllText(path);
textBox.MarkAllLines();
textBox.Render();
modified = false;
}
UpdateTitle();
}
private void OpenFilePrompt()
{
PromptBox prompt = new PromptBox(this, "Open File", "Enter the path to open.", "Path", (string newPath) =>
{
if (!newPath.Contains(':'))
{
newPath = $@"0:\{newPath}";
}
Open(newPath);
});
prompt.Show();
}
private void SaveAsPrompt()
{
PromptBox prompt = new PromptBox(this, "Save As", "Enter the path to save to.", "Path", (string newPath) =>
{
if (!newPath.Contains(':'))
{
newPath = $@"0:\{newPath}";
}
Open(newPath, readFile: false);
// Check if open succeeded.
if (path != null)
{
Save();
}
});
prompt.Show();
}
private void Save()
{
if (path == null)
{
SaveAsPrompt();
return;
}
File.WriteAllText(path, textBox.Text);
modified = false;
UpdateTitle();
}
private void ApplyTheme()
{
if (settingsService.DarkNotepad)
{
textBox.Background = Color.FromArgb(24, 24, 30);
textBox.Foreground = Color.White;
shortcutBar.Background = Color.FromArgb(56, 56, 71);
shortcutBar.Foreground = Color.White;
}
else
{
textBox.Background = Color.White;
textBox.Foreground = Color.Black;
shortcutBar.Background = Color.LightGray;
shortcutBar.Foreground = Color.Black;
}
textBox.MarkAllLines();
textBox.Render();
}
private void OpenViewSettings()
{
AppWindow settingsWindow = new AppWindow(this, 320, 264, 256, 192);
settingsWindow.DrawString("Notepad Settings", Color.DarkBlue, 12, 12);
settingsWindow.DrawString($"Notepad v{Kernel.Version}", Color.DarkGray, 12, settingsWindow.Height - 12 - FontData.Height);
wm.AddWindow(settingsWindow);
settingsWindow.Title = "Notepad";
Switch darkSwitch = new Switch(settingsWindow, 12, 40, settingsWindow.Width - 16, 20);
darkSwitch.Text = "Dark theme";
darkSwitch.Checked = settingsService.DarkNotepad;
darkSwitch.CheckBoxChanged = (bool @checked) =>
{
settingsService.DarkNotepad = @checked;
ApplyTheme();
};
wm.AddWindow(darkSwitch);
wm.Update(settingsWindow);
}
public override void Start()
{
base.Start();
window = new AppWindow(this, 320, 264, 384, 240);
wm.AddWindow(window);
UpdateTitle();
window.Closing = TryStop;
window.Icon = AppManager.GetAppMetadata("Notepad").Icon;
window.CanResize = true;
window.UserResized = WindowResized;
shortcutBar = new ShortcutBar(window, 0, 0, window.Width, 20);
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("View", OpenViewSettings));
shortcutBar.Render();
wm.AddWindow(shortcutBar);
textBox = new TextBox(window, 0, 20, window.Width, window.Height - 20);
textBox.MultiLine = true;
textBox.Changed = TextChanged;
wm.AddWindow(textBox);
ApplyTheme();
Open(path);
wm.Update(window);
}
public override void Run()
{
}
}
}

View File

@@ -0,0 +1,89 @@
using CMLeonOS.Gui.UILib;
using System.Collections.Generic;
using System.Drawing;
namespace CMLeonOS.Gui.Apps.Paint
{
internal class ColourPicker : Window
{
private Paint paintInstance;
private Table table;
internal readonly List<Color> Colours = new List<Color>()
{
Color.Black,
Color.White,
Color.Red,
Color.Blue,
Color.Orange,
Color.Green,
Color.Pink,
Color.Gray,
Color.Purple,
Color.DarkGoldenrod,
Color.DarkGray,
Color.DarkGreen,
Color.DarkCyan,
Color.Cyan,
Color.BlueViolet,
Color.AliceBlue,
Color.Brown,
Color.CornflowerBlue,
Color.Azure,
Color.Beige,
Color.DarkBlue,
Color.DarkSlateBlue,
Color.SeaGreen
};
private void TableClicked(int x, int y)
{
// Clear 'Selected' text on previously selected colour.
foreach (var cell in table.Cells)
{
cell.Text = string.Empty;
}
var selectedCell = table.Cells[table.SelectedCellIndex];
Color color = (Color)selectedCell.Tag;
paintInstance.SelectedColor = color;
selectedCell.Text = "Selected";
table.Render();
}
internal ColourPicker(Paint paint, int x, int y, int width, int height) : base(paint, x, y, width, height)
{
paintInstance = paint;
Clear(Color.FromArgb(107, 107, 107));
DrawString("Colours", Color.White, 8, 8);
table = new Table(this, 0, 32, Width, Height - 32);
table.AllowDeselection = false;
table.CellHeight = 20;
table.TextAlignment = Alignment.Middle;
table.OnClick = TableClicked;
foreach (Color colour in Colours)
{
TableCell cell = new(string.Empty, tag: colour);
cell.BackgroundColourOverride = colour;
cell.ForegroundColourOverride = colour.GetForegroundColour();
if (colour == paint.SelectedColor)
{
cell.Text = "Selected";
}
table.Cells.Add(cell);
}
table.Render();
WM.AddWindow(this);
WM.AddWindow(table);
}
}
}

88
Gui/Apps/Paint/Paint.cs Normal file
View File

@@ -0,0 +1,88 @@
using Cosmos.System;
using CMLeonOS;
using CMLeonOS.Gui.UILib;
using System.Drawing;
namespace CMLeonOS.Gui.Apps.Paint
{
internal class Paint : Process
{
internal Paint() : base("Paint", ProcessType.Application)
{
}
AppWindow window;
Window canvas;
ToolBox toolBox;
ColourPicker colourPicker;
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
private bool down = false;
internal Color SelectedColor { get; set; } = Color.Black;
internal bool IsInBounds(int x, int y)
{
if (x >= canvas.Width || y >= canvas.Height) return false;
if (x < 0 || y < 0) return false;
return true;
}
private void CanvasDown(int x, int y)
{
down = true;
}
public override void Start()
{
base.Start();
window = new AppWindow(this, 256, 256, 768, 448);
window.Title = "Paint";
window.Icon = AppManager.GetAppMetadata("Paint").Icon;
window.Closing = TryStop;
window.Clear(Color.FromArgb(73, 73, 73));
wm.AddWindow(window);
int canvasWidth = 384;
int canvasHeight = 256;
canvas = new Window(this, (window.Width / 2) - (canvasWidth / 2), (window.Height / 2) - (canvasHeight / 2), canvasWidth, canvasHeight);
canvas.RelativeTo = window;
canvas.OnDown = CanvasDown;
canvas.Clear(Color.White);
wm.AddWindow(canvas);
toolBox = new ToolBox(this, 0, 0, 128, window.Height);
toolBox.RelativeTo = window;
colourPicker = new ColourPicker(this, window.Width - 128, 0, 128, window.Height);
colourPicker.RelativeTo = window;
wm.Update(window);
}
public override void Run()
{
if (down)
{
if (MouseManager.MouseState == MouseState.None)
{
down = false;
}
toolBox.SelectedTool.Run(
this,
canvas,
MouseManager.MouseState,
(int)(MouseManager.X - canvas.ScreenX),
(int)(MouseManager.Y - canvas.ScreenY)
);
wm.Update(canvas);
}
}
}
}

24
Gui/Apps/Paint/Tool.cs Normal file
View File

@@ -0,0 +1,24 @@
using Cosmos.System;
namespace CMLeonOS.Gui.Apps.Paint
{
internal abstract class Tool
{
internal Tool(string name)
{
Name = name;
}
internal abstract void Run(Paint paint, Window canvas, MouseState mouseState, int mouseX, int mouseY);
internal virtual void Selected()
{
}
internal virtual void Deselected()
{
}
internal string Name { get; init; }
}
}

60
Gui/Apps/Paint/ToolBox.cs Normal file
View File

@@ -0,0 +1,60 @@
using CMLeonOS.Gui.UILib;
using System.Collections.Generic;
using System.Drawing;
namespace CMLeonOS.Gui.Apps.Paint
{
internal class ToolBox : Window
{
private Paint paintInstance;
private Table table;
internal Tool SelectedTool;
internal readonly List<Tool> Tools = new List<Tool>()
{
new Tools.Pencil(),
new Tools.CircleBrush()
};
private void TableClicked(int x, int y)
{
Tool tool = table.Cells[table.SelectedCellIndex].Tag as Tool;
if (tool != SelectedTool)
{
SelectedTool.Deselected();
SelectedTool = tool;
}
}
internal ToolBox(Paint paint, int x, int y, int width, int height) : base(paint, x, y, width, height)
{
paintInstance = paint;
Clear(Color.FromArgb(107, 107, 107));
DrawString("Toolbox", Color.White, 8, 8);
table = new Table(this, 0, 32, Width, Height - 32);
table.AllowDeselection = false;
table.CellHeight = 24;
table.TextAlignment = Alignment.Middle;
table.OnClick = TableClicked;
foreach (Tool tool in Tools)
{
table.Cells.Add(new TableCell(tool.Name, tool));
}
SelectedTool = Tools[0];
table.SelectedCellIndex = 0;
table.Render();
WM.AddWindow(this);
WM.AddWindow(table);
}
}
}

View File

@@ -0,0 +1,19 @@
using Cosmos.System;
namespace CMLeonOS.Gui.Apps.Paint.Tools
{
internal class CircleBrush : Tool
{
public CircleBrush() : base("Circle brush")
{
}
internal override void Run(Paint paint, Window canvas, MouseState mouseState, int mouseX, int mouseY)
{
if (mouseState == MouseState.Left)
{
canvas.DrawCircle(mouseX, mouseY, 5, paint.SelectedColor);
}
}
}
}

View File

@@ -0,0 +1,42 @@
using Cosmos.System;
namespace CMLeonOS.Gui.Apps.Paint.Tools
{
internal class Pencil : Tool
{
public Pencil() : base("Pencil")
{
}
private bool joinLine;
private int joinX;
private int joinY;
internal override void Run(Paint paint, Window canvas, MouseState mouseState, int mouseX, int mouseY)
{
if (mouseState == MouseState.Left)
{
if (joinLine)
{
canvas.DrawLine(joinX, joinY, mouseX, mouseY, paint.SelectedColor);
}
else
{
canvas.DrawPoint(mouseX, mouseY, paint.SelectedColor);
}
joinLine = true;
joinX = mouseX;
joinY = mouseY;
}
else
{
joinLine = false;
}
}
internal override void Deselected()
{
joinLine = false;
}
}
}

296
Gui/Apps/Settings.cs Normal file
View File

@@ -0,0 +1,296 @@
using Cosmos.System.Graphics;
using CMLeonOS;
using CMLeonOS.Gui.UILib;
using System.Drawing;
namespace CMLeonOS.Gui.Apps
{
internal class Settings : Process
{
internal Settings() : base("Settings", ProcessType.Application) { }
AppWindow window;
Window currentCategoryWindow;
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")]
private static byte[] _iconBytes_User;
internal static Bitmap Icon_User = new Bitmap(_iconBytes_User);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Settings.Admin.bmp")]
private static byte[] _iconBytes_Admin;
internal static Bitmap Icon_Admin = new Bitmap(_iconBytes_Admin);
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Settings.Info.bmp")]
private static byte[] _iconBytes_Info;
internal static Bitmap Icon_Info = new Bitmap(_iconBytes_Info);
}
private void CategorySelected(int index)
{
switch (index)
{
case 0:
ShowAppearanceCategory();
break;
case 1:
ShowDisplayCategory();
break;
case 2:
ShowDateTimeCategory();
break;
case 3:
ShowUsersCategory();
break;
case 4:
ShowMouseCategory();
break;
default:
return;
}
}
private void LeftStartButtonChanged(bool @checked)
{
settingsService.LeftHandStartButton = @checked;
}
private void TwelveHourClockChanged(bool @checked)
{
settingsService.TwelveHourClock = @checked;
}
private void ShowFpsChanged(bool @checked)
{
settingsService.ShowFps = @checked;
}
private void MouseSensitivityChanged(float value)
{
settingsService.MouseSensitivity = value;
}
private void ShowAppearanceCategory()
{
if (currentCategoryWindow != null)
{
wm.RemoveWindow(currentCategoryWindow);
}
Window appearance = new Window(this, window, 128, 0, window.Width - 128, window.Height);
currentCategoryWindow = appearance;
appearance.DrawString("Appearance Settings", Color.DarkBlue, 12, 12);
wm.AddWindow(appearance);
Switch leftStartButton = new Switch(appearance, 12, 40, 244, 16);
leftStartButton.Text = "Left-hand start button";
leftStartButton.Checked = settingsService.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.CheckBoxChanged = ShowFpsChanged;
wm.AddWindow(showFps);
wm.Update(window);
}
private void ShowDateTimeCategory()
{
if (currentCategoryWindow != null)
{
wm.RemoveWindow(currentCategoryWindow);
}
Window dateTime = new Window(this, window, 128, 0, window.Width - 128, window.Height);
currentCategoryWindow = dateTime;
dateTime.DrawString("Date & Time Settings", Color.DarkBlue, 12, 12);
wm.AddWindow(dateTime);
Switch twelveHourClock = new Switch(dateTime, 12, 40, 244, 16);
twelveHourClock.Text = "12-hour clock";
twelveHourClock.Checked = settingsService.TwelveHourClock;
twelveHourClock.CheckBoxChanged = TwelveHourClockChanged;
wm.AddWindow(twelveHourClock);
AppMetadata calendarApp = AppManager.GetAppMetadata("Calendar");
Button openCalendar = new Button(dateTime, 12, 68, 160, 20);
openCalendar.Text = "Open Calendar";
openCalendar.Image = calendarApp.Icon.Resize(20, 20);
openCalendar.ImageLocation = Button.ButtonImageLocation.Left;
openCalendar.OnClick = (int x, int y) =>
{
calendarApp.Start(wm);
};
wm.AddWindow(openCalendar);
wm.Update(window);
}
private void ShowDisplayCategory()
{
if (currentCategoryWindow != null)
{
wm.RemoveWindow(currentCategoryWindow);
}
Window display = new Window(this, window, 128, 0, window.Width - 128, window.Height);
currentCategoryWindow = display;
display.DrawString("Display Settings", Color.DarkBlue, 12, 12);
wm.AddWindow(display);
Table resolutionsTable = new Table(display, 12, 40, display.Width - 24, display.Height - 12 - 16 - 12 - 12 - 16 - 12);
resolutionsTable.AllowDeselection = false;
for (int i = 0; i < wm.AvailableModes.Count; i++)
{
Mode mode = wm.AvailableModes[i];
resolutionsTable.Cells.Add(new TableCell($"{mode.Width}x{mode.Height}"));
if (mode.Equals(settingsService.Mode))
{
resolutionsTable.SelectedCellIndex = i;
}
}
resolutionsTable.Render();
resolutionsTable.TableCellSelected = (int index) =>
{
Mode mode = wm.AvailableModes[index];
settingsService.Mode = mode;
settingsService.Flush();
MessageBox messageBox = new MessageBox(this, "Restart Required", "Restart your PC to apply changes.");
messageBox.Show();
};
wm.AddWindow(resolutionsTable);
display.DrawImageAlpha(Icons.Icon_Info, 12, window.Height - 16 - 12);
display.DrawString("Select a screen resolution.", Color.Gray, 36, window.Height - 16 - 12);
wm.AddWindow(display);
wm.Update(display);
}
private void ShowUsersCategory()
{
if (currentCategoryWindow != null)
{
wm.RemoveWindow(currentCategoryWindow);
}
Window users = new Window(this, window, 128, 0, window.Width - 128, window.Height);
currentCategoryWindow = users;
users.DrawString("Users", Color.DarkBlue, 12, 12);
users.DrawImageAlpha(Icons.Icon_Info, 12, window.Height - 16 - 12);
users.DrawString("Double-click on a user for info.", Color.Gray, 36, window.Height - 16 - 12);
wm.AddWindow(users);
Table usersTable = new Table(users, 12, 40, users.Width - 24, users.Height - 40 - 12 - 16 - 12);
foreach (User user in UserSystem.GetUsers())
{
usersTable.Cells.Add(new TableCell(user.Admin ? Icons.Icon_Admin : Icons.Icon_User, user.Username, tag: user));
}
usersTable.OnDoubleClick = (int x, int y) =>
{
if (usersTable.SelectedCellIndex != -1)
{
User user = (User)usersTable.Cells[usersTable.SelectedCellIndex].Tag;
AppWindow userDetail = new AppWindow(this, 256, 256, 256, 192);
userDetail.Title = user.Username;
wm.AddWindow(userDetail);
userDetail.DrawFilledRectangle(0, 0, userDetail.Width, 40, Color.DarkBlue);
userDetail.DrawImageAlpha(user.Admin ? Icons.Icon_Admin : Icons.Icon_User, 12, 12);
userDetail.DrawString($"User: {user.Username}", Color.White, 36, 12);
userDetail.DrawString($"Role: {(user.Admin ? "Admin" : "User")}", Color.Black, 12, 48);
userDetail.DrawString($"Unread messages: {user.Messages.Count}", Color.Black, 12, 76);
Button ok = new Button(userDetail, userDetail.Width - 80 - 12, userDetail.Height - 20 - 12, 80, 20);
ok.Text = "OK";
ok.OnClick = (int x, int y) =>
{
wm.RemoveWindow(userDetail);
};
wm.AddWindow(ok);
wm.Update(userDetail);
}
};
usersTable.Render();
wm.AddWindow(usersTable);
wm.Update(window);
}
private void ShowMouseCategory()
{
if (currentCategoryWindow != null)
{
wm.RemoveWindow(currentCategoryWindow);
}
Window mouse = new Window(this, window, 128, 0, window.Width - 128, window.Height);
currentCategoryWindow = mouse;
mouse.DrawString("Mouse Settings", Color.DarkBlue, 12, 12);
wm.AddWindow(mouse);
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);
mouseSensitivity.Changed = MouseSensitivityChanged;
wm.AddWindow(mouseSensitivity);
wm.Update(window);
}
#region Process
public override void Start()
{
base.Start();
window = new AppWindow(this, 256, 256, 448, 272);
window.Closing = TryStop;
window.Icon = AppManager.GetAppMetadata("Settings").Icon;
wm.AddWindow(window);
window.Title = "Settings";
Table categoryTable = new Table(window, 0, 0, 128, window.Height);
categoryTable.TextAlignment = Alignment.Middle;
categoryTable.TableCellSelected = CategorySelected;
categoryTable.SelectedCellIndex = 0;
categoryTable.AllowDeselection = false;
categoryTable.CellHeight = 24;
/*categoryTable.Border = categoryTable.Background;
categoryTable.SelectedBorder = categoryTable.SelectedBackground;*/
categoryTable.Cells.Add(new TableCell("Appearance"));
categoryTable.Cells.Add(new TableCell("Display"));
categoryTable.Cells.Add(new TableCell("Date & Time"));
categoryTable.Cells.Add(new TableCell("Users"));
categoryTable.Cells.Add(new TableCell("Mouse"));
categoryTable.Render();
wm.AddWindow(categoryTable);
ShowAppearanceCategory();
wm.Update(window);
}
public override void Run()
{
}
#endregion
}
}

161
Gui/Apps/Stopwatch.cs Normal file
View File

@@ -0,0 +1,161 @@
using CMLeonOS;
using CMLeonOS.Gui.SmoothMono;
using CMLeonOS.Gui.UILib;
using System;
using System.Drawing;
namespace CMLeonOS.Gui.Apps
{
internal class Stopwatch : Process
{
internal Stopwatch() : base("Stopwatch", ProcessType.Application) { }
AppWindow window;
Button startStopButton;
Button lapResetButton;
Table lapTable;
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
private const string format = @"hh\:mm\:ss";
private readonly Color background = Color.FromArgb(56, 56, 71);
private bool stopwatchRunning = false;
DateTime startTime;
DateTime lastLap;
TimeSpan elapsed = TimeSpan.Zero;
int lastSecond;
private void UpdateWindow()
{
window.Clear(background);
string text;
text = elapsed.ToString(format);
window.DrawString(text, System.Drawing.Color.White, (window.Width / 2) - ((text.Length * FontData.Width) / 2), 8);
wm.Update(window);
}
private void StartStopwatch()
{
if (stopwatchRunning) return;
stopwatchRunning = true;
startTime = DateTime.Now;
lastLap = startTime;
lastSecond = startTime.Second;
startStopButton.Text = "Stop";
lapResetButton.Text = "Lap";
}
private void StopStopwatch()
{
if (!stopwatchRunning) return;
stopwatchRunning = false;
UpdateWindow();
startStopButton.Text = "Start";
lapResetButton.Text = "Reset";
}
private void Lap()
{
DateTime now = DateTime.Now;
TableCell cell = new TableCell((now - lastLap).ToString(format));
lapTable.Cells.Add(cell);
lapTable.ScrollToBottom();
lapTable.Render();
wm.Update(lapTable);
lastLap = DateTime.Now;
}
private void Reset()
{
elapsed = TimeSpan.Zero;
lapTable.Cells.Clear();
lapTable.Render();
wm.Update(lapTable);
UpdateWindow();
}
public override void Start()
{
base.Start();
window = new AppWindow(this, 256, 256, 160, 160);
wm.AddWindow(window);
window.Title = "Stopwatch";
window.Icon = AppManager.GetAppMetadata("Stopwatch").Icon;
window.Closing = TryStop;
startStopButton = new Button(window, window.Width / 2, window.Height - 24, window.Width / 2, 24);
startStopButton.Text = "Start";
startStopButton.OnClick = (int x, int y) =>
{
if (stopwatchRunning)
{
StopStopwatch();
}
else
{
StartStopwatch();
}
};
wm.AddWindow(startStopButton);
lapResetButton = new Button(window, 0, window.Height - 24, window.Width / 2, 24);
lapResetButton.Text = "Reset";
lapResetButton.OnClick = (int x, int y) =>
{
if (stopwatchRunning)
{
Lap();
}
else
{
Reset();
}
};
wm.AddWindow(lapResetButton);
int lapTableY = 8 + FontData.Height + 8;
lapTable = new Table(window, 0, lapTableY, window.Width, window.Height - lapTableY - 24);
lapTable.Background = Color.FromArgb(80, 80, 102);
lapTable.Border = background;
lapTable.Foreground = Color.FromArgb(185, 185, 234);
lapTable.TextAlignment = Alignment.Middle;
lapTable.AllowSelection = false;
lapTable.CellHeight = 20;
lapTable.ScrollbarThickness = 15;
lapTable.Render();
wm.AddWindow(lapTable);
UpdateWindow();
}
public override void Run()
{
int second = DateTime.Now.Second;
if (lastSecond != second)
{
lastSecond = second;
if (stopwatchRunning)
{
elapsed = DateTime.Now - startTime;
}
UpdateWindow();
}
}
}
}

82
Gui/Apps/Tasks.cs Normal file
View File

@@ -0,0 +1,82 @@
using CMLeonOS;
using CMLeonOS.Gui.UILib;
using System;
using System.Drawing;
namespace CMLeonOS.Gui.Apps
{
internal class Tasks : Process
{
internal Tasks() : base("Tasks", ProcessType.Application) { }
AppWindow window;
Table table;
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
int lastSecond = DateTime.Now.Second;
private void PopulateTable()
{
table.Cells.Clear();
foreach (Process process in ProcessManager.Processes)
{
table.Cells.Add(new TableCell(process.Name));
}
table.Render();
}
private void EndTaskClicked(int x, int y)
{
if (table.SelectedCellIndex != -1 && table.SelectedCellIndex < ProcessManager.Processes.Count)
{
if (UserSystem.CurrentLoggedInUser == null || !UserSystem.CurrentLoggedInUser.Admin)
{
MessageBox messageBox = new MessageBox(this, Name, "You must be an admin to end tasks.");
messageBox.Show();
return;
}
ProcessManager.Processes[table.SelectedCellIndex].TryStop();
ProcessManager.Sweep();
table.SelectedCellIndex = -1;
PopulateTable();
}
}
public override void Start()
{
base.Start();
window = new AppWindow(this, 256, 256, 384, 256);
wm.AddWindow(window);
window.Title = "Tasks";
window.Icon = AppManager.GetAppMetadata("Tasks").Icon;
window.Closing = TryStop;
window.Clear(Color.Gray);
table = new Table(window, 12, 12, window.Width - 24, window.Height - 24 - 20 - 12);
PopulateTable();
wm.AddWindow(table);
Button endTask = new Button(window, window.Width - 100 - 12, window.Height - 20 - 12, 100, 20);
endTask.Text = "End Task";
endTask.OnClick = EndTaskClicked;
wm.AddWindow(endTask);
wm.Update(window);
}
public override void Run()
{
DateTime now = DateTime.Now;
if (lastSecond != now.Second)
{
PopulateTable();
lastSecond = now.Second;
}
}
}
}

39
Gui/Asc16.cs Normal file

File diff suppressed because one or more lines are too long

49
Gui/BitmapExtensions.cs Normal file
View File

@@ -0,0 +1,49 @@
using Cosmos.System.Graphics;
using System;
namespace CMLeonOS.Gui
{
internal static class BitmapExtensions
{
internal static Bitmap Resize(this Bitmap bmp, uint width, uint height)
{
if (bmp.Width == width && bmp.Height == height)
{
return bmp;
}
if (bmp.Depth != ColorDepth.ColorDepth32)
{
throw new Exception("Resize can only resize images with a colour depth of 32.");
}
Bitmap res = new Bitmap(width, height, ColorDepth.ColorDepth32);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
double xDouble = (double)x / (double)width;
double yDouble = (double)y / (double)height;
uint origX = (uint)((double)bmp.Width * xDouble);
uint origY = (uint)((double)bmp.Height * yDouble);
res.RawData[y * width + x] = bmp.RawData[(origY * bmp.Width) + origX];
}
}
return res;
}
internal static Bitmap ResizeWidthKeepRatio(this Bitmap bmp, uint width)
{
return Resize(bmp, width, (uint)((double)bmp.Height * ((double)width / (double)bmp.Width)));
}
internal static Bitmap ResizeHeightKeepRatio(this Bitmap bmp, uint height)
{
return Resize(bmp, (uint)((double)bmp.Width * ((double)height / (double)bmp.Height)), height);
}
}
}

8
Gui/CursorType.cs Normal file
View File

@@ -0,0 +1,8 @@
namespace CMLeonOS.Gui
{
internal enum CursorType
{
Cursor,
WaitCursor
}
}

77
Gui/Gui.cs Normal file
View File

@@ -0,0 +1,77 @@
using CMLeonOS;
using CMLeonOS.Logger;
using System;
using System.Threading;
namespace CMLeonOS.Gui
{
internal static class Gui
{
private static bool guiRunning = false;
private static WindowManager windowManager;
internal static bool StartGui()
{
Console.Clear();
Console.CursorVisible = false;
windowManager = new WindowManager();
Logger.Logger.Instance.Info("Gui", "GUI starting.");
if (Cosmos.Core.CPU.GetAmountOfRAM() < 1000)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("Not enough system memory is available to run the GUI.");
Console.WriteLine("At least 1 GB should be allocated.");
Console.ResetColor();
Console.Write("Continue anyway? [y/N]");
if (Console.ReadKey(true).Key != ConsoleKey.Y)
{
return false;
}
}
Console.WriteLine("Loading apps...");
Thread.Sleep(1000);
AppManager.LoadAllApps();
ProcessManager.AddProcess(windowManager);
ProcessManager.AddProcess(windowManager, new SettingsService()).Start();
windowManager.Start();
ProcessManager.AddProcess(windowManager, new Sound.SoundService()).Start();
Console.WriteLine("Starting lock screen...");
ProcessManager.AddProcess(windowManager, new ShellComponents.Lock()).Start();
guiRunning = true;
// 进入 GUI 事件循环
RunGuiLoop();
return true;
}
private static void RunGuiLoop()
{
while (guiRunning)
{
ProcessManager.Yield();
System.Threading.Thread.Sleep(1);
}
}
internal static void StopGui()
{
guiRunning = false;
if (windowManager != null)
{
windowManager.Stop();
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
Gui/Resources/Check.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

BIN
Gui/Resources/Close.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 KiB

BIN
Gui/Resources/Cursor.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Gui/Resources/Files/Up.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 B

BIN
Gui/Resources/Lock/Key.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
Gui/Resources/Lock/User.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Gui/Resources/Logs/Info.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Gui/Resources/Maximise.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
Gui/Resources/Minimise.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
Gui/Resources/Restore.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Binary file not shown.

BIN
Gui/Resources/Start.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
Gui/Resources/Start_old.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Gui/Resources/SwitchOff.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
Gui/Resources/SwitchOn.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Some files were not shown because too many files have changed in this diff Show More