1using CommunityToolkit.Mvvm.ComponentModel;
2using CommunityToolkit.Mvvm.Input;
6using System.Collections.ObjectModel;
7using System.ComponentModel;
8using System.Globalization;
28 this.MemoryItems = [];
32 this.Entry = Args.
Entry;
36 if (this.Entry is not
null)
37 this.Value = this.Entry.EntryData;
38 else if (this.ViewModel is not
null && this.Property is not
null)
39 this.Value = this.ViewModel.GetValue(this.Property)?.ToString() ??
string.Empty;
41 this.Value =
string.Empty;
44 this.DecimalSeparator = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator;
45 this.DisplayMain =
true;
46 this.DisplayFunctions =
false;
47 this.DisplayHyperbolic =
false;
48 this.DisplayInverse =
false;
49 this.DisplayEndParenthesis =
false;
50 this.DisplayEquals =
true;
51 this.Status =
string.Empty;
53 this.Entering =
false;
54 this.NrParentheses = 0;
55 this.HasValue = !
string.IsNullOrEmpty(this.Value);
56 this.HasStatistics =
false;
64 await base.OnDisposeAsync();
72 base.OnPropertyChanged(e);
74 switch (e.PropertyName)
76 case nameof(this.Value):
77 this.HasValue = !
string.IsNullOrEmpty(this.Value);
79 if (this.Entry is not
null)
80 this.Entry.EntryData = this.Value ??
string.Empty;
82 if (this.ViewModel is not
null && this.Property is not
null)
83 this.ViewModel.SetValue(this.Property, this.Value);
86 case nameof(this.NrParentheses):
87 case nameof(this.DisplayFunctions):
88 case nameof(this.DisplayHyperbolic):
89 case nameof(this.DisplayInverse):
99 private string? value;
105 private string? status;
111 private bool entering;
117 private bool hasValue;
123 private bool hasStatistics;
129 private int nrParentheses;
135 private object? memory;
153 private string? property;
159 private string? decimalSeparator;
165 private bool displayMain;
171 private bool displayFunctions;
177 private bool displayHyperbolic;
183 private bool displayInverse;
189 private bool displayNotHyperbolicNotInverse;
195 private bool displayHyperbolicNotInverse;
201 private bool displayNotHyperbolicInverse;
207 private bool displayHyperbolicInverse;
213 private bool displayEquals;
219 private bool displayEndParenthesis;
221 private void CalcDisplay()
223 this.DisplayHyperbolicInverse = this.DisplayFunctions && this.DisplayHyperbolic && this.DisplayInverse;
224 this.DisplayNotHyperbolicInverse = this.DisplayFunctions && !this.DisplayHyperbolic && this.DisplayInverse;
225 this.DisplayHyperbolicNotInverse = this.DisplayFunctions && this.DisplayHyperbolic && !this.DisplayInverse;
226 this.DisplayNotHyperbolicNotInverse = this.DisplayFunctions && !this.DisplayHyperbolic && !this.DisplayInverse;
227 this.DisplayEquals = this.DisplayMain && this.NrParentheses == 0;
228 this.DisplayEndParenthesis = this.DisplayMain && this.NrParentheses > 0;
234 public ObservableCollection<StackItem>
Stack {
get; }
249 private void Toggle()
251 this.DisplayMain = !this.DisplayMain;
252 this.DisplayFunctions = !this.DisplayFunctions;
259 private void ToggleHyperbolic()
261 this.DisplayHyperbolic = !this.DisplayHyperbolic;
268 private void ToggleInverse()
270 this.DisplayInverse = !this.DisplayInverse;
277 private async Task KeyPress(
object P)
281 string Key = P?.ToString() ??
string.Empty;
305 this.Value =
string.Empty;
306 this.Entering =
true;
313 Key = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator;
315 this.Entering =
true;
321 this.Value =
string.Empty;
322 this.Entering =
false;
326 this.Value =
string.Empty;
330 this.Entering =
false;
331 this.HasStatistics =
false;
344 await this.Evaluate(
"-x");
348 await this.Evaluate(
"1/x");
352 await this.Evaluate(
"x%");
356 await this.Evaluate(
"x‰");
360 await this.Evaluate(
"x°");
364 await this.Evaluate(
"x^2");
368 await this.Evaluate(
"sqrt(x)");
372 await this.Evaluate(
"10^x");
376 await this.Evaluate(
"2^x");
380 await this.Evaluate(
"x*180/pi");
419 if (this.
Stack.Count > 0)
421 this.
Stack[^1].StartParenthesis =
true;
428 await this.Evaluate(
string.Empty,
"=",
OperatorPriority.Parenthesis,
false);
429 if (this.
Stack.Count > 0)
431 this.
Stack[^1].StartParenthesis =
false;
466 await this.Evaluate(Key +
"(x)");
476 await this.Evaluate(Key +
"(x)");
480 await this.Evaluate(
"x-floor(x)");
486 await this.AddToMemory();
490 await this.SubtractFromMemory();
495 this.Entering =
false;
504 await this.EvaluateStatistics(Key +
"(x)");
510 this.Status = ex.Message;
514 private async Task<object> Evaluate()
516 if (
string.IsNullOrEmpty(this.Value))
529 private async Task Evaluate(
string Script)
531 object x = await this.Evaluate();
542 this.Entering =
false;
550 private async Task Evaluate(
string Script,
string Operator,
OperatorPriority Priority,
bool StartParenthesis)
552 object x = await this.Evaluate();
554 int c = this.
Stack.Count;
559 while (c > 0 && (Item = this.
Stack[c - 1]).Priority >= Priority && !Item.StartParenthesis)
563 this.Value = Item.Entry ??
string.Empty;
564 x = await this.Evaluate();
576 this.Entering =
false;
584 this.
Stack.RemoveAt(c);
587 if (!
string.IsNullOrEmpty(Script))
589 this.
Stack.Add(
new StackItem()
595 StartParenthesis = StartParenthesis
598 this.Value =
string.Empty;
601 this.Entering =
false;
605 private async Task EvaluateStatistics(
string Script)
621 this.Entering =
false;
636 StringBuilder sb =
new();
638 int NrParantheses = 0;
640 bool StartParenthesis =
false;
649 if (Item.
Priority < PrevPriority || StartParenthesis)
658 sb.Append(Item.
Entry);
663 if (StartParenthesis)
669 this.NrParentheses = NrParantheses;
671 while (NrParantheses > 0)
677 return sb.ToString();
694 if (this.
Stack.Count == 0 &&
string.IsNullOrEmpty(
this.Value))
719 if (this.Memory is
null)
722 StringBuilder sb =
new();
727 sb.Append(this.MemoryItems.Count.ToString(CultureInfo.InvariantCulture));
730 return sb.ToString();
734 private async Task AddToMemory()
738 object x = await this.Evaluate();
740 this.MemoryItems.Add(x);
742 if (this.Memory is
null)
748 v[
"M"] = this.Memory;
754 this.HasStatistics =
true;
758 private async Task SubtractFromMemory()
762 object x = await this.Evaluate();
764 this.MemoryItems.Add(x);
766 if (this.Memory is
null)
778 v[
"M"] = this.Memory;
784 this.HasStatistics =
true;
A strongly-typed resource class, for looking up localized strings, etc.
static string EnterValue
Looks up a localized string similar to You need to enter a value first..
static string CalculationError
Looks up a localized string similar to Unable to perform calculation..
static string EnterValidValue
Looks up a localized string similar to Enter a valid value first..
Base class that references services in the app.
static IReportingStringLocalizer Localizer
Localization service
A customizable entry control that allows setting views on the left and right sides of the entry.
A base class for all view models, inheriting from the BindableObject. NOTE: using this class requir...
Holds navigation parameters for the calculator.
CompositeEntry? 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.
override async Task OnDisposeAsync()
Method called when the view is disposed, and will not be used more. Use this method to unregister eve...
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.
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