diff --git a/BuildTime.txt b/BuildTime.txt index 59052cf..2263405 100644 --- a/BuildTime.txt +++ b/BuildTime.txt @@ -1 +1 @@ -2026-03-26 20:46:03 \ No newline at end of file +2026-03-26 21:30:36 \ No newline at end of file diff --git a/GitCommit.txt b/GitCommit.txt index ae547ae..e639942 100644 --- a/GitCommit.txt +++ b/GitCommit.txt @@ -1 +1 @@ -312acd9 \ No newline at end of file +cd6fee6 \ No newline at end of file diff --git a/Gui/Apps/Calculator.cs b/Gui/Apps/Calculator.cs index 259c670..904f4ec 100644 --- a/Gui/Apps/Calculator.cs +++ b/Gui/Apps/Calculator.cs @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -using Cosmos.System.Graphics; using CMLeonOS; using CMLeonOS.Gui.UILib; using System; @@ -26,10 +25,6 @@ namespace CMLeonOS.Gui.Apps { internal Calculator() : base("Calculator", ProcessType.Application) { } - AppWindow window; - - WindowManager wm = ProcessManager.GetProcess(); - private enum Operator { None, @@ -39,268 +34,274 @@ namespace CMLeonOS.Gui.Apps Divide } - [IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Calculator.GridButton.bmp")] - private static byte[] gridButtonBytes; - private static Bitmap gridButtonBitmap = new Bitmap(gridButtonBytes); + private AppWindow window; + private TextBlock expressionBlock; + private TextBlock displayBlock; + private StatusBar statusBar; - [IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Calculator.Display.bmp")] - private static byte[] displayBytes; - private static Bitmap displayBitmap = new Bitmap(displayBytes); + private readonly WindowManager wm = ProcessManager.GetProcess(); - private const int padding = 16; - private const int gridButtonSize = 40; - private const int resultHeight = 40; + private const int padding = 12; + private const int buttonWidth = 68; + private const int buttonHeight = 34; + private const int buttonGap = 8; + private const int displayHeight = 72; + private const int statusHeight = 24; private long num1 = 0; private long num2 = 0; private Operator op = Operator.None; + private bool overwriteNextDigit = false; - private void RenderGridButton(string text, int x, int y) + private string OperatorText { - int buttonX = (x * gridButtonSize); - int buttonY = (y * gridButtonSize) + resultHeight; - window.DrawImage(gridButtonBitmap, buttonX, buttonY); - window.DrawString(text, Color.Black, buttonX + (gridButtonSize / 2) - ((text.Length * 8) / 2), buttonY + (gridButtonSize / 2) - (16 / 2)); - } - - private void WindowClick(int x, int y) - { - int gridX = x / gridButtonSize; - int gridY = (y - resultHeight) / gridButtonSize; - if (gridY < 0) + get { - return; - } - switch (gridY) - { - case 0: - switch (gridX) - { - case 0: - InputNum("7"); - break; - case 1: - InputNum("8"); - break; - case 2: - InputNum("9"); - break; - case 3: - InputOp(Operator.Add); - break; - } - break; - case 1: - switch (gridX) - { - case 0: - InputNum("4"); - break; - case 1: - InputNum("5"); - break; - case 2: - InputNum("6"); - break; - case 3: - InputOp(Operator.Subtract); - break; - } - break; - case 2: - switch (gridX) - { - case 0: - InputNum("1"); - break; - case 1: - InputNum("2"); - break; - case 2: - InputNum("3"); - break; - case 3: - InputOp(Operator.Multiply); - break; - } - break; - case 3: - switch (gridX) - { - case 0: - InputNum("0"); - break; - case 1: - InputBksp(); - break; - case 2: - InputEquals(); - break; - case 3: - InputOp(Operator.Divide); - break; - } - break; - } - } - - private void RenderDisplay(bool updateWindow = true) - { - window.DrawImage(displayBitmap, 0, 0); - string text; - if (op != Operator.None) - { - char opChar; - opChar = op switch + return op switch { - Operator.Add => '+', - Operator.Subtract => '-', - Operator.Multiply => '*', - Operator.Divide => '/', - _ => throw new Exception("Unrecognised operator.") + Operator.Add => "+", + Operator.Subtract => "-", + Operator.Multiply => "*", + Operator.Divide => "/", + _ => string.Empty }; - text = num1.ToString().TrimEnd('.') + opChar + num2.ToString().TrimEnd('.'); - } - else - { - text = num1.ToString().TrimEnd('.'); - } - window.DrawString(text, Color.Black, window.Width - 12 - (text.Length * 8), 12); - if (updateWindow) - { - wm.Update(window); } } - private void InputNum(string num) + private void UpdateDisplay() { - if (op != Operator.None) + if (op == Operator.None) { - num2 = long.Parse(num2.ToString() + num); + expressionBlock.Text = "Current Value"; + displayBlock.Text = num1.ToString(); } else { - num1 = long.Parse(num1.ToString() + num); + expressionBlock.Text = $"{num1} {OperatorText}"; + displayBlock.Text = num2.ToString(); } - RenderDisplay(); + + string state = op == Operator.None ? "Ready" : $"Operator: {OperatorText}"; + statusBar.Text = state; + statusBar.DetailText = "Integer Mode"; } - private void InputOp(Operator @operator) + private void ShowError(string text) { - if (op != Operator.None) + new MessageBox(this, "Calculator", text).Show(); + } + + private void InputDigit(int digit) + { + if (op == Operator.None) { - num1 = num2; + if (overwriteNextDigit) + { + num1 = digit; + overwriteNextDigit = false; + } + else + { + num1 = (num1 * 10) + digit; + } } - op = @operator; + else + { + if (overwriteNextDigit) + { + num2 = digit; + overwriteNextDigit = false; + } + else + { + num2 = (num2 * 10) + digit; + } + } + + UpdateDisplay(); + } + + private void InputOperator(Operator nextOperator) + { + if (op != Operator.None && !overwriteNextDigit) + { + InputEquals(); + } + + op = nextOperator; num2 = 0; - RenderDisplay(); + overwriteNextDigit = false; + UpdateDisplay(); } - private void InputBksp() + private void InputBackspace() { - long num = op != Operator.None ? num2 : num1; - string numStr = num.ToString(); - if (numStr.Length > 1) + if (op == Operator.None) { - num = long.Parse(numStr.Substring(0, numStr.Length - 1)); + num1 /= 10; } else { - num = 0; + num2 /= 10; } - if (op != Operator.None) + + UpdateDisplay(); + } + + private void InputClear() + { + num1 = 0; + num2 = 0; + op = Operator.None; + overwriteNextDigit = false; + UpdateDisplay(); + } + + private void InputClearEntry() + { + if (op == Operator.None) { - num2 = num; + num1 = 0; } else { - num1 = num; + num2 = 0; } - RenderDisplay(); + + overwriteNextDigit = false; + UpdateDisplay(); } private void InputEquals() { - if (op == Operator.None) return; + if (op == Operator.None) + { + return; + } + long result = num1; switch (op) { case Operator.Add: - num1 = num1 + num2; + result = num1 + num2; break; case Operator.Subtract: - num1 = num1 - num2; + result = num1 - num2; break; case Operator.Multiply: - num1 = num1 * num2; + result = num1 * num2; break; case Operator.Divide: if (num2 == 0) { - MessageBox messageBox = new MessageBox(this, "Calculator", "Cannot divide by zero."); - messageBox.Show(); + ShowError("Cannot divide by zero."); return; } - num1 = num1 / num2; + result = num1 / num2; break; - default: - throw new Exception("Unrecognised operator."); } + + num1 = result; num2 = 0; op = Operator.None; - RenderDisplay(); + overwriteNextDigit = true; + UpdateDisplay(); } - private void RenderGridButtons() + private Button CreateButton(string text, int col, int row, Action onClick, bool accent = false, bool neutral = false) { - RenderGridButton("7", 0, 0); - RenderGridButton("8", 1, 0); - RenderGridButton("9", 2, 0); - RenderGridButton("+", 3, 0); + int x = padding + (col * (buttonWidth + buttonGap)); + int y = padding + displayHeight + padding + (row * (buttonHeight + buttonGap)); - RenderGridButton("4", 0, 1); - RenderGridButton("5", 1, 1); - RenderGridButton("6", 2, 1); - RenderGridButton("-", 3, 1); - - RenderGridButton("1", 0, 2); - RenderGridButton("2", 1, 2); - RenderGridButton("3", 2, 2); - RenderGridButton("*", 3, 2); - - RenderGridButton("0", 0, 3); - RenderGridButton("<-", 1, 3); - RenderGridButton("=", 2, 3); - RenderGridButton("/", 3, 3); + Button button = new Button(window, x, y, buttonWidth, buttonHeight); + button.Text = text; + if (accent) + { + button.Background = UITheme.Accent; + button.Border = UITheme.AccentDark; + button.Foreground = Color.White; + } + else if (neutral) + { + button.Background = UITheme.SurfaceMuted; + button.Border = UITheme.SurfaceBorder; + button.Foreground = UITheme.TextPrimary; + } + button.OnClick = (_, _) => onClick(); + wm.AddWindow(button); + return button; } public override void Start() { base.Start(); - window = new AppWindow(this, 256, 256, gridButtonSize * 4, (gridButtonSize * 4) + resultHeight); + + int width = padding * 2 + (buttonWidth * 4) + (buttonGap * 3); + int buttonRows = 5; + int height = padding + displayHeight + padding + (buttonRows * buttonHeight) + ((buttonRows - 1) * buttonGap) + padding + statusHeight; + + window = new AppWindow(this, 260, 170, width, height); + window.Title = "Calculator"; + window.Icon = AppManager.GetAppMetadata("Calculator").Icon; + window.Closing = TryStop; wm.AddWindow(window); - window.Title = "Calculator"; - window.Clear(Color.Gray); - window.Icon = AppManager.GetAppMetadata("Calculator").Icon; - window.OnClick = WindowClick; - window.Closing = TryStop; + expressionBlock = new TextBlock(window, padding, padding, width - (padding * 2), 18); + expressionBlock.Background = UITheme.Surface; + expressionBlock.Foreground = UITheme.TextSecondary; + expressionBlock.HorizontalAlignment = Alignment.End; + wm.AddWindow(expressionBlock); - /*inputTextBlock = new TextBlock(window, padding / 2, padding / 2, window.Width - padding, resultHeight - padding); - inputTextBlock.Background = Color.Gray; - inputTextBlock.Foreground = Color.White; - wm.AddWindow(inputTextBlock);*/ + displayBlock = new TextBlock(window, padding, padding + 22, width - (padding * 2), 42); + displayBlock.Background = UITheme.Surface; + displayBlock.Foreground = UITheme.TextPrimary; + displayBlock.HorizontalAlignment = Alignment.End; + displayBlock.VerticalAlignment = Alignment.Middle; + wm.AddWindow(displayBlock); - RenderDisplay(updateWindow: false); + Separator separator = new Separator(window, padding, padding + displayHeight, width - (padding * 2), 8); + separator.Background = UITheme.Surface; + separator.Foreground = UITheme.SurfaceBorder; + wm.AddWindow(separator); - RenderGridButtons(); + CreateButton("C", 0, 0, InputClear, neutral: true); + CreateButton("Bk", 1, 0, InputBackspace, neutral: true); + CreateButton("/", 2, 0, () => InputOperator(Operator.Divide), neutral: true); + CreateButton("*", 3, 0, () => InputOperator(Operator.Multiply), neutral: true); + CreateButton("7", 0, 1, () => InputDigit(7)); + CreateButton("8", 1, 1, () => InputDigit(8)); + CreateButton("9", 2, 1, () => InputDigit(9)); + CreateButton("-", 3, 1, () => InputOperator(Operator.Subtract), neutral: true); + + CreateButton("4", 0, 2, () => InputDigit(4)); + CreateButton("5", 1, 2, () => InputDigit(5)); + CreateButton("6", 2, 2, () => InputDigit(6)); + CreateButton("+", 3, 2, () => InputOperator(Operator.Add), neutral: true); + + CreateButton("1", 0, 3, () => InputDigit(1)); + CreateButton("2", 1, 3, () => InputDigit(2)); + CreateButton("3", 2, 3, () => InputDigit(3)); + CreateButton("=", 3, 3, InputEquals, accent: true); + + CreateButton("0", 0, 4, () => InputDigit(0)); + CreateButton("00", 1, 4, () => + { + InputDigit(0); + InputDigit(0); + }); + CreateButton("CE", 2, 4, InputClearEntry, neutral: true); + CreateButton("=", 3, 4, InputEquals, accent: true); + + statusBar = new StatusBar(window, 0, height - statusHeight, width, statusHeight); + wm.AddWindow(statusBar); + + InputClear(); wm.Update(window); } public override void Run() { - } } }