390 lines
13 KiB
C#
390 lines
13 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// Interaction logic for MainWindow.xaml
|
|
/// </summary>
|
|
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
|
|
}
|
|
}
|