重写计算器

This commit is contained in:
2026-03-26 21:34:16 +08:00
parent cd6fee644c
commit 7a7d44e9d8
3 changed files with 189 additions and 188 deletions

View File

@@ -1 +1 @@
2026-03-26 20:46:03 2026-03-26 21:30:36

View File

@@ -1 +1 @@
312acd9 cd6fee6

View File

@@ -14,7 +14,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
using Cosmos.System.Graphics;
using CMLeonOS; using CMLeonOS;
using CMLeonOS.Gui.UILib; using CMLeonOS.Gui.UILib;
using System; using System;
@@ -26,10 +25,6 @@ namespace CMLeonOS.Gui.Apps
{ {
internal Calculator() : base("Calculator", ProcessType.Application) { } internal Calculator() : base("Calculator", ProcessType.Application) { }
AppWindow window;
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
private enum Operator private enum Operator
{ {
None, None,
@@ -39,268 +34,274 @@ namespace CMLeonOS.Gui.Apps
Divide Divide
} }
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Calculator.GridButton.bmp")] private AppWindow window;
private static byte[] gridButtonBytes; private TextBlock expressionBlock;
private static Bitmap gridButtonBitmap = new Bitmap(gridButtonBytes); private TextBlock displayBlock;
private StatusBar statusBar;
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Calculator.Display.bmp")] private readonly WindowManager wm = ProcessManager.GetProcess<WindowManager>();
private static byte[] displayBytes;
private static Bitmap displayBitmap = new Bitmap(displayBytes);
private const int padding = 16; private const int padding = 12;
private const int gridButtonSize = 40; private const int buttonWidth = 68;
private const int resultHeight = 40; 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 num1 = 0;
private long num2 = 0; private long num2 = 0;
private Operator op = Operator.None; 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); get
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; return op switch
int gridY = (y - resultHeight) / gridButtonSize;
if (gridY < 0)
{ {
return; Operator.Add => "+",
} Operator.Subtract => "-",
switch (gridY) Operator.Multiply => "*",
{ Operator.Divide => "/",
case 0: _ => string.Empty
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
{
Operator.Add => '+',
Operator.Subtract => '-',
Operator.Multiply => '*',
Operator.Divide => '/',
_ => throw new Exception("Unrecognised operator.")
}; };
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 else
{ {
num1 = long.Parse(num1.ToString() + num); expressionBlock.Text = $"{num1} {OperatorText}";
} displayBlock.Text = num2.ToString();
RenderDisplay();
} }
private void InputOp(Operator @operator) string state = op == Operator.None ? "Ready" : $"Operator: {OperatorText}";
{ statusBar.Text = state;
if (op != Operator.None) statusBar.DetailText = "Integer Mode";
{
num1 = num2;
} }
op = @operator;
private void ShowError(string text)
{
new MessageBox(this, "Calculator", text).Show();
}
private void InputDigit(int digit)
{
if (op == Operator.None)
{
if (overwriteNextDigit)
{
num1 = digit;
overwriteNextDigit = false;
}
else
{
num1 = (num1 * 10) + digit;
}
}
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; num2 = 0;
RenderDisplay(); overwriteNextDigit = false;
UpdateDisplay();
} }
private void InputBksp() private void InputBackspace()
{ {
long num = op != Operator.None ? num2 : num1; if (op == Operator.None)
string numStr = num.ToString();
if (numStr.Length > 1)
{ {
num = long.Parse(numStr.Substring(0, numStr.Length - 1)); num1 /= 10;
} }
else else
{ {
num = 0; num2 /= 10;
} }
if (op != Operator.None)
UpdateDisplay();
}
private void InputClear()
{ {
num2 = num; num1 = 0;
num2 = 0;
op = Operator.None;
overwriteNextDigit = false;
UpdateDisplay();
}
private void InputClearEntry()
{
if (op == Operator.None)
{
num1 = 0;
} }
else else
{ {
num1 = num; num2 = 0;
} }
RenderDisplay();
overwriteNextDigit = false;
UpdateDisplay();
} }
private void InputEquals() private void InputEquals()
{ {
if (op == Operator.None) return; if (op == Operator.None)
{
return;
}
long result = num1;
switch (op) switch (op)
{ {
case Operator.Add: case Operator.Add:
num1 = num1 + num2; result = num1 + num2;
break; break;
case Operator.Subtract: case Operator.Subtract:
num1 = num1 - num2; result = num1 - num2;
break; break;
case Operator.Multiply: case Operator.Multiply:
num1 = num1 * num2; result = num1 * num2;
break; break;
case Operator.Divide: case Operator.Divide:
if (num2 == 0) if (num2 == 0)
{ {
MessageBox messageBox = new MessageBox(this, "Calculator", "Cannot divide by zero."); ShowError("Cannot divide by zero.");
messageBox.Show();
return; return;
} }
num1 = num1 / num2; result = num1 / num2;
break; break;
default:
throw new Exception("Unrecognised operator.");
} }
num1 = result;
num2 = 0; num2 = 0;
op = Operator.None; 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); int x = padding + (col * (buttonWidth + buttonGap));
RenderGridButton("8", 1, 0); int y = padding + displayHeight + padding + (row * (buttonHeight + buttonGap));
RenderGridButton("9", 2, 0);
RenderGridButton("+", 3, 0);
RenderGridButton("4", 0, 1); Button button = new Button(window, x, y, buttonWidth, buttonHeight);
RenderGridButton("5", 1, 1); button.Text = text;
RenderGridButton("6", 2, 1); if (accent)
RenderGridButton("-", 3, 1); {
button.Background = UITheme.Accent;
RenderGridButton("1", 0, 2); button.Border = UITheme.AccentDark;
RenderGridButton("2", 1, 2); button.Foreground = Color.White;
RenderGridButton("3", 2, 2); }
RenderGridButton("*", 3, 2); else if (neutral)
{
RenderGridButton("0", 0, 3); button.Background = UITheme.SurfaceMuted;
RenderGridButton("<-", 1, 3); button.Border = UITheme.SurfaceBorder;
RenderGridButton("=", 2, 3); button.Foreground = UITheme.TextPrimary;
RenderGridButton("/", 3, 3); }
button.OnClick = (_, _) => onClick();
wm.AddWindow(button);
return button;
} }
public override void Start() public override void Start()
{ {
base.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); wm.AddWindow(window);
window.Title = "Calculator"; expressionBlock = new TextBlock(window, padding, padding, width - (padding * 2), 18);
window.Clear(Color.Gray); expressionBlock.Background = UITheme.Surface;
window.Icon = AppManager.GetAppMetadata("Calculator").Icon; expressionBlock.Foreground = UITheme.TextSecondary;
window.OnClick = WindowClick; expressionBlock.HorizontalAlignment = Alignment.End;
window.Closing = TryStop; wm.AddWindow(expressionBlock);
/*inputTextBlock = new TextBlock(window, padding / 2, padding / 2, window.Width - padding, resultHeight - padding); displayBlock = new TextBlock(window, padding, padding + 22, width - (padding * 2), 42);
inputTextBlock.Background = Color.Gray; displayBlock.Background = UITheme.Surface;
inputTextBlock.Foreground = Color.White; displayBlock.Foreground = UITheme.TextPrimary;
wm.AddWindow(inputTextBlock);*/ 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); wm.Update(window);
} }
public override void Run() public override void Run()
{ {
} }
} }
} }