mirror of
https://github.com/Leonmmcoset/CMLeonOS.git
synced 2026-04-21 19:24:00 +00:00
重写计算器
This commit is contained in:
@@ -1 +1 @@
|
|||||||
2026-03-26 20:46:03
|
2026-03-26 21:30:36
|
||||||
@@ -1 +1 @@
|
|||||||
312acd9
|
cd6fee6
|
||||||
@@ -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()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user