diff --git a/BuildTime.txt b/BuildTime.txt index 82284af..3a7f7b3 100644 --- a/BuildTime.txt +++ b/BuildTime.txt @@ -1 +1 @@ -2026-03-29 19:34:16 \ No newline at end of file +2026-03-29 20:23:53 \ No newline at end of file diff --git a/GitCommit.txt b/GitCommit.txt index 1097cc6..a4544c3 100644 --- a/GitCommit.txt +++ b/GitCommit.txt @@ -1 +1 @@ -3a9ff9c \ No newline at end of file +36f467d \ No newline at end of file diff --git a/Gui/Apps/CodeStudio/Ide.cs b/Gui/Apps/CodeStudio/Ide.cs index 5dd754b..5b56f96 100644 --- a/Gui/Apps/CodeStudio/Ide.cs +++ b/Gui/Apps/CodeStudio/Ide.cs @@ -1,25 +1,8 @@ -// The CMLeonOS Project (https://github.com/Leonmmcoset/CMLeonOS) -// Copyright (C) 2025-present LeonOS 2 Developer Team -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -using CMLeonOS; +using CMLeonOS; using CMLeonOS.Gui.UILib; using Cosmos.System.Graphics; -using System.Drawing; using System; -using System.Collections.Generic; +using System.Drawing; using System.IO; using UniLua; @@ -41,92 +24,163 @@ namespace CMLeonOS.Gui.Apps.CodeStudio private static byte[] _runBytes; private static Bitmap runBitmap = new Bitmap(_runBytes); - Process process; + private readonly Process process; + private readonly WindowManager wm; - WindowManager wm; - - AppWindow mainWindow; - - Button runButton; - - CodeEditor editor; - - TextBox problems; - - TextBox output; - - FileBrowser fileBrowser; - - private const int headersHeight = 24; - private const int problemsHeight = 128; - private const int outputHeight = 128; - - private string? path = null; + private AppWindow mainWindow; + private Button runButton; + private ShortcutBar shortcutBar; + private CodeEditor editor; + private TextBox problems; + private TextBox output; + private TextBox statusBar; + private Table sideTable; + private FileBrowser fileBrowser; + private string path = null; private bool modified = false; - private void TextChanged() + private static class Layout { - modified = true; - - UpdateTitle(); - } - - private void WindowResized() - { - int editorHeight = mainWindow.Height - headersHeight - problemsHeight - outputHeight - (headersHeight * 3); - editor.Move(0, headersHeight); - editor.Resize(mainWindow.Width, editorHeight); - editor.MarkAllLines(); - editor.Render(); - - problems.Move(0, headersHeight + editorHeight + headersHeight); - problems.Resize(mainWindow.Width, problemsHeight + (headersHeight * 2)); - problems.MarkAllLines(); - problems.Render(); - - output.Move(0, headersHeight + editorHeight + problemsHeight + (headersHeight * 2)); - output.Resize(mainWindow.Width, outputHeight + (headersHeight * 2)); - output.MarkAllLines(); - output.Render(); - - mainWindow.Clear(Theme.Background); - mainWindow.DrawString("Problems", Color.White, 0, headersHeight + editorHeight); - mainWindow.DrawString("Output", Color.White, 0, headersHeight + editorHeight + problemsHeight + headersHeight); + internal const int TopBarHeight = 30; + internal const int BottomBarHeight = 24; + internal const int Gap = 6; + internal const int Side = 8; + internal const int RunWidth = 72; + internal const int SidePanelWidth = 190; + internal const int PanelTitleHeight = 18; + internal const int BottomPanelHeight = 150; } private static class Theme { - internal static Color Background = Color.FromArgb(68, 76, 84); - internal static Color CodeBackground = Color.FromArgb(41, 46, 51); + internal static readonly Color FrameBg = Color.FromArgb(34, 40, 52); + internal static readonly Color ToolbarBg = Color.FromArgb(27, 33, 44); + internal static readonly Color EditorBg = Color.FromArgb(19, 24, 34); + internal static readonly Color PanelBg = Color.FromArgb(23, 29, 39); + internal static readonly Color PanelBorder = Color.FromArgb(66, 78, 97); + internal static readonly Color TitleText = Color.FromArgb(220, 228, 240); + internal static readonly Color HintText = Color.FromArgb(157, 171, 190); + internal static readonly Color OkText = Color.FromArgb(142, 219, 160); + internal static readonly Color ErrorText = Color.FromArgb(255, 153, 164); } private void UpdateTitle() { if (path == null) { - mainWindow.Title = "Untitled - Lua CodeStudio"; + mainWindow.Title = "Untitled - CodeStudio"; return; } - if (modified) + string fileName = Path.GetFileName(path); + mainWindow.Title = modified ? $"{fileName}* - CodeStudio" : $"{fileName} - CodeStudio"; + } + + private void SetStatus(string text) + { + statusBar.Text = text; + statusBar.Render(); + wm.Update(statusBar); + } + + private void TextChanged() + { + modified = true; + UpdateTitle(); + SetStatus("Edited"); + } + + private void RenderChrome() + { + mainWindow.Clear(Theme.FrameBg); + mainWindow.DrawFilledRectangle(0, 0, mainWindow.Width, Layout.TopBarHeight, Theme.ToolbarBg); + mainWindow.DrawRectangle(0, 0, mainWindow.Width, Layout.TopBarHeight, Theme.PanelBorder); + + int contentY = Layout.TopBarHeight + Layout.Gap; + int contentH = mainWindow.Height - contentY - Layout.BottomBarHeight - Layout.Gap; + int leftW = Layout.SidePanelWidth; + int rightX = Layout.Side + leftW + Layout.Gap; + int rightW = mainWindow.Width - rightX - Layout.Side; + + int editorTop = contentY + Layout.PanelTitleHeight; + int editorH = contentH - Layout.BottomPanelHeight - Layout.Gap - Layout.PanelTitleHeight; + int bottomY = editorTop + editorH + Layout.Gap + Layout.PanelTitleHeight; + int halfW = (rightW - Layout.Gap) / 2; + + mainWindow.DrawString("Workspace", Theme.TitleText, Layout.Side + 2, contentY + 2); + mainWindow.DrawString("Editor", Theme.TitleText, rightX + 2, contentY + 2); + mainWindow.DrawString("Problems", Theme.TitleText, rightX + 2, bottomY - Layout.PanelTitleHeight + 2); + mainWindow.DrawString("Output", Theme.TitleText, rightX + halfW + Layout.Gap + 2, bottomY - Layout.PanelTitleHeight + 2); + } + + private int GetEditorHeight() + { + int contentY = Layout.TopBarHeight + Layout.Gap; + int contentH = mainWindow.Height - contentY - Layout.BottomBarHeight - Layout.Gap; + int available = contentH - Layout.BottomPanelHeight - Layout.Gap - Layout.PanelTitleHeight; + if (available < 80) { - mainWindow.Title = $"{Path.GetFileName(path)}* - Lua CodeStudio"; - } - else - { - mainWindow.Title = $"{Path.GetFileName(path)} - Lua CodeStudio"; + return 80; } + return available; + } + + private void ReLayout() + { + int side = Layout.Side; + int width = mainWindow.Width - (side * 2); + int y = 0; + + runButton.MoveAndResize(side, y, Layout.RunWidth, Layout.TopBarHeight, sendWMEvent: false); + shortcutBar.MoveAndResize(side + Layout.RunWidth + Layout.Gap, y, width - Layout.RunWidth - Layout.Gap, Layout.TopBarHeight, sendWMEvent: false); + shortcutBar.Render(); + + int contentY = Layout.TopBarHeight + Layout.Gap; + int contentH = mainWindow.Height - contentY - Layout.BottomBarHeight - Layout.Gap; + int leftW = Layout.SidePanelWidth; + int rightX = side + leftW + Layout.Gap; + int rightW = mainWindow.Width - rightX - side; + + sideTable.MoveAndResize(side, contentY + Layout.PanelTitleHeight, leftW, contentH - Layout.PanelTitleHeight, sendWMEvent: false); + sideTable.Render(); + + int editorY = contentY + Layout.PanelTitleHeight; + int editorH = GetEditorHeight(); + editor.MoveAndResize(rightX, editorY, rightW, editorH, sendWMEvent: false); + editor.MarkAllLines(); + editor.Render(); + + int bottomY = editorY + editorH + Layout.Gap + Layout.PanelTitleHeight; + int halfW = (rightW - Layout.Gap) / 2; + problems.MoveAndResize(rightX, bottomY, halfW, Layout.BottomPanelHeight, sendWMEvent: false); + problems.MarkAllLines(); + problems.Render(); + + output.MoveAndResize(rightX + halfW + Layout.Gap, bottomY, rightW - halfW - Layout.Gap, Layout.BottomPanelHeight, sendWMEvent: false); + output.MarkAllLines(); + output.Render(); + + int statusY = mainWindow.Height - Layout.BottomBarHeight; + statusBar.MoveAndResize(0, statusY, mainWindow.Width, Layout.BottomBarHeight, sendWMEvent: false); + statusBar.Render(); + + RenderChrome(); + wm.Update(mainWindow); } internal void Open(string newPath, bool readFile = true) { - if (newPath == null) return; + if (newPath == null) + { + return; + } if (readFile && !File.Exists(newPath)) { - MessageBox messageBox = new MessageBox(process, "Lua CodeStudio", $"No such file '{Path.GetFileName(newPath)}'."); + MessageBox messageBox = new MessageBox(process, "CodeStudio", $"No such file '{Path.GetFileName(newPath)}'."); messageBox.Show(); + return; } path = newPath; @@ -137,7 +191,6 @@ namespace CMLeonOS.Gui.Apps.CodeStudio string extension = Path.GetExtension(path).ToLower(); editor.SetSyntaxHighlighting(extension == ".lua", extension); - editor.MarkAllLines(); editor.Render(); @@ -145,6 +198,7 @@ namespace CMLeonOS.Gui.Apps.CodeStudio } UpdateTitle(); + SetStatus("Opened: " + Path.GetFileName(path)); } private void OpenFilePrompt() @@ -181,9 +235,55 @@ namespace CMLeonOS.Gui.Apps.CodeStudio } File.WriteAllText(path, editor.Text); - modified = false; UpdateTitle(); + SetStatus("Saved: " + Path.GetFileName(path)); + } + + private void SideCommandSelected(int index) + { + if (index < 0 || index >= sideTable.Cells.Count) + { + return; + } + + string cmd = sideTable.Cells[index].Text; + if (cmd == "Open File") + { + OpenFilePrompt(); + } + else if (cmd == "Save File") + { + Save(); + } + else if (cmd == "Save As") + { + SaveAsPrompt(); + } + else if (cmd == "Evaluate") + { + Evaluate(); + } + else if (cmd == "Run Script") + { + RunClicked(0, 0); + } + else if (cmd == "Insert: Hello") + { + editor.Text += "\nprint(\"Hello from CodeStudio\")"; + editor.MarkAllLines(); + editor.Render(); + wm.Update(editor); + TextChanged(); + } + else if (cmd == "Insert: GUI Demo") + { + editor.Text += "\nlocal w = gui.window(\"Demo\", 100, 100, 260, 120)\n"; + editor.MarkAllLines(); + editor.Render(); + wm.Update(editor); + TextChanged(); + } } private void RunClicked(int x, int y) @@ -191,20 +291,23 @@ namespace CMLeonOS.Gui.Apps.CodeStudio try { output.Text = ""; - + ILuaState lua = LuaAPI.NewState(); lua.L_OpenLibs(); - + LuaGuiLibrary.Initialize(wm, process); LuaGuiLibrary.Register(lua); - + lua.PushCSharpFunction(L => { int n = L.GetTop(); string result = ""; for (int i = 1; i <= n; i++) { - if (i > 1) result += "\t"; + if (i > 1) + { + result += "\t"; + } LuaType type = L.Type(i); if (type == LuaType.LUA_TSTRING) { @@ -227,37 +330,47 @@ namespace CMLeonOS.Gui.Apps.CodeStudio return 0; }); lua.SetGlobal("print"); - + UniLua.ThreadStatus loadResult = lua.L_LoadString(editor.Text); - + if (loadResult == UniLua.ThreadStatus.LUA_OK) { UniLua.ThreadStatus callResult = lua.PCall(0, 0, 0); - if (callResult == UniLua.ThreadStatus.LUA_OK) { - problems.Foreground = Color.LimeGreen; - problems.Text = "Execution successful"; + problems.Foreground = Theme.OkText; + problems.Text = "Execution successful."; + SetStatus("Run succeeded"); } else { string errorMsg = lua.ToString(-1); - problems.Foreground = Color.Pink; - problems.Text = $"Script execution error: {errorMsg}"; + problems.Foreground = Theme.ErrorText; + problems.Text = "Script execution error: " + errorMsg; + SetStatus("Run failed"); } } else { string errorMsg = lua.ToString(-1); - problems.Foreground = Color.Pink; - problems.Text = $"Script load error: {errorMsg}"; + problems.Foreground = Theme.ErrorText; + problems.Text = "Script load error: " + errorMsg; + SetStatus("Run failed"); } } catch (Exception e) { - problems.Foreground = Color.Pink; + problems.Foreground = Theme.ErrorText; problems.Text = e.Message; + SetStatus("Run failed"); } + + problems.MarkAllLines(); + problems.Render(); + output.MarkAllLines(); + output.Render(); + wm.Update(problems); + wm.Update(output); } private void Evaluate() @@ -267,58 +380,73 @@ namespace CMLeonOS.Gui.Apps.CodeStudio ILuaState lua = LuaAPI.NewState(); lua.L_OpenLibs(); UniLua.ThreadStatus loadResult = lua.L_LoadString(editor.Text); - + if (loadResult == UniLua.ThreadStatus.LUA_OK) { - problems.Foreground = Color.LimeGreen; - problems.Text = "No syntax errors"; + problems.Foreground = Theme.OkText; + problems.Text = "No syntax errors."; + SetStatus("Evaluate passed"); } else { string errorMsg = lua.ToString(-1); + problems.Foreground = Theme.ErrorText; if (string.IsNullOrWhiteSpace(errorMsg)) { - problems.Foreground = Color.Pink; problems.Text = "Script load error: Unknown error"; } else { - problems.Foreground = Color.Pink; - problems.Text = $"Script load error: {errorMsg}"; + problems.Text = "Script load error: " + errorMsg; } + SetStatus("Evaluate failed"); } } catch (Exception e) { - problems.Foreground = Color.Pink; + problems.Foreground = Theme.ErrorText; problems.Text = e.Message; + SetStatus("Evaluate failed"); } + + problems.MarkAllLines(); + problems.Render(); + wm.Update(problems); } internal void Start() { - mainWindow = new AppWindow(process, 96, 96, 800, 600); + mainWindow = new AppWindow(process, 96, 96, 920, 640); mainWindow.Icon = iconBitmap; - mainWindow.Clear(Theme.Background); mainWindow.Closing = process.TryStop; mainWindow.CanResize = true; - mainWindow.UserResized = WindowResized; - UpdateTitle(); + mainWindow.UserResized = ReLayout; wm.AddWindow(mainWindow); + UpdateTitle(); - runButton = new Button(mainWindow, 0, 0, 60, headersHeight); - runButton.Background = Theme.Background; - runButton.Border = Theme.Background; - runButton.Foreground = Color.White; + runButton = new Button(mainWindow, Layout.Side, 0, Layout.RunWidth, Layout.TopBarHeight); + runButton.Background = Theme.ToolbarBg; + runButton.Border = Theme.PanelBorder; + runButton.Foreground = Theme.TitleText; runButton.Text = "Run"; runButton.Image = runBitmap; runButton.ImageLocation = Button.ButtonImageLocation.Left; runButton.OnClick = RunClicked; wm.AddWindow(runButton); - editor = new CodeEditor(mainWindow, 0, headersHeight, mainWindow.Width, mainWindow.Height - headersHeight - problemsHeight - outputHeight - (headersHeight * 3)) + shortcutBar = new ShortcutBar(mainWindow, Layout.Side + Layout.RunWidth + Layout.Gap, 0, 300, Layout.TopBarHeight); + shortcutBar.Background = Theme.ToolbarBg; + shortcutBar.Foreground = Theme.TitleText; + 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("Evaluate", Evaluate)); + shortcutBar.Render(); + wm.AddWindow(shortcutBar); + + editor = new CodeEditor(mainWindow, Layout.Side, Layout.TopBarHeight + Layout.Gap, 300, 200) { - Background = Theme.CodeBackground, + Background = Theme.EditorBg, Foreground = Color.White, Text = "print(\"Hello World!\")", Changed = TextChanged, @@ -327,42 +455,55 @@ namespace CMLeonOS.Gui.Apps.CodeStudio editor.SetSyntaxHighlighting(true, ".lua"); wm.AddWindow(editor); - problems = new TextBox(mainWindow, 0, headersHeight + editor.Height + headersHeight, mainWindow.Width, problemsHeight + (headersHeight * 2)) + sideTable = new Table(mainWindow, Layout.Side, Layout.TopBarHeight + Layout.Gap + Layout.PanelTitleHeight, Layout.SidePanelWidth, 300); + sideTable.CellHeight = 24; + sideTable.AllowDeselection = false; + sideTable.Background = Theme.PanelBg; + sideTable.Border = Theme.PanelBorder; + sideTable.Foreground = Theme.TitleText; + sideTable.SelectedBackground = Color.FromArgb(54, 72, 103); + sideTable.SelectedBorder = Color.FromArgb(88, 112, 152); + sideTable.SelectedForeground = Color.White; + sideTable.TableCellSelected = SideCommandSelected; + sideTable.Cells.Add(new TableCell("Open File")); + sideTable.Cells.Add(new TableCell("Save File")); + sideTable.Cells.Add(new TableCell("Save As")); + sideTable.Cells.Add(new TableCell("Evaluate")); + sideTable.Cells.Add(new TableCell("Run Script")); + sideTable.Cells.Add(new TableCell("Insert: Hello")); + sideTable.Cells.Add(new TableCell("Insert: GUI Demo")); + wm.AddWindow(sideTable); + + problems = new TextBox(mainWindow, Layout.Side, 280, 300, Layout.BottomPanelHeight) { - Background = Theme.CodeBackground, - Foreground = Color.Gray, - Text = "Click Evaluate to check your program for syntax errors.", + Background = Theme.PanelBg, + Foreground = Theme.HintText, + Text = "Click Evaluate to check syntax.", ReadOnly = true, MultiLine = true }; wm.AddWindow(problems); - mainWindow.DrawString("Problems", Color.White, 0, headersHeight + editor.Height); - - output = new TextBox(mainWindow, 0, headersHeight + editor.Height + problemsHeight + (headersHeight * 2), mainWindow.Width, outputHeight + (headersHeight * 2)) + output = new TextBox(mainWindow, Layout.Side, 430, 300, Layout.BottomPanelHeight) { - Background = Theme.CodeBackground, - Foreground = Color.White, + Background = Theme.PanelBg, + Foreground = Theme.TitleText, Text = "Output will appear here...", ReadOnly = true, MultiLine = true }; wm.AddWindow(output); - mainWindow.DrawString("Output", Color.White, 0, headersHeight + editor.Height + problemsHeight + headersHeight); - - var shortcutBar = new ShortcutBar(mainWindow, runButton.Width, 0, mainWindow.Width - runButton.Width, headersHeight) + statusBar = new TextBox(mainWindow, 0, mainWindow.Height - Layout.BottomBarHeight, mainWindow.Width, Layout.BottomBarHeight) { - Background = Theme.Background, - Foreground = Color.White + Background = Theme.ToolbarBg, + Foreground = Theme.HintText, + ReadOnly = true, + Text = "Ready" }; - 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("Evaluate", Evaluate)); - shortcutBar.Render(); - wm.AddWindow(shortcutBar); + wm.AddWindow(statusBar); + ReLayout(); wm.Update(mainWindow); } }