diff --git a/src/AdvancedCalculator/Converters/CategoryToBrushConverter.cs b/src/AdvancedCalculator/Converters/CategoryToBrushConverter.cs new file mode 100644 index 0000000..ebddb1c --- /dev/null +++ b/src/AdvancedCalculator/Converters/CategoryToBrushConverter.cs @@ -0,0 +1,31 @@ +using System; +using System.Globalization; +using Avalonia.Data.Converters; +using Avalonia.Media; +using AdvancedCalculator.Models; + +namespace AdvancedCalculator.Converters; + +public class CategoryToBrushConverter : IValueConverter +{ + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + if (value is not FunctionCategory cat) return Brushes.Gray; + + // Soft header background colors per category + return cat switch + { + FunctionCategory.Base => new SolidColorBrush(Color.FromRgb(0xE3, 0xF2, 0xFD)), // light blue 50 + FunctionCategory.Angle => new SolidColorBrush(Color.FromRgb(0xE8, 0xF5, 0xE9)), // green 50 + FunctionCategory.Rounding => new SolidColorBrush(Color.FromRgb(0xFF, 0xF3, 0xE0)), // orange 50 + FunctionCategory.Trigonometry => new SolidColorBrush(Color.FromRgb(0xF3, 0xE5, 0xF5)), // purple 50 + FunctionCategory.HyperbolicTrig => new SolidColorBrush(Color.FromRgb(0xE0, 0xF7, 0xFA)), // cyan 50 + FunctionCategory.NumberTheory => new SolidColorBrush(Color.FromRgb(0xFF, 0xFD, 0xE7)), // yellow 50 + FunctionCategory.Random => new SolidColorBrush(Color.FromRgb(0xFC, 0xE4, 0xEC)), // pink 50 + _ => Brushes.Gray + }; + } + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => throw new NotSupportedException(); +} + diff --git a/src/AdvancedCalculator/Models/FunctionDefinitionItem.cs b/src/AdvancedCalculator/Models/FunctionDefinitionItem.cs index 4cfbb1d..842d9a9 100644 --- a/src/AdvancedCalculator/Models/FunctionDefinitionItem.cs +++ b/src/AdvancedCalculator/Models/FunctionDefinitionItem.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; namespace AdvancedCalculator.Models; @@ -6,23 +7,115 @@ public class FunctionDefinitionItem { public string FunctionName { get; private set; } = string.Empty; public string FunctionDescription { get; private set; } = string.Empty; - public string Icon { get; private set; } = string.Empty; public IEnumerable> FunctionArguments { get; private set; } = new List>(); + public FunctionCategory Category { get; private set; } + + public string Signature => $"{FunctionName}({string.Join(", ", FunctionArguments.Select(a => a.Key))})"; public static IEnumerable DefinedFunctions { get { - yield return new FunctionDefinitionItem { FunctionName = "sin", Icon = IconFont.SineWave, FunctionDescription = "Returns the sine value of a given expression.", FunctionArguments = new[] { new KeyValuePair("expression", "An expression to compute.") } }; - yield return new FunctionDefinitionItem { FunctionName = "cos", Icon = IconFont.CosineWave, FunctionDescription = "Returns the cosine value of a given expression.", FunctionArguments = new[] { new KeyValuePair("expression", "An expression to compute.") } }; - yield return new FunctionDefinitionItem { FunctionName = "tan", Icon = IconFont.MathTan, FunctionDescription = "Returns the tangent value of a given expression.", FunctionArguments = new[] { new KeyValuePair("expression", "An expression to compute.") } }; - yield return new FunctionDefinitionItem { FunctionName = "round", Icon = IconFont.RoundedCorner, FunctionDescription = "Rounds an expression to the nearest whole number.", FunctionArguments = new[] { new KeyValuePair("expression", "An expression to compute.") } }; - yield return new FunctionDefinitionItem { FunctionName = "sqrt", Icon = IconFont.SquareRoot, FunctionDescription = "Returns the square root of a given expression.", FunctionArguments = new[] { new KeyValuePair("expression", "An expression to compute.") } }; - yield return new FunctionDefinitionItem { FunctionName = "abs", Icon = IconFont.PlusCircle, FunctionDescription = "Returns the absolute value of a given expression.", FunctionArguments = new[] { new KeyValuePair("expression", "An expression to compute.") } }; - yield return new FunctionDefinitionItem { FunctionName = "exp", Icon = IconFont.AlphaECircle, FunctionDescription = "Returns the constant e to a given power.", FunctionArguments = new[] { new KeyValuePair("power", "An expression to compute.") } }; - yield return new FunctionDefinitionItem { FunctionName = "log", Icon = IconFont.MathLog, FunctionDescription = "Returns the log of the first expression to the base of the second expression.", FunctionArguments = new[] { new KeyValuePair("value", "An expression to compute."), new KeyValuePair("base", "An expression to compute.") } }; - yield return new FunctionDefinitionItem { FunctionName = "precision", Icon = IconFont.DecimalIncrease, FunctionDescription = "Returns the value of expression1 to a given precision.", FunctionArguments = new[] { new KeyValuePair("value", "An expression to compute."), new KeyValuePair("precision", "An expression to compute.") } }; + // Base + yield return new FunctionDefinitionItem { FunctionName = "abs", Category = FunctionCategory.Base, FunctionDescription = "Absolute value of a number.", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "sign", Category = FunctionCategory.Base, FunctionDescription = "Sign of a number: 1 or -1.", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "min", Category = FunctionCategory.Base, FunctionDescription = "Minimum of two numbers.", FunctionArguments = new[] { new KeyValuePair("first", "number"), new KeyValuePair("second", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "max", Category = FunctionCategory.Base, FunctionDescription = "Maximum of two numbers.", FunctionArguments = new[] { new KeyValuePair("first", "number"), new KeyValuePair("second", "number") } }; + + // Angle + yield return new FunctionDefinitionItem { FunctionName = "degrees", Category = FunctionCategory.Angle, FunctionDescription = "Converts radians to degrees.", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "radians", Category = FunctionCategory.Angle, FunctionDescription = "Converts degrees to radians.", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "wrapangle", Category = FunctionCategory.Angle, FunctionDescription = "Wraps angle into [start, end).", FunctionArguments = new[] { new KeyValuePair("value", "number"), new KeyValuePair("periodStart", "number"), new KeyValuePair("periodEnd", "number") } }; + + // Rounding + yield return new FunctionDefinitionItem { FunctionName = "floor", Category = FunctionCategory.Rounding, FunctionDescription = "Largest integer ≤ value.", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "ceiling", Category = FunctionCategory.Rounding, FunctionDescription = "Smallest integer ≥ value.", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "truncate", Category = FunctionCategory.Rounding, FunctionDescription = "Integer part toward zero.", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "round", Category = FunctionCategory.Rounding, FunctionDescription = "Round to precision (banker's).", FunctionArguments = new[] { new KeyValuePair("value", "number"), new KeyValuePair("precision", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "frac", Category = FunctionCategory.Rounding, FunctionDescription = "Fractional part of a number.", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "clamp", Category = FunctionCategory.Rounding, FunctionDescription = "Clamp to [low, high].", FunctionArguments = new[] { new KeyValuePair("value", "number"), new KeyValuePair("low", "number"), new KeyValuePair("high", "number") } }; + + // Trigonometry + yield return new FunctionDefinitionItem { FunctionName = "sin", Category = FunctionCategory.Trigonometry, FunctionDescription = "Sine of angle (radians).", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "cos", Category = FunctionCategory.Trigonometry, FunctionDescription = "Cosine of angle (radians).", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "tan", Category = FunctionCategory.Trigonometry, FunctionDescription = "Tangent of angle (radians).", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "asin", Category = FunctionCategory.Trigonometry, FunctionDescription = "Arcsine (radians).", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "acos", Category = FunctionCategory.Trigonometry, FunctionDescription = "Arccosine (radians).", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "atan", Category = FunctionCategory.Trigonometry, FunctionDescription = "Arctangent (radians).", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "atan2", Category = FunctionCategory.Trigonometry, FunctionDescription = "Arctan(y/x) (radians).", FunctionArguments = new[] { new KeyValuePair("y", "number"), new KeyValuePair("x", "number") } }; + + // Hyperbolic Trig + yield return new FunctionDefinitionItem { FunctionName = "sinh", Category = FunctionCategory.HyperbolicTrig, FunctionDescription = "Hyperbolic sine.", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "cosh", Category = FunctionCategory.HyperbolicTrig, FunctionDescription = "Hyperbolic cosine.", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "tanh", Category = FunctionCategory.HyperbolicTrig, FunctionDescription = "Hyperbolic tangent.", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "asinh", Category = FunctionCategory.HyperbolicTrig, FunctionDescription = "Inverse hyperbolic sine.", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "acosh", Category = FunctionCategory.HyperbolicTrig, FunctionDescription = "Inverse hyperbolic cosine.", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "atanh", Category = FunctionCategory.HyperbolicTrig, FunctionDescription = "Inverse hyperbolic tangent.", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + + // Number Theory + yield return new FunctionDefinitionItem { FunctionName = "fac", Category = FunctionCategory.NumberTheory, FunctionDescription = "Factorial; Γ(n+1) for non-integers; 0 outside 0..20.", FunctionArguments = new[] { new KeyValuePair("value", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "ncr", Category = FunctionCategory.NumberTheory, FunctionDescription = "Binomial coefficient 0 ≤ r ≤ n ≤ 20.", FunctionArguments = new[] { new KeyValuePair("first", "number"), new KeyValuePair("second", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "npr", Category = FunctionCategory.NumberTheory, FunctionDescription = "Permutations 0 ≤ r ≤ n ≤ 20.", FunctionArguments = new[] { new KeyValuePair("first", "number"), new KeyValuePair("second", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "gcd", Category = FunctionCategory.NumberTheory, FunctionDescription = "GCD of two positive integers.", FunctionArguments = new[] { new KeyValuePair("first", "number"), new KeyValuePair("second", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "lcm", Category = FunctionCategory.NumberTheory, FunctionDescription = "LCM of two positive integers.", FunctionArguments = new[] { new KeyValuePair("first", "number"), new KeyValuePair("second", "number") } }; + + // Random + yield return new FunctionDefinitionItem { FunctionName = "flip", Category = FunctionCategory.Random, FunctionDescription = "Fair coin flip → boolean.", FunctionArguments = Enumerable.Empty>() }; + yield return new FunctionDefinitionItem { FunctionName = "bern", Category = FunctionCategory.Random, FunctionDescription = "Bernoulli trial with probability p.", FunctionArguments = new[] { new KeyValuePair("p", "number in [0,1]") } }; + yield return new FunctionDefinitionItem { FunctionName = "rand", Category = FunctionCategory.Random, FunctionDescription = "Uniform random in [0,1).", FunctionArguments = Enumerable.Empty>() }; + yield return new FunctionDefinitionItem { FunctionName = "rands", Category = FunctionCategory.Random, FunctionDescription = "Uniform random in [lower, upper).", FunctionArguments = new[] { new KeyValuePair("lower", "number"), new KeyValuePair("upper", "number") } }; + yield return new FunctionDefinitionItem { FunctionName = "randn", Category = FunctionCategory.Random, FunctionDescription = "Standard normal N(0,1).", FunctionArguments = Enumerable.Empty>() }; + yield return new FunctionDefinitionItem { FunctionName = "randns", Category = FunctionCategory.Random, FunctionDescription = "Normal scaled by (upper − lower).", FunctionArguments = new[] { new KeyValuePair("lower", "number"), new KeyValuePair("upper", "number") } }; + } + } + + public static IEnumerable DefinedFunctionGroups + { + get + { + var groups = new[] + { + new { Category = FunctionCategory.Base, Name = "Base", Icon = IconFont.FunctionVariant }, + new { Category = FunctionCategory.Angle, Name = "Angle", Icon = IconFont.Protractor }, + new { Category = FunctionCategory.Rounding, Name = "Rounding", Icon = IconFont.Ruler }, + new { Category = FunctionCategory.Trigonometry, Name = "Trigonometry", Icon = IconFont.SineWave }, + new { Category = FunctionCategory.HyperbolicTrig, Name = "Hyperbolic Trig", Icon = IconFont.Waveform }, + new { Category = FunctionCategory.NumberTheory, Name = "Number Theory", Icon = IconFont.Abacus }, + new { Category = FunctionCategory.Random, Name = "Random", Icon = IconFont.DiceMultipleOutline }, + }; + + var all = DefinedFunctions.ToList(); + foreach (var g in groups) + { + var items = all.Where(f => f.Category == g.Category).OrderBy(f => f.FunctionName).ToList(); + if (items.Count == 0) continue; + yield return new FunctionGroup + { + Category = g.Category, + GroupName = g.Name, + Icon = g.Icon, + Functions = items + }; + } } } } +public enum FunctionCategory +{ + Base, + Angle, + Rounding, + Trigonometry, + HyperbolicTrig, + NumberTheory, + Random +} + +public class FunctionGroup +{ + public FunctionCategory Category { get; set; } + public string GroupName { get; set; } = string.Empty; + public string Icon { get; set; } = string.Empty; // MDI glyph + public IEnumerable Functions { get; set; } = new List(); +} diff --git a/src/AdvancedCalculator/Models/IconFont.cs b/src/AdvancedCalculator/Models/IconFont.cs index 07ffb75..3424fdf 100644 --- a/src/AdvancedCalculator/Models/IconFont.cs +++ b/src/AdvancedCalculator/Models/IconFont.cs @@ -6,6 +6,7 @@ public static class IconFont public const string ArrowRightDropCircle = "\U000f0059"; public const string DecimalIncrease = "\U000f01b5"; public const string Function = "\U000f0295"; + public const string FunctionVariant = "\U000f070f"; public const string PlusCircle = "\U000f0417"; public const string RoundedCorner = "\U000f0607"; public const string SquareRoot = "\U000f0784"; @@ -15,5 +16,10 @@ public static class IconFont public const string MathTan = "\U000f0c98"; public const string MathLog = "\U000f1085"; public const string CosineWave = "\U000f1479"; + public const string AngleAcute = "\U000f0937"; + public const string Protractor = "\U000f0b4f"; + public const string Ruler = "\U000f0463"; + public const string Waveform = "\U000f147c"; + public const string Abacus = "\U000f16e0"; + public const string DiceMultipleOutline = "\U000f1156"; } - diff --git a/src/AdvancedCalculator/Views/MainView.axaml b/src/AdvancedCalculator/Views/MainView.axaml index 6cd04d7..d14d902 100644 --- a/src/AdvancedCalculator/Views/MainView.axaml +++ b/src/AdvancedCalculator/Views/MainView.axaml @@ -15,6 +15,7 @@ + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +