1using CommunityToolkit.Mvvm.ComponentModel;
2using CommunityToolkit.Mvvm.Input;
5using System.Collections.ObjectModel;
6using System.ComponentModel;
7using System.Globalization;
27 this.MemoryItems = [];
31 this.Entry = Args.
Entry;
35 if (this.Entry is not
null)
36 this.Value = this.Entry.Text;
37 else if (this.ViewModel is not
null && this.Property is not
null)
38 this.Value = this.ViewModel.GetValue(this.Property)?.ToString() ??
string.Empty;
40 this.Value =
string.Empty;
43 this.DecimalSeparator = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator;
44 this.DisplayMain =
true;
45 this.DisplayFunctions =
false;
46 this.DisplayHyperbolic =
false;
47 this.DisplayInverse =
false;
48 this.DisplayEndParenthesis =
false;
49 this.DisplayEquals =
true;
50 this.Status =
string.Empty;
52 this.Entering =
false;
53 this.NrParentheses = 0;
54 this.HasValue = !
string.IsNullOrEmpty(this.Value);
55 this.HasStatistics =
false;
63 await base.OnDispose();
71 base.OnPropertyChanged(e);
73 switch (e.PropertyName)
75 case nameof(this.Value):
76 this.HasValue = !
string.IsNullOrEmpty(this.Value);
78 if (this.Entry is not
null)
79 this.Entry.Text = this.Value;
81 if (this.ViewModel is not
null && this.Property is not
null)
82 this.ViewModel.SetValue(this.Property, this.Value);
85 case nameof(this.NrParentheses):
86 case nameof(this.DisplayFunctions):
87 case nameof(this.DisplayHyperbolic):
88 case nameof(this.DisplayInverse):
98 private string? value;
104 private string? status;
110 private bool entering;
116 private bool hasValue;
122 private bool hasStatistics;
128 private int nrParentheses;
134 private object? memory;
140 private Entry? entry;
152 private string? property;
158 private string? decimalSeparator;
164 private bool displayMain;
170 private bool displayFunctions;
176 private bool displayHyperbolic;
182 private bool displayInverse;
188 private bool displayNotHyperbolicNotInverse;
194 private bool displayHyperbolicNotInverse;
200 private bool displayNotHyperbolicInverse;
206 private bool displayHyperbolicInverse;
212 private bool displayEquals;
218 private bool displayEndParenthesis;
220 private void CalcDisplay()
222 this.DisplayHyperbolicInverse = this.DisplayFunctions && this.DisplayHyperbolic && this.DisplayInverse;
223 this.DisplayNotHyperbolicInverse = this.DisplayFunctions && !this.DisplayHyperbolic && this.DisplayInverse;
224 this.DisplayHyperbolicNotInverse = this.DisplayFunctions && this.DisplayHyperbolic && !this.DisplayInverse;
225 this.DisplayNotHyperbolicNotInverse = this.DisplayFunctions && !this.DisplayHyperbolic && !this.DisplayInverse;
226 this.DisplayEquals = this.DisplayMain && this.NrParentheses == 0;
227 this.DisplayEndParenthesis = this.DisplayMain && this.NrParentheses > 0;
233 public ObservableCollection<StackItem>
Stack {
get; }
248 private void Toggle()
250 this.DisplayMain = !this.DisplayMain;
251 this.DisplayFunctions = !this.DisplayFunctions;
258 private void ToggleHyperbolic()
260 this.DisplayHyperbolic = !this.DisplayHyperbolic;
267 private void ToggleInverse()
269 this.DisplayInverse = !this.DisplayInverse;
276 private async Task KeyPress(
object P)
280 string Key = P?.ToString() ??
string.Empty;
304 this.Value =
string.Empty;
305 this.Entering =
true;
312 Key = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator;
314 this.Entering =
true;
320 this.Value =
string.Empty;
321 this.Entering =
false;
325 this.Value =
string.Empty;
329 this.Entering =
false;
330 this.HasStatistics =
false;
343 await this.Evaluate(
"-x");
347 await this.Evaluate(
"1/x");
351 await this.Evaluate(
"x%");
355 await this.Evaluate(
"x‰");
359 await this.Evaluate(
"x°");
363 await this.Evaluate(
"x^2");
367 await this.Evaluate(
"sqrt(x)");
371 await this.Evaluate(
"10^x");
375 await this.Evaluate(
"2^x");
379 await this.Evaluate(
"x*180/pi");
418 if (this.
Stack.Count > 0)
420 this.
Stack[^1].StartParenthesis =
true;
427 await this.Evaluate(
string.Empty,
"=",
OperatorPriority.Parenthesis,
false);
428 if (this.
Stack.Count > 0)
430 this.
Stack[^1].StartParenthesis =
false;
465 await this.Evaluate(Key +
"(x)");
475 await this.Evaluate(Key +
"(x)");
479 await this.Evaluate(
"x-floor(x)");
485 await this.AddToMemory();
489 await this.SubtractFromMemory();
494 this.Entering =
false;
503 await this.EvaluateStatistics(Key +
"(x)");
509 this.Status = ex.Message;
513 private async Task<object> Evaluate()
515 if (
string.IsNullOrEmpty(this.Value))
528 private async Task Evaluate(
string Script)
530 object x = await this.Evaluate();
541 this.Entering =
false;
549 private async Task Evaluate(
string Script,
string Operator,
OperatorPriority Priority,
bool StartParenthesis)
551 object x = await this.Evaluate();
553 int c = this.
Stack.Count;
558 while (c > 0 && (Item = this.
Stack[c - 1]).Priority >= Priority && !Item.StartParenthesis)
562 this.Value = Item.Entry ??
string.Empty;
563 x = await this.Evaluate();
575 this.Entering =
false;
583 this.
Stack.RemoveAt(c);
586 if (!
string.IsNullOrEmpty(Script))
588 this.
Stack.Add(
new StackItem()
594 StartParenthesis = StartParenthesis
597 this.Value =
string.Empty;
600 this.Entering =
false;
604 private async Task EvaluateStatistics(
string Script)
620 this.Entering =
false;
635 StringBuilder sb =
new();
637 int NrParantheses = 0;
639 bool StartParenthesis =
false;
648 if (Item.
Priority < PrevPriority || StartParenthesis)
657 sb.Append(Item.
Entry);
662 if (StartParenthesis)
668 this.NrParentheses = NrParantheses;
670 while (NrParantheses > 0)
676 return sb.ToString();
693 if (this.
Stack.Count == 0 &&
string.IsNullOrEmpty(
this.Value))
718 if (this.Memory is
null)
721 StringBuilder sb =
new();
726 sb.Append(this.MemoryItems.Count.ToString(CultureInfo.InvariantCulture));
729 return sb.ToString();
733 private async Task AddToMemory()
737 object x = await this.Evaluate();
739 this.MemoryItems.Add(x);
741 if (this.Memory is
null)
747 v[
"M"] = this.Memory;
753 this.HasStatistics =
true;
757 private async Task SubtractFromMemory()
761 object x = await this.Evaluate();
763 this.MemoryItems.Add(x);
765 if (this.Memory is
null)
777 v[
"M"] = this.Memory;
783 this.HasStatistics =
true;
Base class that references services in the app.
static IStringLocalizer Localizer
Localization service
A base class for all view models, inheriting from the BindableObject. NOTE: using this class requir...
Holds navigation parameters for the calculator.
Entry? Entry
Entry whose value is being calculated.
string? Property
Property containing the value to calculate.
BaseViewModel? ViewModel
View model containing a bindable property with the value to calculate.
The view model to bind to for when displaying the calculator.
ObservableCollection< StackItem > Stack
Holds the contents of the calculation stack
ObservableCollection< object > MemoryItems
Holds the contents of the memory
Task EvaluateStack()
Evaluates the current stack.
async Task EvaluateStack(bool IgnoreError)
Evaluates the current stack.
string MemoryString
String representation of contents on the statistical memory.
string StackString
String representation of contents on the stack.
override void OnPropertyChanged(PropertyChangedEventArgs e)
CalculatorViewModel(CalculatorNavigationArgs? Args)
Creates an instance of the CalculatorViewModel class.
override async Task OnDispose()
Method called when the view is disposed, and will not be used more. Use this method to unregister eve...
string? Operator
Operator to display
OperatorPriority Priority
Priority level
bool StartParenthesis
If parenthesis was started
A view model that holds the XMPP state.
Class managing a script expression.
static Task< object > EvalAsync(string Script)
Evaluates script, in string format.
static IElement Encapsulate(object Value)
Encapsulates an object.
static string ToString(double Value)
Converts a value to a string, that can be parsed as part of an expression.
static IElement Encapsulate(Array Elements, bool CanEncapsulateAsMatrix, ScriptNode Node)
Encapsulates the elements of a vector.
Basic interface for all types of elements.
OperatorPriority
Binary operator priority