123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- using InABox.Core;
- using NPOI.DDF;
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Linq;
- using System.Runtime.CompilerServices;
- using System.Text;
- using System.Text.RegularExpressions;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Data;
- using System.Windows.Documents;
- using System.Windows.Input;
- using System.Windows.Media;
- using System.Windows.Media.Imaging;
- using System.Windows.Shapes;
- namespace InABox.DynamicGrid
- {
- /// <summary>
- /// Interaction logic for ExpressionEditorWindow.xaml
- /// </summary>
- public partial class ExpressionEditorWindow : Window
- {
- public static List<Tuple<string, List<FunctionTemplate>>> FunctionTemplates = new();
- public List<string> Variables { get; private set; }
- public string Expression
- {
- get => Editor.Text;
- set => Editor.Text = value;
- }
- private static void RegisterFunctionTemplate(string group, string name, List<string> parameters)
- {
- var groupList = FunctionTemplates.FirstOrDefault(x => x.Item1 == group)?.Item2;
- if(groupList is null)
- {
- groupList = new List<FunctionTemplate>();
- FunctionTemplates.Add(new(group, groupList));
- }
- groupList.Add(new FunctionTemplate
- {
- Name = name,
- Parameters = parameters.ToList()
- });
- }
- private static void RegisterFunctionTemplate(string group, string name, params string[] parameters)
- => RegisterFunctionTemplate(group, name, parameters.ToList());
- static ExpressionEditorWindow()
- {
- RegisterFunctionTemplate("Math", "Abs", "x");
- RegisterFunctionTemplate("Math", "Acos", "x");
- RegisterFunctionTemplate("Math", "Asin", "x");
- RegisterFunctionTemplate("Math", "Atan", "x");
- RegisterFunctionTemplate("Math", "Ceiling", "x");
- RegisterFunctionTemplate("Math", "Cos", "x");
- RegisterFunctionTemplate("Math", "Count", "x");
- RegisterFunctionTemplate("Math", "Exp", "exp");
- RegisterFunctionTemplate("Math", "Floor", "x");
- RegisterFunctionTemplate("Math", "IEEERemainder", "x", "y");
- RegisterFunctionTemplate("Math", "Log10", "x");
- RegisterFunctionTemplate("Math", "Log", "x", "base");
- RegisterFunctionTemplate("Math", "Max", "x", "y");
- RegisterFunctionTemplate("Math", "Min", "x", "y");
- RegisterFunctionTemplate("Math", "Pow", "base", "exp");
- RegisterFunctionTemplate("Math", "Random");
- RegisterFunctionTemplate("Math", "Round", "x", "precision");
- RegisterFunctionTemplate("Math", "Sign", "x");
- RegisterFunctionTemplate("Math", "Sin", "x");
- RegisterFunctionTemplate("Math", "Sqrt", "x");
- RegisterFunctionTemplate("Math", "Tan", "x");
- RegisterFunctionTemplate("Math", "Truncate", "x");
- RegisterFunctionTemplate("Logical", "If", "condition", "exp1", "exp2");
- RegisterFunctionTemplate("Logical", "In", "value", "...");
- RegisterFunctionTemplate("Statistical", "Average", "...");
- RegisterFunctionTemplate("Statistical", "Mean", "...");
- RegisterFunctionTemplate("Statistical", "Median", "...");
- RegisterFunctionTemplate("Statistical", "Mode", "...");
- RegisterFunctionTemplate("Statistical", "Sum", "...");
- RegisterFunctionTemplate("String", "Contains", "text", "value");
- RegisterFunctionTemplate("String", "EndsWith", "text", "value");
- RegisterFunctionTemplate("String", "Length", "value");
- RegisterFunctionTemplate("String", "PadLeft", "value", "length", "character");
- RegisterFunctionTemplate("String", "PadRight", "value", "length", "character");
- RegisterFunctionTemplate("String", "StartsWith", "text", "value");
- RegisterFunctionTemplate("String", "Substring", "text", "startIndex", "length");
- RegisterFunctionTemplate("Date", "AddYears", "date", "years");
- RegisterFunctionTemplate("Date", "AddMonths", "date", "months");
- RegisterFunctionTemplate("Date", "AddDays", "date", "days");
- RegisterFunctionTemplate("Date", "AddHours", "date", "hrs");
- RegisterFunctionTemplate("Date", "AddMinutes", "date", "mins");
- RegisterFunctionTemplate("Date", "AddSeconds", "date", "secs");
- RegisterFunctionTemplate("Date", "AddMilliseconds", "date", "ms");
- RegisterFunctionTemplate("Date", "YearOf", "date");
- RegisterFunctionTemplate("Date", "MonthOf", "date");
- RegisterFunctionTemplate("Date", "DayOf", "date");
- RegisterFunctionTemplate("Date", "HourOf", "date");
- RegisterFunctionTemplate("Date", "MinuteOf", "date");
- RegisterFunctionTemplate("Date", "SecondOf", "date");
- RegisterFunctionTemplate("Date", "MillisecondOf", "date");
- RegisterFunctionTemplate("Date", "DaysBetween", "date", "date");
- RegisterFunctionTemplate("Date", "HoursBetween", "date", "date");
- RegisterFunctionTemplate("Date", "MinutesBetween", "date", "date");
- RegisterFunctionTemplate("Date", "SecondsBetween", "date", "date");
- RegisterFunctionTemplate("Date", "MillisecondsBetween", "date", "date");
- RegisterFunctionTemplate("Conversion", "Date", "value");
- RegisterFunctionTemplate("Conversion", "Date", "value", "format");
- RegisterFunctionTemplate("Conversion", "Decimal", "value");
- RegisterFunctionTemplate("Conversion", "Double", "value");
- RegisterFunctionTemplate("Conversion", "Integer", "value");
- RegisterFunctionTemplate("Conversion", "Long", "value");
- RegisterFunctionTemplate("Conversion", "String", "value");
- foreach(var function in CoreExpression.Functions)
- {
- RegisterFunctionTemplate(function.Group, function.Name, function.Parameters);
- }
- }
- public ExpressionEditorWindow(List<string> variables)
- {
- Variables = variables;
- InitializeComponent();
- }
- private void ExpressionWindow_Loaded(object sender, RoutedEventArgs e)
- {
- Editor.Focus();
- }
- private void InsertText(string text)
- {
- var newCaret = Editor.CaretIndex + text.Length;
- Editor.Text = Editor.Text.Insert(Editor.CaretIndex, text);
- Editor.CaretIndex = newCaret;
- }
- private void AppendText(string text)
- {
- var oldCaret = Editor.CaretIndex;
- Editor.Text = Editor.Text.Insert(Editor.CaretIndex, text);
- Editor.CaretIndex = oldCaret;
- }
- private void DeleteText(int start, int length)
- {
- var oldCaret = Editor.CaretIndex;
- Editor.Text = Editor.Text.Remove(start, length);
- if(oldCaret >= start && oldCaret < start + length)
- {
- Editor.CaretIndex = start;
- }
- else
- {
- Editor.CaretIndex = oldCaret - length;
- }
- }
- private static Regex tagRegex = new("\\{\\S+\\}");
- private static Regex backTagRegex = new("\\{\\S+\\}", RegexOptions.RightToLeft);
- private bool DeletePlaceholder()
- {
- if (Editor.CaretIndex >= Editor.Text.Length) return false;
- var tagStart = Editor.Text.LastIndexOf('{', Editor.CaretIndex);
- if (tagStart == -1) return false;
- var tagMatch = tagRegex.Match(Editor.Text, tagStart);
- if (!tagMatch.Success) return false;
- var startIndex = tagMatch.Index;
- if (startIndex != tagStart) return false;
- var length = tagMatch.Length;
- if (Editor.CaretIndex >= startIndex + length) return false;
- DeleteText(startIndex, length);
- return true;
- }
- private void JumpPlaceholderBackwards()
- {
- if (Editor.CaretIndex == 0) return;
- var tagMatch = backTagRegex.Match(Editor.Text, Editor.CaretIndex - 1);
- if (!tagMatch.Success) return;
- Editor.CaretIndex = tagMatch.Index;
- }
- private void JumpPlaceholder(bool allowStart = false)
- {
- if (Editor.CaretIndex >= Editor.Text.Length) return;
- var start = allowStart ? Editor.CaretIndex : Editor.CaretIndex + 1;
- var tagMatch = tagRegex.Match(Editor.Text, start);
- if (!tagMatch.Success) return;
- Editor.CaretIndex = tagMatch.Index;
- }
- private void FunctionTemplate_Click(object sender, MouseButtonEventArgs e)
- {
- if ((sender as FrameworkElement)!.Tag is not FunctionTemplate template) return;
- var placeholder = DeletePlaceholder();
- InsertText($"{template.Name}(");
- AppendText(string.Join(", ", template.Parameters.Select(x => $"{{{x}}}")) + ")");
- if (placeholder)
- JumpPlaceholder(true);
- }
- private void Variable_Click(object sender, MouseButtonEventArgs e)
- {
- if ((sender as FrameworkElement)!.Tag is not string str) return;
- DeletePlaceholder();
- InsertText($"[{str}]");
- }
- private void Editor_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
- {
- e.Handled = true;
- }
- private void Editor_PreviewTextInput(object sender, TextCompositionEventArgs e)
- {
- DeletePlaceholder();
- }
- private void Editor_KeyDown(object sender, KeyEventArgs e)
- {
- if(e.Key == Key.Tab)
- {
- if((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift)
- {
- JumpPlaceholderBackwards();
- }
- else
- {
- JumpPlaceholder();
- }
- e.Handled = true;
- }
- }
- private void OK_Click(object sender, RoutedEventArgs e)
- {
- DialogResult = true;
- }
- }
- }
|