diff --git a/Kernel.cs b/Kernel.cs index 4c69634..97b1272 100644 --- a/Kernel.cs +++ b/Kernel.cs @@ -20,7 +20,7 @@ namespace RemSox; /// public class Kernel : Sys.Kernel { - private static Window? activeDragWindow = null; + private static Window? activeInteractWindow = null; private static Point lastPointerPosition = Point.Empty; @@ -48,7 +48,11 @@ public class Kernel : Sys.Kernel Sys.Mouse.MouseManager.Initialize(); Sys.Keyboard.KeyboardManager.Initialize(); - ProcessManager.SpawnProcess(); + for (int i = 0; i < 5; i++) + { + ProcessManager.SpawnProcess(); + } + Console.WriteLine(CosmosFeatures.MouseEnabled); Console.WriteLine(CosmosFeatures.KeyboardEnabled); @@ -87,16 +91,16 @@ public class Kernel : Sys.Kernel if (leftButtonDown && !wasLeftButtonDown) { - activeDragWindow = TryBeginDrag(pointerPosition); + activeInteractWindow = TryBeginInteract(pointerPosition); } - else if (leftButtonDown && activeDragWindow is not null) + else if (leftButtonDown && activeInteractWindow is not null) { - activeDragWindow.DragTo(pointerPosition); + activeInteractWindow.UpdateInteraction(pointerPosition); } - else if (!leftButtonDown && activeDragWindow is not null) + else if (!leftButtonDown && activeInteractWindow is not null) { - activeDragWindow.EndDrag(); - activeDragWindow = null; + activeInteractWindow.EndInteraction(); + activeInteractWindow = null; } wasLeftButtonDown = leftButtonDown; @@ -108,7 +112,7 @@ public class Kernel : Sys.Kernel lastPointerPosition = pointerPosition; } - private static Window? TryBeginDrag(Point pointerPosition) + private static Window? TryBeginInteract(Point pointerPosition) { foreach (Processing.Process process in ProcessManager.GetAllProcesses()) { @@ -118,7 +122,7 @@ public class Kernel : Sys.Kernel { Window window = windows[index]; - if (window.TryBeginDrag(pointerPosition)) + if (window.TryBeginInteract(pointerPosition)) { return window; } diff --git a/Processing/ProcessManager.cs b/Processing/ProcessManager.cs index d36b897..5ba8800 100644 --- a/Processing/ProcessManager.cs +++ b/Processing/ProcessManager.cs @@ -1,10 +1,11 @@ using System; +using System.Collections.Concurrent; namespace RemSox.Processing; public static class ProcessManager { - private static readonly Dictionary processes = []; + private static readonly ConcurrentDictionary processes = new(); private static int nextProcessId = 0; @@ -19,7 +20,7 @@ public static class ProcessManager Thread thread = new(process.Run); - processes.Add(id, (process, thread)); + processes.TryAdd(id, (process, thread)); thread.Start(); @@ -33,7 +34,7 @@ public static class ProcessManager entry.Process.RequestStop(); - processes.Remove(processId); + processes.TryRemove(processId, out _); } public static void StopAllProcesses() diff --git a/UI/GUI/Windows/Window.cs b/UI/GUI/Windows/Window.cs index 1d5d87a..6a4379d 100644 --- a/UI/GUI/Windows/Window.cs +++ b/UI/GUI/Windows/Window.cs @@ -35,14 +35,16 @@ public sealed class Window(string title, int processId, int id, IRenderSource re public Size Size { get; set; } - public bool IsDragging => isDragging; + public bool IsDragging => currentInteraction == InteractionMode.Drag; private readonly Dictionary uiElements = []; private int nextUIElementId = 1; - private bool isDragging; - + private enum InteractionMode { None, Drag, ResizeTop, ResizeBottom, ResizeLeft, ResizeRight, ResizeTopLeft, ResizeTopRight, ResizeBottomLeft, ResizeBottomRight } + private InteractionMode currentInteraction = InteractionMode.None; + private Rectangle interactionStartBounds; + private Point interactionStartPointer; private Point dragOffset; private Point lastRenderedPosition = new Point(-1, -1); @@ -149,44 +151,114 @@ public sealed class Window(string title, int processId, int id, IRenderSource re } } - public bool TryBeginDrag(Point pointerPosition) + public bool TryBeginInteract(Point pointerPosition) { - if (!IsVisible || !IsDraggable || !IsPointInTitleBar(pointerPosition)) + if (!IsVisible) { return false; } - isDragging = true; - dragOffset = new Point(pointerPosition.X - Position.X, pointerPosition.Y - Position.Y); + const int resizeMargin = 5; - WindowManager.FocusWindow(this); + bool onLeft = pointerPosition.X >= Position.X && pointerPosition.X <= Position.X + resizeMargin; + bool onRight = pointerPosition.X >= Position.X + Size.Width - resizeMargin && pointerPosition.X <= Position.X + Size.Width; + bool onTop = pointerPosition.Y >= Position.Y && pointerPosition.Y <= Position.Y + resizeMargin; + bool onBottom = pointerPosition.Y >= Position.Y + Size.Height - resizeMargin && pointerPosition.Y <= Position.Y + Size.Height; - return true; - } + bool inBounds = pointerPosition.X >= Position.X && pointerPosition.X <= Position.X + Size.Width && + pointerPosition.Y >= Position.Y && pointerPosition.Y <= Position.Y + Size.Height; - public void DragTo(Point pointerPosition) - { - if (!isDragging || !IsDraggable) + currentInteraction = InteractionMode.None; + + if (IsResizable) { - return; + if (onTop && onLeft) currentInteraction = InteractionMode.ResizeTopLeft; + else if (onTop && onRight) currentInteraction = InteractionMode.ResizeTopRight; + else if (onBottom && onLeft) currentInteraction = InteractionMode.ResizeBottomLeft; + else if (onBottom && onRight) currentInteraction = InteractionMode.ResizeBottomRight; + else if (onLeft && inBounds) currentInteraction = InteractionMode.ResizeLeft; + else if (onRight && inBounds) currentInteraction = InteractionMode.ResizeRight; + else if (onTop && inBounds) currentInteraction = InteractionMode.ResizeTop; + else if (onBottom && inBounds) currentInteraction = InteractionMode.ResizeBottom; } - int newX = pointerPosition.X - dragOffset.X; - int newY = pointerPosition.Y - dragOffset.Y; + if (currentInteraction == InteractionMode.None && IsDraggable && IsPointInTitleBar(pointerPosition)) + { + currentInteraction = InteractionMode.Drag; + dragOffset = new Point(pointerPosition.X - Position.X, pointerPosition.Y - Position.Y); + } - // Cosmos DrawCanvas fails to render if coordinates are negative. - // Clamp to 0,0 to prevent the window from disappearing. - newX = Math.Max(0, newX); - newY = Math.Max(0, newY); + if (currentInteraction != InteractionMode.None) + { + interactionStartBounds = new Rectangle(Position, Size); + interactionStartPointer = pointerPosition; + WindowManager.FocusWindow(this); + return true; + } - Position = new Point(newX, newY); - - Flush(); + return false; } - public void EndDrag() + public void UpdateInteraction(Point pointerPosition) { - isDragging = false; + if (currentInteraction == InteractionMode.Drag) + { + int newX = pointerPosition.X - dragOffset.X; + int newY = pointerPosition.Y - dragOffset.Y; + + // Cosmos DrawCanvas fails to render if coordinates are negative. + // Clamp to 0,0 to prevent the window from disappearing. + newX = Math.Max(0, newX); + newY = Math.Max(0, newY); + + Position = new Point(newX, newY); + Flush(); + } + else if (currentInteraction != InteractionMode.None) + { + int dx = pointerPosition.X - interactionStartPointer.X; + int dy = pointerPosition.Y - interactionStartPointer.Y; + + int newX = interactionStartBounds.X; + int newY = interactionStartBounds.Y; + int newW = interactionStartBounds.Width; + int newH = interactionStartBounds.Height; + + const int minWidth = 100; + const int minHeight = 50; + + if (currentInteraction == InteractionMode.ResizeRight || currentInteraction == InteractionMode.ResizeBottomRight || currentInteraction == InteractionMode.ResizeTopRight) + { + newW = Math.Max(minWidth, interactionStartBounds.Width + dx); + } + if (currentInteraction == InteractionMode.ResizeBottom || currentInteraction == InteractionMode.ResizeBottomRight || currentInteraction == InteractionMode.ResizeBottomLeft) + { + newH = Math.Max(minHeight, interactionStartBounds.Height + dy); + } + if (currentInteraction == InteractionMode.ResizeLeft || currentInteraction == InteractionMode.ResizeBottomLeft || currentInteraction == InteractionMode.ResizeTopLeft) + { + int maxDx = interactionStartBounds.Width - minWidth; + int clampedDx = Math.Min(dx, maxDx); + newX = Math.Max(0, interactionStartBounds.X + clampedDx); + newW = interactionStartBounds.Width - clampedDx; + } + if (currentInteraction == InteractionMode.ResizeTop || currentInteraction == InteractionMode.ResizeTopLeft || currentInteraction == InteractionMode.ResizeTopRight) + { + int maxDy = interactionStartBounds.Height - minHeight; + int clampedDy = Math.Min(dy, maxDy); + newY = Math.Max(0, interactionStartBounds.Y + clampedDy); + newH = interactionStartBounds.Height - clampedDy; + } + + Position = new Point(newX, newY); + Size = new Size(newW, newH); + Flush(); + } + } + + public void EndInteraction() + { + currentInteraction = InteractionMode.None; } private bool IsPointInTitleBar(Point pointerPosition) diff --git a/UI/GUI/Windows/WindowManager.cs b/UI/GUI/Windows/WindowManager.cs index b30c6b2..da7d001 100644 --- a/UI/GUI/Windows/WindowManager.cs +++ b/UI/GUI/Windows/WindowManager.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Drawing; using RemSox.Processing; using RemSox.UI.GUI.Rendering; @@ -8,7 +9,7 @@ namespace RemSox.UI.GUI.Windows; public static class WindowManager { // Process ID to list of windows - private static readonly Dictionary> windows = []; + private static readonly ConcurrentDictionary> windows = new(); private static int nextWindowId = 1; @@ -58,10 +59,7 @@ public static class WindowManager public static void CloseWindowsForProcess(Process process) { - if (windows.ContainsKey(process.Id)) - { - windows.Remove(process.Id); - } + windows.TryRemove(process.Id, out _); } public static void FocusWindow(Window? window)