mirror of
https://github.com/Stone-Red-Code/RemSox.git
synced 2026-09-04 00:56:19 +02:00
Initial commit
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace RemSox.UI.GUI.CLI;
|
||||
|
||||
public interface ICommand
|
||||
{
|
||||
string Name { get; }
|
||||
|
||||
string Description { get; }
|
||||
|
||||
void Execute(string? arguments);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace RemSox.UI.GUI.Rendering;
|
||||
|
||||
public interface IRenderSource
|
||||
{
|
||||
public void Render(IEnumerable<RenderCommand> commands);
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace RemSox.UI.GUI.Windows;
|
||||
|
||||
public enum WindowLayer
|
||||
{
|
||||
Background,
|
||||
Normal,
|
||||
Foreground
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user