Files
CMLeonOS/Gui/Apps/Calculator.cs

308 lines
9.6 KiB
C#
Raw Normal View History

2026-03-08 20:22:53 +08:00
// 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 <https://www.gnu.org/licenses/>.
2026-03-01 17:03:49 +08:00
using CMLeonOS;
using CMLeonOS.Gui.UILib;
using System;
using System.Drawing;
namespace CMLeonOS.Gui.Apps
{
internal class Calculator : Process
{
internal Calculator() : base("Calculator", ProcessType.Application) { }
private enum Operator
{
None,
Add,
Subtract,
Multiply,
Divide
}
2026-03-26 21:34:16 +08:00
private AppWindow window;
private TextBlock expressionBlock;
private TextBlock displayBlock;
private StatusBar statusBar;
2026-03-01 17:03:49 +08:00
2026-03-26 21:34:16 +08:00
private readonly WindowManager wm = ProcessManager.GetProcess<WindowManager>();
2026-03-01 17:03:49 +08:00
2026-03-26 21:34:16 +08:00
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;
2026-03-01 17:03:49 +08:00
private long num1 = 0;
private long num2 = 0;
private Operator op = Operator.None;
2026-03-26 21:34:16 +08:00
private bool overwriteNextDigit = false;
2026-03-01 17:03:49 +08:00
2026-03-26 21:34:16 +08:00
private string OperatorText
2026-03-01 17:03:49 +08:00
{
2026-03-26 21:34:16 +08:00
get
{
return op switch
{
Operator.Add => "+",
Operator.Subtract => "-",
Operator.Multiply => "*",
Operator.Divide => "/",
_ => string.Empty
};
}
2026-03-01 17:03:49 +08:00
}
2026-03-26 21:34:16 +08:00
private void UpdateDisplay()
2026-03-01 17:03:49 +08:00
{
2026-03-26 21:34:16 +08:00
if (op == Operator.None)
2026-03-01 17:03:49 +08:00
{
2026-03-26 21:34:16 +08:00
expressionBlock.Text = "Current Value";
displayBlock.Text = num1.ToString();
2026-03-01 17:03:49 +08:00
}
2026-03-26 21:34:16 +08:00
else
2026-03-01 17:03:49 +08:00
{
2026-03-26 21:34:16 +08:00
expressionBlock.Text = $"{num1} {OperatorText}";
displayBlock.Text = num2.ToString();
2026-03-01 17:03:49 +08:00
}
2026-03-26 21:34:16 +08:00
string state = op == Operator.None ? "Ready" : $"Operator: {OperatorText}";
statusBar.Text = state;
statusBar.DetailText = "Integer Mode";
}
private void ShowError(string text)
{
new MessageBox(this, "Calculator", text).Show();
2026-03-01 17:03:49 +08:00
}
2026-03-26 21:34:16 +08:00
private void InputDigit(int digit)
2026-03-01 17:03:49 +08:00
{
2026-03-26 21:34:16 +08:00
if (op == Operator.None)
2026-03-01 17:03:49 +08:00
{
2026-03-26 21:34:16 +08:00
if (overwriteNextDigit)
2026-03-01 17:03:49 +08:00
{
2026-03-26 21:34:16 +08:00
num1 = digit;
overwriteNextDigit = false;
}
else
{
num1 = (num1 * 10) + digit;
}
2026-03-01 17:03:49 +08:00
}
else
{
2026-03-26 21:34:16 +08:00
if (overwriteNextDigit)
{
num2 = digit;
overwriteNextDigit = false;
}
else
{
num2 = (num2 * 10) + digit;
}
2026-03-01 17:03:49 +08:00
}
2026-03-26 21:34:16 +08:00
UpdateDisplay();
}
private void InputOperator(Operator nextOperator)
{
if (op != Operator.None && !overwriteNextDigit)
2026-03-01 17:03:49 +08:00
{
2026-03-26 21:34:16 +08:00
InputEquals();
2026-03-01 17:03:49 +08:00
}
2026-03-26 21:34:16 +08:00
op = nextOperator;
num2 = 0;
overwriteNextDigit = false;
UpdateDisplay();
2026-03-01 17:03:49 +08:00
}
2026-03-26 21:34:16 +08:00
private void InputBackspace()
2026-03-01 17:03:49 +08:00
{
2026-03-26 21:34:16 +08:00
if (op == Operator.None)
2026-03-01 17:03:49 +08:00
{
2026-03-26 21:34:16 +08:00
num1 /= 10;
2026-03-01 17:03:49 +08:00
}
else
{
2026-03-26 21:34:16 +08:00
num2 /= 10;
2026-03-01 17:03:49 +08:00
}
2026-03-26 21:34:16 +08:00
UpdateDisplay();
2026-03-01 17:03:49 +08:00
}
2026-03-26 21:34:16 +08:00
private void InputClear()
2026-03-01 17:03:49 +08:00
{
2026-03-26 21:34:16 +08:00
num1 = 0;
2026-03-01 17:03:49 +08:00
num2 = 0;
2026-03-26 21:34:16 +08:00
op = Operator.None;
overwriteNextDigit = false;
UpdateDisplay();
2026-03-01 17:03:49 +08:00
}
2026-03-26 21:34:16 +08:00
private void InputClearEntry()
2026-03-01 17:03:49 +08:00
{
2026-03-26 21:34:16 +08:00
if (op == Operator.None)
2026-03-01 17:03:49 +08:00
{
2026-03-26 21:34:16 +08:00
num1 = 0;
2026-03-01 17:03:49 +08:00
}
else
{
2026-03-26 21:34:16 +08:00
num2 = 0;
2026-03-01 17:03:49 +08:00
}
2026-03-26 21:34:16 +08:00
overwriteNextDigit = false;
UpdateDisplay();
2026-03-01 17:03:49 +08:00
}
private void InputEquals()
{
2026-03-26 21:34:16 +08:00
if (op == Operator.None)
{
return;
}
2026-03-01 17:03:49 +08:00
2026-03-26 21:34:16 +08:00
long result = num1;
2026-03-01 17:03:49 +08:00
switch (op)
{
case Operator.Add:
2026-03-26 21:34:16 +08:00
result = num1 + num2;
2026-03-01 17:03:49 +08:00
break;
case Operator.Subtract:
2026-03-26 21:34:16 +08:00
result = num1 - num2;
2026-03-01 17:03:49 +08:00
break;
case Operator.Multiply:
2026-03-26 21:34:16 +08:00
result = num1 * num2;
2026-03-01 17:03:49 +08:00
break;
case Operator.Divide:
if (num2 == 0)
{
2026-03-26 21:34:16 +08:00
ShowError("Cannot divide by zero.");
2026-03-01 17:03:49 +08:00
return;
}
2026-03-26 21:34:16 +08:00
result = num1 / num2;
2026-03-01 17:03:49 +08:00
break;
}
2026-03-26 21:34:16 +08:00
num1 = result;
2026-03-01 17:03:49 +08:00
num2 = 0;
op = Operator.None;
2026-03-26 21:34:16 +08:00
overwriteNextDigit = true;
UpdateDisplay();
2026-03-01 17:03:49 +08:00
}
2026-03-26 21:34:16 +08:00
private Button CreateButton(string text, int col, int row, Action onClick, bool accent = false, bool neutral = false)
2026-03-01 17:03:49 +08:00
{
2026-03-26 21:34:16 +08:00
int x = padding + (col * (buttonWidth + buttonGap));
int y = padding + displayHeight + padding + (row * (buttonHeight + buttonGap));
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;
2026-03-01 17:03:49 +08:00
}
public override void Start()
{
base.Start();
2026-03-26 21:34:16 +08:00
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);
2026-03-01 17:03:49 +08:00
window.Title = "Calculator";
window.Icon = AppManager.GetAppMetadata("Calculator").Icon;
window.Closing = TryStop;
2026-03-26 21:34:16 +08:00
wm.AddWindow(window);
2026-03-01 17:03:49 +08:00
2026-03-26 21:34:16 +08:00
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);
2026-03-01 17:03:49 +08:00
2026-03-26 21:34:16 +08:00
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);
2026-03-01 17:03:49 +08:00
2026-03-26 21:34:16 +08:00
Separator separator = new Separator(window, padding, padding + displayHeight, width - (padding * 2), 8);
separator.Background = UITheme.Surface;
separator.Foreground = UITheme.SurfaceBorder;
wm.AddWindow(separator);
2026-03-01 17:03:49 +08:00
2026-03-26 21:34:16 +08:00
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();
2026-03-01 17:03:49 +08:00
wm.Update(window);
}
public override void Run()
{
}
}
}