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()
{
-
}
}
}