Initial commit

This commit is contained in:
Stone_Red
2026-06-08 12:30:37 +02:00
commit 2ba87a113d
310 changed files with 4457 additions and 0 deletions
+60
View File
@@ -0,0 +1,60 @@
using System;
namespace RemSox.UI.GUI.CLI;
public static class CommandManager
{
private static readonly Dictionary<string, ICommand> commands = new(StringComparer.OrdinalIgnoreCase);
public static void RegisterCommand(ICommand command)
{
commands[command.Name] = command;
}
public static void RegisterCommands(IEnumerable<ICommand> commandsToRegister)
{
foreach (ICommand command in commandsToRegister)
{
RegisterCommand(command);
}
}
public static IEnumerable<ICommand> GetCommands()
{
return commands.Values.OrderBy(command => command.Name);
}
public static bool TryExecute(string input)
{
string trimmedInput = input.Trim();
if (trimmedInput.Length == 0)
{
return false;
}
foreach (KeyValuePair<string, ICommand> entry in commands
.OrderByDescending(entry => entry.Key.Length))
{
string commandName = entry.Key;
if (!trimmedInput.Equals(commandName, StringComparison.OrdinalIgnoreCase) &&
!trimmedInput.StartsWith(commandName + " ", StringComparison.OrdinalIgnoreCase))
{
continue;
}
string? arguments = null;
if (trimmedInput.Length > commandName.Length)
{
arguments = trimmedInput.Substring(commandName.Length).TrimStart();
}
entry.Value.Execute(arguments);
return true;
}
return false;
}
}
+15
View File
@@ -0,0 +1,15 @@
using System;
namespace RemSox.UI.GUI.CLI.Commands;
public sealed class ClearCommand : ICommand
{
public string Name => "clear";
public string Description => "Clear the screen";
public void Execute(string? arguments)
{
Console.Clear();
}
}
+16
View File
@@ -0,0 +1,16 @@
using System;
namespace RemSox.UI.GUI.CLI.Commands;
public sealed class HaltCommand : ICommand
{
public string Name => "halt";
public string Description => "Halt the system";
public void Execute(string? arguments)
{
Console.WriteLine("Halting system...");
Environment.Exit(0);
}
}
+20
View File
@@ -0,0 +1,20 @@
using System;
namespace RemSox.UI.GUI.CLI.Commands;
public sealed class HelpCommand : ICommand
{
public string Name => "help";
public string Description => "Show this help message";
public void Execute(string? arguments)
{
Console.WriteLine("Available commands:");
foreach (ICommand command in CommandManager.GetCommands())
{
Console.WriteLine($" {command.Name,-12} - {command.Description}");
}
}
}
+63
View File
@@ -0,0 +1,63 @@
using System;
using RemSox.Processing;
namespace RemSox.UI.GUI.CLI.Commands;
public sealed class SpawnTestProcessCommand : ICommand
{
public string Name => "spawn test";
public string Description => "Spawn the test process";
public void Execute(string? arguments)
{
int processId = ProcessManager.SpawnProcess<TestProcess>();
Console.WriteLine($"Spawned TestProcess with ID {processId}");
}
}
public sealed class ListProcessesCommand : ICommand
{
public string Name => "ps";
public string Description => "List running processes";
public void Execute(string? arguments)
{
IEnumerable<Process> processes = ProcessManager.GetAllProcesses();
Console.WriteLine("Running processes:");
foreach (Process process in processes)
{
Console.WriteLine($" ID: {process.Id}, Name: {process.Name}");
}
}
}
public sealed class StopProcessCommand : ICommand
{
public string Name => "stop";
public string Description => "Stop a process by ID";
public void Execute(string? arguments)
{
string? idText = arguments;
if (string.IsNullOrWhiteSpace(idText))
{
Console.WriteLine("Usage: stop <process-id>");
return;
}
if (int.TryParse(idText, out int processId))
{
ProcessManager.StopProcess(processId);
Console.WriteLine($"Stopped process with ID {processId}");
return;
}
Console.WriteLine("Invalid process ID");
}
}
+10
View File
@@ -0,0 +1,10 @@
namespace RemSox.UI.GUI.CLI;
public interface ICommand
{
string Name { get; }
string Description { get; }
void Execute(string? arguments);
}
+65
View File
@@ -0,0 +1,65 @@
using System;
using System.Drawing;
using Cosmos.Kernel.System.Graphics;
namespace RemSox.UI.GUI.Rendering;
public sealed class CanvasRenderSource : IRenderSource
{
public void Render(IEnumerable<RenderCommand> commands)
{
Canvas canvas = FullScreenCanvas.GetFullScreenCanvas();
foreach (RenderCommand command in commands)
{
if (command.ElementType == "Window")
{
RenderWindow(canvas, command);
continue;
}
if (command.ElementType == "Circle")
{
RenderCircle(canvas, command);
}
}
}
private static void RenderWindow(Canvas canvas, RenderCommand command)
{
int x = command.Position.X;
int y = command.Position.Y;
Size size = command.Properties.TryGetValue(nameof(Size), out object? rawSize) && rawSize is Size windowSize
? windowSize
: new Size(160, 120);
bool isFocused = command.Properties.TryGetValue(nameof(Windows.Window.IsFocused), out object? rawFocused) && rawFocused is bool focused && focused;
Color borderColor = isFocused ? Color.White : Color.DarkGray;
Color bodyColor = Color.FromArgb(32, 32, 32);
Color titleColor = isFocused ? Color.FromArgb(0, 120, 215) : Color.FromArgb(80, 80, 80);
canvas.DrawFilledRectangle(bodyColor, x, y, size.Width, size.Height);
canvas.DrawFilledRectangle(titleColor, x, y, size.Width, 18);
canvas.DrawRectangle(borderColor, x, y, size.Width, size.Height);
}
private static void RenderCircle(Canvas canvas, RenderCommand command)
{
Color color = command.Properties.TryGetValue(nameof(Color), out object? rawColor) && rawColor is Color circleColor
? circleColor
: Color.White;
int radius = command.Properties.TryGetValue(nameof(Radius), out object? rawRadius) && rawRadius is int circleRadius
? circleRadius
: 10;
int centerX = command.Position.X + radius;
int centerY = command.Position.Y + radius;
canvas.DrawFilledCircle(color, centerX, centerY, radius);
}
private static string Radius => nameof(Radius);
}
+6
View File
@@ -0,0 +1,6 @@
namespace RemSox.UI.GUI.Rendering;
public interface IRenderSource
{
public void Render(IEnumerable<RenderCommand> commands);
}
+12
View File
@@ -0,0 +1,12 @@
using System;
using System.Drawing;
namespace RemSox.UI.GUI.Rendering;
public class RenderCommand
{
public required int ElementId { get; set; }
public required string ElementType { get; set; }
public required Point Position { get; set; }
public required IReadOnlyDictionary<string, object?> Properties { get; set; }
}
+19
View File
@@ -0,0 +1,19 @@
using System;
using System.Drawing;
namespace RemSox.UI.GUI.UIEelements;
public abstract class Control(string type) : UIElement(type)
{
public Color BackgroundColor
{
get;
set => SetProperty(nameof(BackgroundColor), ref field, value);
} = Color.LightGray;
public Size Size
{
get;
set => SetProperty(nameof(Size), ref field, value);
}
}
+12
View File
@@ -0,0 +1,12 @@
using System.Drawing;
namespace RemSox.UI.GUI.UIEelements;
public abstract class Shape(string type) : UIElement(type)
{
public Color Color
{
get;
set => SetProperty(nameof(Color), ref field, value);
}
}
+12
View File
@@ -0,0 +1,12 @@
using System.Drawing;
namespace RemSox.UI.GUI.UIEelements.Shapes;
public class Circle() : Shape("Circle")
{
public int Radius
{
get;
set => SetProperty(nameof(Radius), ref field, value);
}
}
+19
View File
@@ -0,0 +1,19 @@
namespace RemSox.UI.GUI.UIEelements;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using RemSox.Utils;
public abstract class UIElement(string type) : ChangedPropertiesTracker
{
public int Id { get; init; }
public string Type { get; set; } = type;
public Point Position
{
get;
set => SetProperty(nameof(Position), ref field, value);
}
}
+167
View File
@@ -0,0 +1,167 @@
using System;
using System.Drawing;
using System.Reflection;
using RemSox.UI.GUI.Rendering;
using RemSox.UI.GUI.UIEelements;
namespace RemSox.UI.GUI.Windows;
public sealed class Window(string title, int processId, int id, IRenderSource renderSource)
{
public int Id { get; } = id;
public int ProcessId { get; } = processId;
public string Title { get; set; } = title;
public bool AutoFlush { get; set; } = false;
public bool IsFocused
{
get => WindowManager.IsWindowFocused(this);
set
{
WindowManager.FocusWindow(value ? this : null);
}
}
public bool IsVisible { get; set; } = true;
public bool IsResizable { get; set; } = true;
public bool IsDraggable { get; set; } = true;
public Point Position { get; set; }
public Size Size { get; set; }
public bool IsDragging => isDragging;
private readonly Dictionary<int, UIElement> uiElements = [];
private int nextUIElementId = 1;
private bool isDragging;
private Point dragOffset;
public T CreateUIElement<T>(Action<T>? options = null) where T : UIElement, new()
{
int uiElementId = GetNextUIElementId();
T uiElement = new()
{
Id = uiElementId
};
options?.Invoke(uiElement);
uiElement.PropertyChanged += (sender, args) =>
{
if (AutoFlush)
{
Flush();
}
};
if (AutoFlush)
{
Flush();
}
uiElements.Add(uiElementId, uiElement);
return uiElement;
}
public void Flush()
{
List<RenderCommand> commands = [];
if (IsVisible)
{
commands.Add(new RenderCommand
{
ElementId = Id,
ElementType = "Window",
Position = Position,
Properties = new Dictionary<string, object?>
{
[nameof(Title)] = Title,
[nameof(Size)] = Size,
[nameof(IsFocused)] = IsFocused,
[nameof(IsResizable)] = IsResizable,
[nameof(IsDraggable)] = IsDraggable
}
});
}
foreach (UIElement element in uiElements.Values)
{
if (element.AnyPropertyChanged)
{
IReadOnlyDictionary<string, object?> changes = element.ChangedProperties;
commands.Add(new RenderCommand
{
ElementId = element.Id,
ElementType = element.Type,
Position = element.Position,
Properties = changes
});
element.ClearChangedProperties();
}
}
if (commands.Count > 0)
{
renderSource.Render(commands);
}
}
public bool TryBeginDrag(Point pointerPosition)
{
if (!IsVisible || !IsDraggable || !IsPointInTitleBar(pointerPosition))
{
return false;
}
isDragging = true;
dragOffset = new Point(pointerPosition.X - Position.X, pointerPosition.Y - Position.Y);
WindowManager.FocusWindow(this);
return true;
}
public void DragTo(Point pointerPosition)
{
if (!isDragging || !IsDraggable)
{
return;
}
Position = new Point(pointerPosition.X - dragOffset.X, pointerPosition.Y - dragOffset.Y);
Flush();
}
public void EndDrag()
{
isDragging = false;
}
private bool IsPointInTitleBar(Point pointerPosition)
{
return pointerPosition.X >= Position.X
&& pointerPosition.X < Position.X + Size.Width
&& pointerPosition.Y >= Position.Y
&& pointerPosition.Y < Position.Y + 18;
}
private int GetNextUIElementId()
{
return nextUIElementId++;
}
}
+8
View File
@@ -0,0 +1,8 @@
namespace RemSox.UI.GUI.Windows;
public enum WindowLayer
{
Background,
Normal,
Foreground
}
+105
View File
@@ -0,0 +1,105 @@
using System;
using System.Drawing;
using RemSox.Processing;
using RemSox.UI.GUI.Rendering;
namespace RemSox.UI.GUI.Windows;
public static class WindowManager
{
// Process ID to list of windows
private static readonly Dictionary<int, List<Window>> windows = [];
private static int nextWindowId = 1;
private static Window? focusedWindow;
private static readonly MuliRenderSource renderSource = new([]);
public static void AddRenderSource(IRenderSource source) => renderSource.AddSource(source);
public static void RemoveRenderSource(IRenderSource source) => renderSource.RemoveSource(source);
public static Window CreateWindow(Process process, string title, Point position, Size size)
{
Window window = new(title, process.Id, GetNextWindowId(), renderSource)
{
Position = position,
Size = size
};
if (!windows.ContainsKey(process.Id))
{
windows[process.Id] = [];
}
windows[process.Id].Add(window);
return window;
}
public static void CloseWindow(Window window)
{
if (windows.TryGetValue(window.ProcessId, out var processWindows))
{
processWindows.Remove(window);
}
}
public static List<Window> GetWindowsForProcess(Process process)
{
if (windows.TryGetValue(process.Id, out var processWindows))
{
return processWindows;
}
return [];
}
public static void CloseWindowsForProcess(Process process)
{
if (windows.ContainsKey(process.Id))
{
windows.Remove(process.Id);
}
}
public static void FocusWindow(Window? window)
{
if (focusedWindow == window)
{
return;
}
Window? previousFocusedWindow = focusedWindow;
focusedWindow = window;
previousFocusedWindow?.Flush();
focusedWindow?.Flush();
}
public static bool IsWindowFocused(Window window)
{
return focusedWindow == window;
}
private static int GetNextWindowId()
{
return nextWindowId++;
}
sealed private class MuliRenderSource(List<IRenderSource> sources) : IRenderSource
{
public void AddSource(IRenderSource source) => sources.Add(source);
public void RemoveSource(IRenderSource source) => sources.Remove(source);
public void Render(IEnumerable<RenderCommand> commands)
{
foreach (IRenderSource source in sources)
{
source.Render(commands);
}
}
}
}