using System; using System.Collections.Generic; using System.Linq; using System.Text; 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.Navigation; using System.Windows.Shapes; namespace GraphingCalculator { /// /// Interaction logic for MainWindow.xaml /// public partial class MainWindow : Window { #region Constructor public MainWindow() { InitializeComponent(); // Update textboxes graphingCanvas.CanvasBounds.BoundsChanged += new EventHandler(CanvasBounds_BoundsChanged); graphingCanvas.CanvasBounds.Right = graphingCanvas.CanvasBounds.Right; } #endregion #region Function list private void updateList() { listExpressions.Items.Clear(); foreach (var i in graphingCanvas.Expressions) { CheckBox chk = new CheckBox(); chk.Content = i.ExpressionString; chk.IsChecked = i.IsVisible; chk.Foreground = new SolidColorBrush(i.Color); chk.FontWeight = FontWeights.Bold; chk.Click += new RoutedEventHandler(Visibility_Checked); listExpressions.Items.Add(chk); } } void Visibility_Checked(object sender, RoutedEventArgs e) { int index = listExpressions.Items.IndexOf(sender); CheckBox c = sender as CheckBox; if (index < 0 || c == null || !c.IsChecked.HasValue) return; graphingCanvas.SetExpressionVisibility(index, c.IsChecked.Value); } private void buttonDelete_Click(object sender, RoutedEventArgs e) { int index = listExpressions.SelectedIndex; if (index == -1) return; listExpressions.Items.RemoveAt(index); graphingCanvas.Expressions.RemoveAt(index); graphingCanvas.EvaluateExpressions(); graphingCanvas.Redraw(); } private void buttonClear_Click(object sender, RoutedEventArgs e) { listExpressions.Items.Clear(); graphingCanvas.Expressions.Clear(); graphingCanvas.EvaluateExpressions(); graphingCanvas.Redraw(); } private void buttonHideAll_Click(object sender, RoutedEventArgs e) { for (int i = 0; i < listExpressions.Items.Count; i++) { CheckBox c = listExpressions.Items[i] as CheckBox; if (c != null) c.IsChecked = false; graphingCanvas.SetExpressionVisibility(i, false); } } #endregion #region Keyboard/mouse input private void Window_MouseWheel(object sender, MouseWheelEventArgs e) { graphingCanvas.PeformMouseWheelChange(e); } private bool EditingTextbox() { TextBox box = Keyboard.FocusedElement as TextBox; return (box != null); } private void Window_KeyDown(object sender, KeyEventArgs e) { e.Handled = true; if (e.KeyboardDevice.Modifiers == ModifierKeys.None) { switch (e.Key) { case Key.F1: menuHelp_Click(this, new RoutedEventArgs()); break; case Key.NumPad8: case Key.Up: if (!EditingTextbox()) graphingCanvas.PerformMoveUp(); else e.Handled = false; break; case Key.NumPad4: case Key.Left: if (!EditingTextbox()) graphingCanvas.PerformMoveLeft(); else e.Handled = false; break; case Key.NumPad6: case Key.Right: if (!EditingTextbox()) graphingCanvas.PerformMoveRight(); else e.Handled = false; break; case Key.NumPad2: case Key.Down: if (!EditingTextbox()) graphingCanvas.PerformMoveDown(); else e.Handled = false; break; case Key.NumPad5: if (!EditingTextbox()) graphingCanvas.PerformReset(); else e.Handled = false; break; case Key.Add: if (!EditingTextbox()) graphingCanvas.PerformZoomIn(); else e.Handled = false; break; case Key.Subtract: if (!EditingTextbox()) graphingCanvas.PerformZoomOut(); else e.Handled = false; break; case Key.Enter: buttonPlot_Click(this, new RoutedEventArgs()); break; default: e.Handled = false; break; } } else if (Keyboard.Modifiers == ModifierKeys.Control) { if (e.Key == Key.F1) menuAbout_Click(this, new RoutedEventArgs()); else if (e.Key == Key.S) menuFileSave_Click(this, new RoutedEventArgs()); else if (e.Key == Key.O) menuFileImport_Click(this, new RoutedEventArgs()); else if (e.Key == Key.Q) menuFileExit_Click(this, new RoutedEventArgs()); else e.Handled = false; } else e.Handled = false; } #endregion #region Buttons private void buttonPlot_Click(object sender, RoutedEventArgs e) { if (inputExpression.Text == "") return; VisualExpression expr = new VisualExpression(); try { expr.ExpressionString = inputExpression.Text; expr.Process(); expr.Variables["x"] = expr.Variables["X"] = 0; expr.Evaluate(); } catch (Exception ex) { MessageBox.Show("Error: " + ex.Message, "Error!"); #region Log Log.LogEvent("Failed to plot expression '{0}'. Message: {1}", expr.ExpressionString, ex.Message); Log.LogEvent("> Stack trace: {0}", ex.StackTrace); #endregion return; } graphingCanvas.AddExpression(expr); updateList(); } private void buttonEvaluate_Click(object sender, RoutedEventArgs e) { EvaluateWindow window = new EvaluateWindow(inputExpression.Text); window.Show(); } private void buttonIntegrate_Click(object sender, RoutedEventArgs e) { Controls.IntegralWindow window = new Controls.IntegralWindow(inputExpression.Text); window.Show(); } private bool IsNanInf (params double[] items) { bool result = false; foreach (var i in items) result = result || double.IsNaN(i) || double.IsInfinity(i); return result; } private void buttonChangeBounds_Click(object sender, RoutedEventArgs e) { Expression el, er, et, eb; double l, r, t, b; bool ok = true; // Initialize stuff el = new Expression(inputBoundsLeft.Text); er = new Expression(inputBoundsRight.Text); et = new Expression(inputBoundsTop.Text); eb = new Expression(inputBoundsBottom.Text); l = r = t = b = 0; // Initialize visuals inputBoundsLeft.Background = SystemColors.WindowBrush; inputBoundsTop.Background = SystemColors.WindowBrush; inputBoundsRight.Background = SystemColors.WindowBrush; inputBoundsBottom.Background = SystemColors.WindowBrush; // Evaluate left try { l = el.Evaluate(); } catch { if (!double.TryParse(el.ExpressionString, out l)) { inputBoundsLeft.Background = Brushes.Pink; ok = false; } } // Evaluate top try { t = et.Evaluate(); } catch { if (!double.TryParse(et.ExpressionString, out t)) { inputBoundsTop.Background = Brushes.Pink; ok = false; } } // Evaluate right try { r = er.Evaluate(); } catch { if (!double.TryParse(er.ExpressionString, out r)) { inputBoundsRight.Background = Brushes.Pink; ok = false; } } // Evaluate bottom try { b = eb.Evaluate(); } catch { if (!double.TryParse(eb.ExpressionString, out b)) { inputBoundsBottom.Background = Brushes.Pink; ok = false; } } // Preview results inputBoundsTop.Text = Math.Round(t, 15).ToString(); inputBoundsLeft.Text = Math.Round(l, 15).ToString(); inputBoundsRight.Text = Math.Round(r, 15).ToString(); inputBoundsBottom.Text = Math.Round(b, 15).ToString(); // Verify if (ok) { if (l >= r || b >= t || IsNanInf(l, r, b, t)) MessageBox.Show("Invalid interval! Make sure left is smaller than right, bottom is smaller than top, and the intervals are finite.", "Error"); else graphingCanvas.SetCanvasBounds(new Bounds(l, t, r, b)); } } #endregion #region Menu items private void menuFileSave_Click(object sender, RoutedEventArgs e) { Microsoft.Win32.SaveFileDialog save = new Microsoft.Win32.SaveFileDialog(); save.Filter = "XML Expression list|*.xml|All files|*.*"; save.Title = "Save expression list..."; bool? result = save.ShowDialog(); if (!result.HasValue || !result.Value) return; IO.ExpressionFile file = new IO.ExpressionFile(); file.Expressions.AddRange(graphingCanvas.Expressions); try { file.SaveToFile(save.FileName); } catch (Exception ex) { MessageBox.Show("Error: " + ex.Message, "Error!"); Log.LogEvent("Failed to save to file '{0}': {1}", save.FileName, ex.Message); Log.LogEvent("> Stack trace: {0}", ex.StackTrace); } } private void menuFileImport_Click(object sender, RoutedEventArgs e) { IO.ExpressionFile file = new IO.ExpressionFile(); Microsoft.Win32.OpenFileDialog open = new Microsoft.Win32.OpenFileDialog(); bool? res; // Show dialog open.Filter = "XML Expression list|*.xml|All files|*.*"; open.Title = "Import expression list"; res = open.ShowDialog(); if (!res.HasValue || !res.Value) return; // Try to load data try { file.LoadFromFile(open.FileName); } catch (Exception ex) { MessageBox.Show("Error: " + ex.Message, "Error!"); Log.LogEvent("Failed to import from file '{0}': {1}", open.FileName, ex.Message); Log.LogEvent("> Stack trace: {0}", ex.StackTrace); } // Add expressions to our list foreach (var i in file.Expressions) this.graphingCanvas.AddExpression(i); updateList(); } private void menuFileExit_Click(object sender, RoutedEventArgs e) { this.Close(); } private void menuAppLog_Click(object sender, RoutedEventArgs e) { new LogWindow().Show(); } private void menuAppPref_Click(object sender, RoutedEventArgs e) { new SettingsWindow().ShowDialog(); graphingCanvas.SetCanvasBounds(graphingCanvas.CanvasBounds); } private void menuHelp_Click(object sender, RoutedEventArgs e) { DynamicLink.Launcher.StartModule("Help", "graphingcalc"); } private void menuAbout_Click(object sender, RoutedEventArgs e) { DynamicLink.Launcher.About(); } #endregion #region Misc void CanvasBounds_BoundsChanged(object sender, EventArgs e) { int p = GraphingCalculator.Properties.Settings.Default.RoundDoublesGraph; this.inputBoundsBottom.Text = Math.Round(graphingCanvas.CanvasBounds.Bottom, p).ToString(); this.inputBoundsLeft.Text = Math.Round(graphingCanvas.CanvasBounds.Left, p).ToString(); this.inputBoundsTop.Text = Math.Round(graphingCanvas.CanvasBounds.Top, p).ToString(); this.inputBoundsRight.Text = Math.Round(graphingCanvas.CanvasBounds.Right, p).ToString(); #region Log Log.LogEvent("Canvas bounds changed: left={0}; top={1}; right={2}; bottom={3}", this.inputBoundsLeft.Text, this.inputBoundsTop.Text, this.inputBoundsRight.Text, this.inputBoundsBottom.Text); #endregion } #endregion } }