diff --git a/BuildTime.txt b/BuildTime.txt index 6eccd35..a23bfa9 100644 --- a/BuildTime.txt +++ b/BuildTime.txt @@ -1 +1 @@ -2026-03-28 21:43:07 \ No newline at end of file +2026-03-28 22:22:00 \ No newline at end of file diff --git a/GitCommit.txt b/GitCommit.txt index 61ba08a..a00c459 100644 --- a/GitCommit.txt +++ b/GitCommit.txt @@ -1 +1 @@ -0988f4c \ No newline at end of file +e9d4ae3 \ No newline at end of file diff --git a/Gui/Gui.cs b/Gui/Gui.cs index 9429ec1..89d52ee 100644 --- a/Gui/Gui.cs +++ b/Gui/Gui.cs @@ -23,9 +23,156 @@ namespace CMLeonOS.Gui { internal static class Gui { + private enum LowMemoryAction + { + Continue, + ReturnBootMenu, + Cancel + } + private static bool guiRunning = false; private static WindowManager windowManager; + private static string FitText(string text, int width) + { + if (string.IsNullOrEmpty(text)) + { + return string.Empty.PadRight(width); + } + + if (text.Length > width) + { + if (width <= 3) + { + return text.Substring(0, width); + } + + return text.Substring(0, width - 3) + "..."; + } + + return text.PadRight(width); + } + + private static void WriteAt(int x, int y, string text, ConsoleColor fg, ConsoleColor bg) + { + if (y < 0 || y >= Console.WindowHeight) + { + return; + } + + Console.SetCursorPosition(Math.Max(0, x), y); + Console.ForegroundColor = fg; + Console.BackgroundColor = bg; + Console.Write(text); + } + + private static void DrawBorderLine(int left, int y, int width, ConsoleColor fg, ConsoleColor bg) + { + string mid = new string('-', width - 2); + WriteAt(left, y, "+" + mid + "+", fg, bg); + } + + private static void DrawPanelLine(int left, int y, int width, string content, ConsoleColor contentFg, ConsoleColor contentBg) + { + int innerWidth = width - 2; + WriteAt(left, y, "|", ConsoleColor.Cyan, ConsoleColor.Black); + WriteAt(left + 1, y, FitText(content, innerWidth), contentFg, contentBg); + WriteAt(left + width - 1, y, "|", ConsoleColor.Cyan, ConsoleColor.Black); + } + + private static LowMemoryAction ShowLowMemoryWarning(uint ramMb) + { + int selected = 0; + string[] options = new[] { "Continue Anyway", "Return to Boot Menu", "Cancel" }; + bool needsRender = true; + + while (true) + { + if (needsRender) + { + Console.BackgroundColor = ConsoleColor.Black; + Console.ForegroundColor = ConsoleColor.White; + Console.Clear(); + + int width = Console.WindowWidth; + int height = Console.WindowHeight; + int panelWidth = Math.Min(86, Math.Max(58, width - 8)); + int contentLineCount = 7 + options.Length; + int panelHeight = contentLineCount + 2; + int left = Math.Max(0, (width - panelWidth) / 2); + int top = Math.Max(0, (height - panelHeight) / 2); + + DrawBorderLine(left, top, panelWidth, ConsoleColor.Cyan, ConsoleColor.Black); + DrawPanelLine(left, top + 1, panelWidth, " CMLeonOS Boot Warning ", ConsoleColor.Black, ConsoleColor.Cyan); + DrawPanelLine(left, top + 2, panelWidth, string.Empty, ConsoleColor.White, ConsoleColor.Black); + DrawPanelLine(left, top + 3, panelWidth, " Not enough system memory is available for Desktop GUI.", ConsoleColor.Yellow, ConsoleColor.Black); + DrawPanelLine(left, top + 4, panelWidth, $" Detected : {ramMb} MB", ConsoleColor.Gray, ConsoleColor.Black); + DrawPanelLine(left, top + 5, panelWidth, " Required : at least 1024 MB", ConsoleColor.Gray, ConsoleColor.Black); + DrawPanelLine(left, top + 6, panelWidth, string.Empty, ConsoleColor.White, ConsoleColor.Black); + DrawPanelLine(left, top + 7, panelWidth, " Use Up/Down to select, Enter to confirm", ConsoleColor.DarkGray, ConsoleColor.Black); + + for (int i = 0; i < options.Length; i++) + { + bool isSelected = i == selected; + DrawPanelLine( + left, + top + 8 + i, + panelWidth, + (isSelected ? " > " : " ") + options[i], + isSelected ? ConsoleColor.Black : ConsoleColor.White, + isSelected ? ConsoleColor.White : ConsoleColor.Black + ); + } + + DrawBorderLine(left, top + panelHeight - 1, panelWidth, ConsoleColor.Cyan, ConsoleColor.Black); + needsRender = false; + } + + if (Cosmos.System.KeyboardManager.TryReadKey(out var key)) + { + if (key.Key == Cosmos.System.ConsoleKeyEx.UpArrow) + { + selected--; + if (selected < 0) + { + selected = options.Length - 1; + } + needsRender = true; + } + else if (key.Key == Cosmos.System.ConsoleKeyEx.DownArrow) + { + selected++; + if (selected >= options.Length) + { + selected = 0; + } + needsRender = true; + } + else if (key.Key == Cosmos.System.ConsoleKeyEx.Enter) + { + if (selected == 0) + { + return LowMemoryAction.Continue; + } + if (selected == 1) + { + return LowMemoryAction.ReturnBootMenu; + } + + return LowMemoryAction.Cancel; + } + else if (key.Key == Cosmos.System.ConsoleKeyEx.Escape) + { + return LowMemoryAction.ReturnBootMenu; + } + } + else + { + System.Threading.Thread.Sleep(16); + } + } + } + internal static bool StartGui() { Console.Clear(); @@ -35,18 +182,16 @@ namespace CMLeonOS.Gui Logger.Logger.Instance.Info("Gui", "GUI starting."); - if (Cosmos.Core.CPU.GetAmountOfRAM() < 1000) + uint ramMb = Cosmos.Core.CPU.GetAmountOfRAM(); + if (ramMb < 1000) { - Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine("Not enough system memory is available to run the GUI."); - Console.WriteLine("At least 1 GB should be allocated."); - Console.ResetColor(); - Console.Write("Continue anyway? [y/N]"); - - if (Console.ReadKey(true).Key != ConsoleKey.Y) + LowMemoryAction action = ShowLowMemoryWarning(ramMb); + if (action != LowMemoryAction.Continue) { return false; } + + Console.Clear(); } Console.WriteLine("Loading apps..."); diff --git a/Gui/ShellComponents/Lock.cs b/Gui/ShellComponents/Lock.cs index 73d5b74..8b946bb 100644 --- a/Gui/ShellComponents/Lock.cs +++ b/Gui/ShellComponents/Lock.cs @@ -69,29 +69,90 @@ namespace CMLeonOS.Gui.ShellComponents private const int logOnButtonY = passwordY + 44; private const int logOnButtonHeight = 38; - private readonly Color windowBackground = Color.FromArgb(232, 238, 246); - private readonly Color outerBorder = Color.FromArgb(169, 181, 198); - private readonly Color leftPanel = Color.FromArgb(34, 53, 84); - private readonly Color leftPanelAccent = Color.FromArgb(74, 124, 201); - private readonly Color leftPanelSoft = Color.FromArgb(53, 77, 116); - private readonly Color rightPanel = Color.FromArgb(247, 250, 253); - private readonly Color titleColor = Color.FromArgb(28, 39, 56); - private readonly Color bodyColor = Color.FromArgb(92, 103, 119); - private readonly Color hintColor = Color.FromArgb(132, 142, 156); - private readonly Color inputBackground = Color.White; - private readonly Color inputForeground = Color.FromArgb(31, 42, 55); - private readonly Color selectionBackground = Color.FromArgb(223, 236, 255); - private readonly Color selectionBorder = Color.FromArgb(91, 140, 223); - private readonly Color primaryButton = Color.FromArgb(53, 111, 214); - private readonly Color primaryButtonBorder = Color.FromArgb(33, 83, 171); - private readonly Color primaryButtonText = Color.White; + private Color windowBackground; + private Color outerBorder; + private Color leftPanel; + private Color leftPanelAccent; + private Color leftPanelSoft; + private Color rightPanel; + private Color titleColor; + private Color bodyColor; + private Color hintColor; + private Color inputBackground; + private Color inputForeground; + private Color selectionBackground; + private Color selectionBorder; + private Color primaryButton; + private Color primaryButtonBorder; + private Color primaryButtonText; private double shakiness = 0; private List users = new List(); + private static Color Blend(Color a, Color b, float t) + { + if (t < 0f) t = 0f; + if (t > 1f) t = 1f; + return Color.FromArgb( + (int)(a.R + (b.R - a.R) * t), + (int)(a.G + (b.G - a.G) * t), + (int)(a.B + (b.B - a.B) * t) + ); + } + + private void SyncThemeColors() + { + windowBackground = UITheme.Surface; + outerBorder = UITheme.SurfaceBorder; + rightPanel = UITheme.Surface; + titleColor = UITheme.TextPrimary; + bodyColor = UITheme.TextSecondary; + hintColor = UITheme.TextSecondary; + inputBackground = UITheme.Surface; + inputForeground = UITheme.TextPrimary; + selectionBackground = UITheme.AccentLight; + selectionBorder = UITheme.Accent; + primaryButton = UITheme.Accent; + primaryButtonBorder = UITheme.AccentDark; + primaryButtonText = UITheme.WindowTitleText; + + leftPanel = Blend(UITheme.WindowTitleBackground, Color.Black, 0.28f); + leftPanelAccent = UITheme.Accent; + leftPanelSoft = Blend(leftPanel, UITheme.Accent, 0.32f); + } + + private void ApplyThemeToControls() + { + if (userTable != null) + { + userTable.Background = inputBackground; + userTable.Foreground = inputForeground; + userTable.Border = outerBorder; + userTable.SelectedBackground = selectionBackground; + userTable.SelectedForeground = inputForeground; + userTable.SelectedBorder = selectionBorder; + } + + if (passwordBox != null) + { + passwordBox.Background = inputBackground; + passwordBox.Foreground = inputForeground; + passwordBox.PlaceholderForeground = hintColor; + } + + if (logOnButton != null) + { + logOnButton.Background = primaryButton; + logOnButton.Border = primaryButtonBorder; + logOnButton.Foreground = primaryButtonText; + } + } + private void RenderBackground() { + SyncThemeColors(); + window.Clear(windowBackground); window.DrawRectangle(0, 0, width, height, outerBorder); @@ -104,21 +165,21 @@ namespace CMLeonOS.Gui.ShellComponents window.DrawFilledRectangle(rightX, 0, rightWidth, height, rightPanel); window.DrawFilledRectangle(20, 22, 56, 56, leftPanelSoft); - window.DrawRectangle(20, 22, 56, 56, Color.FromArgb(109, 149, 214)); + window.DrawRectangle(20, 22, 56, 56, Blend(leftPanelAccent, Color.White, 0.25f)); window.DrawImageAlpha(Images.Icon_Key, 32, 34); - window.DrawString("Welcome Back", Color.White, 20, 96); - window.DrawString("CMLeonOS Desktop", Color.FromArgb(190, 208, 233), 20, 120); + window.DrawString("Welcome Back", UITheme.WindowTitleText, 20, 96); + window.DrawString("CMLeonOS Desktop", Blend(UITheme.WindowTitleText, leftPanel, 0.45f), 20, 120); string selectedUserName = GetSelectedUser()?.Username ?? "Guest"; - window.DrawString("Selected account", Color.FromArgb(171, 190, 217), 20, 168); - window.DrawString(selectedUserName, Color.White, 20, 190); - window.DrawString(GetSelectedUserSubtitle(), Color.FromArgb(176, 197, 224), 20, 214); + window.DrawString("Selected account", Blend(UITheme.WindowTitleText, leftPanel, 0.55f), 20, 168); + window.DrawString(selectedUserName, UITheme.WindowTitleText, 20, 190); + window.DrawString(GetSelectedUserSubtitle(), Blend(UITheme.WindowTitleText, leftPanel, 0.5f), 20, 214); window.DrawFilledRectangle(20, height - 72, leftWidth - 40, 44, leftPanelSoft); - window.DrawRectangle(20, height - 72, leftWidth - 40, 44, Color.FromArgb(88, 118, 171)); - window.DrawString("Tip: type password.", Color.White, 32, height - 62); - window.DrawString("Press Enter to sign in.", Color.FromArgb(190, 208, 233), 32, height - 44); + window.DrawRectangle(20, height - 72, leftWidth - 40, 44, Blend(leftPanelAccent, Color.White, 0.2f)); + window.DrawString("Tip: type password.", UITheme.WindowTitleText, 32, height - 62); + window.DrawString("Press Enter to sign in.", Blend(UITheme.WindowTitleText, leftPanelSoft, 0.4f), 32, height - 44); int rightContentX = leftWidth + rightContentPadding; window.DrawString("Sign in", titleColor, rightContentX, 28); @@ -127,7 +188,7 @@ namespace CMLeonOS.Gui.ShellComponents window.DrawString("Accounts", hintColor, rightContentX, accountsLabelY); window.DrawString("Password", hintColor, rightContentX, passwordLabelY); - window.DrawString("Secure local session", Color.FromArgb(118, 128, 141), rightContentX, height - rightContentBottomPadding); + window.DrawString("Secure local session", hintColor, rightContentX, height - rightContentBottomPadding); } @@ -160,6 +221,7 @@ namespace CMLeonOS.Gui.ShellComponents private void RefreshLayout() { RenderBackground(); + ApplyThemeToControls(); wm.Update(window); } @@ -265,6 +327,7 @@ namespace CMLeonOS.Gui.ShellComponents wm.AddWindow(window); RenderBackground(); + SyncThemeColors(); int contentX = leftPanelWidth + rightContentPadding; int contentWidth = width - contentX - rightContentPadding; @@ -273,7 +336,7 @@ namespace CMLeonOS.Gui.ShellComponents userTable.CellHeight = 40; userTable.Background = inputBackground; userTable.Foreground = inputForeground; - userTable.Border = Color.FromArgb(203, 212, 224); + userTable.Border = outerBorder; userTable.SelectedBackground = selectionBackground; userTable.SelectedForeground = inputForeground; userTable.SelectedBorder = selectionBorder; diff --git a/Kernel.cs b/Kernel.cs index c84bde9..fd22058 100644 --- a/Kernel.cs +++ b/Kernel.cs @@ -357,27 +357,37 @@ namespace CMLeonOS { // 在显示 Boot Menu 之前初始化系统(VFS、用户系统等) InitializeSystem(); - - BootMenuAction bootAction = BootMenu.Show(); - switch (bootAction) + while (true) { - case BootMenuAction.Reboot: - Sys.Power.Reboot(); - break; - case BootMenuAction.Shutdown: - Sys.Power.Shutdown(); - break; - case BootMenuAction.GuiBoot: - Console.Clear(); - Console.WriteLine("Starting GUI..."); - Console.WriteLine(); - Gui.Gui.StartGui(); - // GUI 启动后会阻塞在这里,直到 GUI 退出 - return; - case BootMenuAction.NormalBoot: - default: - break; + BootMenuAction bootAction = BootMenu.Show(); + + switch (bootAction) + { + case BootMenuAction.Reboot: + Sys.Power.Reboot(); + return; + case BootMenuAction.Shutdown: + Sys.Power.Shutdown(); + return; + case BootMenuAction.GuiBoot: + Console.Clear(); + Console.WriteLine("Starting GUI..."); + Console.WriteLine(); + if (Gui.Gui.StartGui()) + { + // GUI 启动后会阻塞在这里,直到 GUI 退出 + return; + } + + // 低内存提示选择“返回 BootMenu”时会回到这里继续循环 + continue; + case BootMenuAction.NormalBoot: + default: + break; + } + + break; } Console.Clear();