diff --git a/BuildTime.txt b/BuildTime.txt index 7ab80b0..0a73e73 100644 --- a/BuildTime.txt +++ b/BuildTime.txt @@ -1 +1 @@ -2026-03-24 22:06:48 \ No newline at end of file +2026-03-25 20:01:57 \ No newline at end of file diff --git a/GitCommit.txt b/GitCommit.txt index a6ab992..8beccb1 100644 --- a/GitCommit.txt +++ b/GitCommit.txt @@ -1 +1 @@ -10e3a9d \ No newline at end of file +a0eaf70 \ No newline at end of file diff --git a/Gui/AppManager.cs b/Gui/AppManager.cs index 8569a3c..19ded6c 100644 --- a/Gui/AppManager.cs +++ b/Gui/AppManager.cs @@ -139,6 +139,7 @@ namespace CMLeonOS.Gui RegisterApp(new AppMetadata("CodeStudio", () => { return new Apps.CodeStudio.CodeStudio(); }, Icons.Icon_CodeStudio, Color.FromArgb(14, 59, 76))); RegisterApp(new AppMetadata("Image Viewer", () => { return new ImageViewer(); }, Icons.Icon_Default, Color.FromArgb(25, 25, 25))); RegisterApp(new AppMetadata("MarkIt Viewer", () => { return new MarkItViewer(); }, Icons.Icon_Default, Color.FromArgb(25, 25, 25))); + RegisterApp(new AppMetadata("Environment Variables", () => { return new EnvironmentVariables(); }, Icons.Icon_Default, Color.FromArgb(25, 25, 25))); Logger.Logger.Instance.Info("AppManager", $"{AppMetadatas.Count} apps were registered."); diff --git a/Gui/Apps/EnvironmentVariables.cs b/Gui/Apps/EnvironmentVariables.cs new file mode 100644 index 0000000..dc65ae9 --- /dev/null +++ b/Gui/Apps/EnvironmentVariables.cs @@ -0,0 +1,253 @@ +using CMLeonOS; +using CMLeonOS.Gui.UILib; +using System.Collections.Generic; +using System.Drawing; + +namespace CMLeonOS.Gui.Apps +{ + internal class EnvironmentVariables : Process + { + internal EnvironmentVariables() : base("Environment Variables", ProcessType.Application) { } + + private AppWindow window; + private Window header; + private Table variableTable; + private Button addButton; + private Button editButton; + private Button deleteButton; + private Button refreshButton; + + private readonly WindowManager wm = ProcessManager.GetProcess(); + private readonly EnvironmentVariableManager envManager = EnvironmentVariableManager.Instance; + + private readonly List rowNames = new List(); + private readonly List rowValues = new List(); + + private const int padding = 8; + private const int toolbarHeight = 32; + private const int headerHeight = 54; + private const int buttonWidth = 78; + private const int buttonHeight = 24; + + private string statusText = "Manage variables stored in 0:\\system\\env.dat"; + + private void SetStatus(string text) + { + statusText = text; + RenderHeader(); + } + + private void RenderHeader() + { + header.Clear(Color.FromArgb(235, 241, 248)); + header.DrawRectangle(0, 0, header.Width, header.Height, Color.FromArgb(180, 192, 208)); + header.DrawString("Environment Variables", Color.FromArgb(28, 38, 52), 12, 10); + header.DrawString(statusText, Color.FromArgb(97, 110, 126), 12, 30); + wm.Update(header); + } + + private void UpdateStatusFromSelection() + { + if (variableTable.SelectedCellIndex >= 0 && variableTable.SelectedCellIndex < rowNames.Count) + { + SetStatus($"Selected: {rowNames[variableTable.SelectedCellIndex]}={rowValues[variableTable.SelectedCellIndex]}"); + return; + } + + SetStatus($"Loaded {rowNames.Count} variable(s) from 0:\\system\\env.dat"); + } + + private void PopulateTable() + { + string selectedName = null; + if (variableTable.SelectedCellIndex >= 0 && variableTable.SelectedCellIndex < rowNames.Count) + { + selectedName = rowNames[variableTable.SelectedCellIndex]; + } + + rowNames.Clear(); + rowValues.Clear(); + variableTable.Cells.Clear(); + variableTable.SelectedCellIndex = -1; + + string[] variables = envManager.GetAllVariablesAsLines(); + for (int i = 0; i < variables.Length; i++) + { + string line = variables[i] ?? string.Empty; + int equalIndex = line.IndexOf('='); + string name = equalIndex >= 0 ? line.Substring(0, equalIndex) : line; + string value = equalIndex >= 0 ? line.Substring(equalIndex + 1) : string.Empty; + + rowNames.Add(name); + rowValues.Add(value); + } + + for (int i = 0; i < rowNames.Count; i++) + { + variableTable.Cells.Add(new TableCell($"{rowNames[i]}={rowValues[i]}", rowNames[i])); + } + + if (!string.IsNullOrWhiteSpace(selectedName)) + { + for (int i = 0; i < rowNames.Count; i++) + { + if (rowNames[i] == selectedName) + { + variableTable.SelectedCellIndex = i; + break; + } + } + } + + variableTable.Render(); + UpdateStatusFromSelection(); + } + + private void SelectionChanged(int index) + { + UpdateStatusFromSelection(); + } + + private void RefreshClicked(int x, int y) + { + PopulateTable(); + } + + private void AddClicked(int x, int y) + { + PromptBox namePrompt = new PromptBox(this, "Add Variable", "Enter the variable name.", "MY_VAR", (string name) => + { + string trimmedName = (name ?? string.Empty).Trim(); + if (string.IsNullOrWhiteSpace(trimmedName)) + { + SetStatus("Variable name cannot be empty."); + return; + } + + PromptBox valuePrompt = new PromptBox(this, "Add Variable", $"Enter the value for {trimmedName}.", "value", (string value) => + { + envManager.SetVariable(trimmedName, value ?? string.Empty); + PopulateTable(); + SetStatus($"Added: {trimmedName}"); + }); + valuePrompt.Show(); + }); + namePrompt.Show(); + } + + private void EditClicked(int x, int y) + { + if (variableTable.SelectedCellIndex < 0 || variableTable.SelectedCellIndex >= rowNames.Count) + { + SetStatus("Select a variable first."); + return; + } + + string selectedName = rowNames[variableTable.SelectedCellIndex]; + string selectedValue = rowValues[variableTable.SelectedCellIndex]; + PromptBox valuePrompt = new PromptBox(this, "Edit Variable", $"Enter a new value for {selectedName}.", selectedValue, (string value) => + { + envManager.SetVariable(selectedName, value ?? string.Empty); + PopulateTable(); + SetStatus($"Updated: {selectedName}"); + }); + valuePrompt.Show(); + } + + private void DeleteClicked(int x, int y) + { + if (variableTable.SelectedCellIndex < 0 || variableTable.SelectedCellIndex >= rowNames.Count) + { + SetStatus("Select a variable first."); + return; + } + + string selectedName = rowNames[variableTable.SelectedCellIndex]; + bool deleted = envManager.DeleteVariable(selectedName); + if (!deleted) + { + new MessageBox(this, "Environment Variables", "Unable to delete the selected variable.").Show(); + return; + } + + PopulateTable(); + SetStatus($"Deleted: {selectedName}"); + } + + private void Relayout() + { + int topY = padding; + addButton.MoveAndResize(window.Width - ((buttonWidth * 4) + (padding * 4)), topY, buttonWidth, buttonHeight); + editButton.MoveAndResize(window.Width - ((buttonWidth * 3) + (padding * 3)), topY, buttonWidth, buttonHeight); + deleteButton.MoveAndResize(window.Width - ((buttonWidth * 2) + (padding * 2)), topY, buttonWidth, buttonHeight); + refreshButton.MoveAndResize(window.Width - (buttonWidth + padding), topY, buttonWidth, buttonHeight); + + header.MoveAndResize(0, toolbarHeight, window.Width, headerHeight); + + int tableY = toolbarHeight + headerHeight; + variableTable.MoveAndResize(0, tableY, window.Width, window.Height - tableY); + + addButton.Render(); + editButton.Render(); + deleteButton.Render(); + refreshButton.Render(); + RenderHeader(); + variableTable.Render(); + } + + public override void Start() + { + base.Start(); + + window = new AppWindow(this, 220, 120, 760, 430); + window.Title = "Environment Variables"; + window.Icon = AppManager.DefaultAppIcon; + window.CanResize = true; + window.UserResized = Relayout; + window.Closing = TryStop; + wm.AddWindow(window); + + addButton = new Button(window, 0, 0, 1, 1); + addButton.Text = "Add"; + addButton.OnClick = AddClicked; + wm.AddWindow(addButton); + + editButton = new Button(window, 0, 0, 1, 1); + editButton.Text = "Edit"; + editButton.OnClick = EditClicked; + wm.AddWindow(editButton); + + deleteButton = new Button(window, 0, 0, 1, 1); + deleteButton.Text = "Delete"; + deleteButton.OnClick = DeleteClicked; + wm.AddWindow(deleteButton); + + refreshButton = new Button(window, 0, 0, 1, 1); + refreshButton.Text = "Refresh"; + refreshButton.OnClick = RefreshClicked; + wm.AddWindow(refreshButton); + + header = new Window(this, window, 0, toolbarHeight, window.Width, headerHeight); + wm.AddWindow(header); + + variableTable = new Table(window, 0, toolbarHeight + headerHeight, window.Width, window.Height - toolbarHeight - headerHeight); + variableTable.Background = Color.White; + variableTable.Foreground = Color.Black; + variableTable.Border = Color.FromArgb(185, 194, 207); + variableTable.SelectedBackground = Color.FromArgb(216, 231, 255); + variableTable.SelectedBorder = Color.FromArgb(94, 138, 216); + variableTable.SelectedForeground = Color.Black; + variableTable.CellHeight = 24; + variableTable.TableCellSelected = SelectionChanged; + wm.AddWindow(variableTable); + + PopulateTable(); + Relayout(); + wm.Update(window); + } + + public override void Run() + { + } + } +} diff --git a/Gui/Apps/Paint/ToolBox.cs b/Gui/Apps/Paint/ToolBox.cs index c4bbe04..8ed413c 100644 --- a/Gui/Apps/Paint/ToolBox.cs +++ b/Gui/Apps/Paint/ToolBox.cs @@ -31,7 +31,12 @@ namespace CMLeonOS.Gui.Apps.Paint internal readonly List Tools = new List() { new Tools.Pencil(), - new Tools.CircleBrush() + new Tools.CircleBrush(), + new Tools.Eraser(), + new Tools.LineTool(), + new Tools.RectangleTool(), + new Tools.FilledRectangleTool(), + new Tools.FilledCircleTool() }; private void TableClicked(int x, int y) diff --git a/Gui/Apps/Paint/Tools/Eraser.cs b/Gui/Apps/Paint/Tools/Eraser.cs new file mode 100644 index 0000000..b5a0775 --- /dev/null +++ b/Gui/Apps/Paint/Tools/Eraser.cs @@ -0,0 +1,53 @@ +using Cosmos.System; +using System.Drawing; + +namespace CMLeonOS.Gui.Apps.Paint.Tools +{ + internal class Eraser : Tool + { + public Eraser() : base("Eraser") + { + } + + 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, Color.White); + } + + for (int y = -4; y <= 4; y++) + { + for (int x = -4; x <= 4; x++) + { + int drawX = mouseX + x; + int drawY = mouseY + y; + if (paint.IsInBounds(drawX, drawY)) + { + canvas.DrawPoint(drawX, drawY, Color.White); + } + } + } + + joinLine = true; + joinX = mouseX; + joinY = mouseY; + } + else + { + joinLine = false; + } + } + + internal override void Deselected() + { + joinLine = false; + } + } +} diff --git a/Gui/Apps/Paint/Tools/FilledCircleTool.cs b/Gui/Apps/Paint/Tools/FilledCircleTool.cs new file mode 100644 index 0000000..40f4920 --- /dev/null +++ b/Gui/Apps/Paint/Tools/FilledCircleTool.cs @@ -0,0 +1,58 @@ +using Cosmos.System; +using System; + +namespace CMLeonOS.Gui.Apps.Paint.Tools +{ + internal class FilledCircleTool : Tool + { + public FilledCircleTool() : base("Filled Circle") + { + } + + private bool started; + private int startX; + private int startY; + + internal override void Run(Paint paint, Window canvas, MouseState mouseState, int mouseX, int mouseY) + { + if (mouseState == MouseState.Left) + { + if (!started) + { + started = true; + startX = mouseX; + startY = mouseY; + } + } + else if (started) + { + int radiusX = Math.Abs(mouseX - startX); + int radiusY = Math.Abs(mouseY - startY); + int radius = Math.Max(radiusX, radiusY); + + for (int y = -radius; y <= radius; y++) + { + for (int x = -radius; x <= radius; x++) + { + if ((x * x) + (y * y) <= radius * radius) + { + int drawX = startX + x; + int drawY = startY + y; + if (paint.IsInBounds(drawX, drawY)) + { + canvas.DrawPoint(drawX, drawY, paint.SelectedColor); + } + } + } + } + + started = false; + } + } + + internal override void Deselected() + { + started = false; + } + } +} diff --git a/Gui/Apps/Paint/Tools/FilledRectangleTool.cs b/Gui/Apps/Paint/Tools/FilledRectangleTool.cs new file mode 100644 index 0000000..62b6250 --- /dev/null +++ b/Gui/Apps/Paint/Tools/FilledRectangleTool.cs @@ -0,0 +1,43 @@ +using Cosmos.System; +using System; + +namespace CMLeonOS.Gui.Apps.Paint.Tools +{ + internal class FilledRectangleTool : Tool + { + public FilledRectangleTool() : base("Filled Rect") + { + } + + private bool started; + private int startX; + private int startY; + + internal override void Run(Paint paint, Window canvas, MouseState mouseState, int mouseX, int mouseY) + { + if (mouseState == MouseState.Left) + { + if (!started) + { + started = true; + startX = mouseX; + startY = mouseY; + } + } + else if (started) + { + int x = Math.Min(startX, mouseX); + int y = Math.Min(startY, mouseY); + int width = Math.Abs(mouseX - startX) + 1; + int height = Math.Abs(mouseY - startY) + 1; + canvas.DrawFilledRectangle(x, y, width, height, paint.SelectedColor); + started = false; + } + } + + internal override void Deselected() + { + started = false; + } + } +} diff --git a/Gui/Apps/Paint/Tools/LineTool.cs b/Gui/Apps/Paint/Tools/LineTool.cs new file mode 100644 index 0000000..9c4b14d --- /dev/null +++ b/Gui/Apps/Paint/Tools/LineTool.cs @@ -0,0 +1,38 @@ +using Cosmos.System; + +namespace CMLeonOS.Gui.Apps.Paint.Tools +{ + internal class LineTool : Tool + { + public LineTool() : base("Line") + { + } + + private bool started; + private int startX; + private int startY; + + internal override void Run(Paint paint, Window canvas, MouseState mouseState, int mouseX, int mouseY) + { + if (mouseState == MouseState.Left) + { + if (!started) + { + started = true; + startX = mouseX; + startY = mouseY; + } + } + else if (started) + { + canvas.DrawLine(startX, startY, mouseX, mouseY, paint.SelectedColor); + started = false; + } + } + + internal override void Deselected() + { + started = false; + } + } +} diff --git a/Gui/Apps/Paint/Tools/RectangleTool.cs b/Gui/Apps/Paint/Tools/RectangleTool.cs new file mode 100644 index 0000000..d1a4212 --- /dev/null +++ b/Gui/Apps/Paint/Tools/RectangleTool.cs @@ -0,0 +1,43 @@ +using Cosmos.System; +using System; + +namespace CMLeonOS.Gui.Apps.Paint.Tools +{ + internal class RectangleTool : Tool + { + public RectangleTool() : base("Rectangle") + { + } + + private bool started; + private int startX; + private int startY; + + internal override void Run(Paint paint, Window canvas, MouseState mouseState, int mouseX, int mouseY) + { + if (mouseState == MouseState.Left) + { + if (!started) + { + started = true; + startX = mouseX; + startY = mouseY; + } + } + else if (started) + { + int x = Math.Min(startX, mouseX); + int y = Math.Min(startY, mouseY); + int width = Math.Abs(mouseX - startX) + 1; + int height = Math.Abs(mouseY - startY) + 1; + canvas.DrawRectangle(x, y, width, height, paint.SelectedColor); + started = false; + } + } + + internal override void Deselected() + { + started = false; + } + } +} diff --git a/utils/EnvironmentVariableManager.cs b/utils/EnvironmentVariableManager.cs index 61a25d6..6a800d7 100644 --- a/utils/EnvironmentVariableManager.cs +++ b/utils/EnvironmentVariableManager.cs @@ -184,5 +184,27 @@ namespace CMLeonOS return false; } } + + public Dictionary GetAllVariables() + { + Dictionary copy = new Dictionary(); + foreach (KeyValuePair kvp in environmentVariables) + { + copy[kvp.Key] = kvp.Value; + } + return copy; + } + + public string[] GetAllVariablesAsLines() + { + string[] lines = new string[environmentVariables.Count]; + int index = 0; + foreach (KeyValuePair kvp in environmentVariables) + { + lines[index] = kvp.Key + "=" + kvp.Value; + index++; + } + return lines; + } } }