Added source code.
This commit is contained in:
8
Source/GraphingCalculator/App.xaml
Normal file
8
Source/GraphingCalculator/App.xaml
Normal file
@ -0,0 +1,8 @@
|
||||
<Application x:Class="GraphingCalculator.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
|
||||
</Application.Resources>
|
||||
</Application>
|
42
Source/GraphingCalculator/App.xaml.cs
Normal file
42
Source/GraphingCalculator/App.xaml.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
|
||||
namespace GraphingCalculator
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
protected override void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
base.OnStartup(e);
|
||||
|
||||
Log.LogEvent("Session started!");
|
||||
}
|
||||
|
||||
protected override void OnExit(ExitEventArgs e)
|
||||
{
|
||||
base.OnExit(e);
|
||||
|
||||
Log.LogEvent("Session finished! Exit code: {0}", e.ApplicationExitCode);
|
||||
Log.LogEvent("-----------------");
|
||||
|
||||
try {
|
||||
if (!System.IO.Directory.Exists("logs")) System.IO.Directory.CreateDirectory("logs");
|
||||
|
||||
if (System.IO.File.Exists("logs\\graphingcalc.log"))
|
||||
System.IO.File.AppendAllLines("logs\\graphingcalc.log", Log.Entries.ToArray());
|
||||
else System.IO.File.WriteAllLines("logs\\graphingcalc.log", Log.Entries.ToArray());
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Save settings
|
||||
GraphingCalculator.Properties.Settings.Default.Save();
|
||||
}
|
||||
}
|
||||
}
|
77
Source/GraphingCalculator/Bounds.cs
Normal file
77
Source/GraphingCalculator/Bounds.cs
Normal file
@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace GraphingCalculator
|
||||
{
|
||||
public class Bounds
|
||||
{
|
||||
private double left, right, top, bottom;
|
||||
|
||||
#region Public properties
|
||||
public double Left
|
||||
{
|
||||
get { return left; }
|
||||
set { left = value; if (BoundsChanged != null) BoundsChanged(this, new EventArgs()); }
|
||||
}
|
||||
public double Right
|
||||
{
|
||||
get { return right; }
|
||||
set { right = value; if (BoundsChanged != null) BoundsChanged(this, new EventArgs()); }
|
||||
}
|
||||
public double Top
|
||||
{
|
||||
get { return top; }
|
||||
set { top = value; if (BoundsChanged != null) BoundsChanged(this, new EventArgs()); }
|
||||
}
|
||||
public double Bottom
|
||||
{
|
||||
get { return bottom; }
|
||||
set { bottom = value; if (BoundsChanged != null) BoundsChanged(this, new EventArgs()); }
|
||||
}
|
||||
|
||||
public double Width
|
||||
{
|
||||
get { return Right - Left; }
|
||||
set { Right = Left + value; }
|
||||
}
|
||||
public double Height
|
||||
{
|
||||
get { return Top - Bottom; }
|
||||
set { Top = Bottom + Height; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
public event EventHandler BoundsChanged;
|
||||
|
||||
#region Constructors
|
||||
public Bounds()
|
||||
{
|
||||
Left = Right = Top = Bottom = 0;
|
||||
}
|
||||
public Bounds(double w, double h)
|
||||
{
|
||||
Left = Bottom = 0;
|
||||
Width = w; Height = h;
|
||||
}
|
||||
public Bounds(double l, double t, double r, double b)
|
||||
{
|
||||
Left = l; Top = t; Right = r; Bottom = b;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IsInBounds
|
||||
public bool IsInBounds(double x, double y)
|
||||
{
|
||||
return (x >= Math.Min(Left, Right) && x <= Math.Max(Left, Right) &&
|
||||
y >= Math.Min(Top, Bottom) && y <= Math.Max(Top, Bottom));
|
||||
}
|
||||
|
||||
public bool IsInBounds(System.Windows.Point point)
|
||||
{
|
||||
return IsInBounds(point.X, point.Y);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
101
Source/GraphingCalculator/Controls/EvaluateWindow.xaml
Normal file
101
Source/GraphingCalculator/Controls/EvaluateWindow.xaml
Normal file
@ -0,0 +1,101 @@
|
||||
<Window x:Class="GraphingCalculator.EvaluateWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Evaluate expression" Height="251" Width="471" WindowStartupLocation="CenterScreen"
|
||||
WindowStyle="ToolWindow" SnapsToDevicePixels="True"
|
||||
KeyUp="Window_KeyUp">
|
||||
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="/Styles/GroupBoxStyle.xaml" />
|
||||
<ResourceDictionary Source="/Styles/ButtonStyle.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Window.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint=".5,1">
|
||||
<GradientStop Color="#EEE" Offset="0" />
|
||||
<GradientStop Color="#BBB" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Window.Background>
|
||||
|
||||
<Grid Margin="3">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="5"/>
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<GridSplitter Grid.Column="1" Grid.Row="0" Background="Transparent"
|
||||
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
|
||||
|
||||
<GroupBox Header="Input expression" Margin="0,0,-3,0">
|
||||
<TextBox Name="inputExpression" TextWrapping="Wrap"/>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Column="2" Header="Variables" Margin="-3,0,0,0">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ListBox Name="listVars" Grid.ColumnSpan="100" Margin="0,0,0,2">
|
||||
<ListBox.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="Edit" Click="contextEdit_Click"/>
|
||||
<MenuItem Header="Delete" Click="contextDelete_Click" />
|
||||
<MenuItem Header="Clear list" Click="contextClear_Click" />
|
||||
</ContextMenu>
|
||||
</ListBox.ContextMenu>
|
||||
</ListBox>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center">Name:</TextBlock>
|
||||
<TextBox Name="inputVarName" Grid.Row="1" Grid.Column="1" />
|
||||
<TextBlock Grid.Row="1" Grid.Column="2" VerticalAlignment="Center" Margin="3,0,0,0">Value:</TextBlock>
|
||||
<TextBox Name="inputVarValue" Grid.Row="1" Grid.Column="3" />
|
||||
<Button VerticalAlignment="Center" Name="buttonAdd"
|
||||
Grid.Row="1" Grid.Column="4" Margin="3,0,0,0"
|
||||
Click="buttonAdd_Click">Add</Button>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="1" Grid.ColumnSpan="3" Header="Result">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBox Name="outputResult" Grid.ColumnSpan="2" IsReadOnly="True" Background="White"
|
||||
Margin="0,0,0,2"/>
|
||||
|
||||
<Button Name="buttonClose" Grid.Row="1" Grid.Column="1" Width="80" Margin="2"
|
||||
HorizontalAlignment="Left" Click="buttonClose_Click">Close</Button>
|
||||
<Button Name="buttonEval" Grid.Row="1" Width="80" Margin="2"
|
||||
HorizontalAlignment="Right" Click="buttonEval_Click">Evaluate</Button>
|
||||
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
</Grid>
|
||||
</Window>
|
216
Source/GraphingCalculator/Controls/EvaluateWindow.xaml.cs
Normal file
216
Source/GraphingCalculator/Controls/EvaluateWindow.xaml.cs
Normal file
@ -0,0 +1,216 @@
|
||||
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.Shapes;
|
||||
|
||||
namespace GraphingCalculator
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for EvaluateWindow.xaml
|
||||
/// </summary>
|
||||
public partial class EvaluateWindow : Window
|
||||
{
|
||||
private Dictionary<string, double> variables = new Dictionary<string, double>();
|
||||
|
||||
#region Properties
|
||||
public string InputExpression
|
||||
{
|
||||
get { return inputExpression.Text; }
|
||||
set { inputExpression.Text = value; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public EvaluateWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public EvaluateWindow(string txt)
|
||||
{
|
||||
InitializeComponent();
|
||||
InputExpression = txt;
|
||||
|
||||
// Convenience: evaluate already
|
||||
buttonEval_Click(this, new RoutedEventArgs());
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region User input
|
||||
private void buttonAdd_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
string errorMessage = "";
|
||||
double val = 0;
|
||||
|
||||
outputResult.Clear();
|
||||
|
||||
// Verify boxes are not empty
|
||||
if (inputVarName.Text == "" || inputVarValue.Text == "")
|
||||
errorMessage = "Name or value cannot be empty!";
|
||||
|
||||
// Get number
|
||||
if (errorMessage == "" && !double.TryParse(inputVarValue.Text, out val))
|
||||
{
|
||||
try {
|
||||
Expression expr = new Expression(inputVarValue.Text);
|
||||
val = expr.Evaluate();
|
||||
}
|
||||
|
||||
catch { errorMessage = "Value must be a number!"; }
|
||||
}
|
||||
|
||||
// Verify name is unique
|
||||
if (errorMessage == "" && variables.ContainsKey(inputVarName.Text))
|
||||
{
|
||||
var res = MessageBox.Show("A variable with the same name already exists. Replace it with the new value?", "Warning", MessageBoxButton.YesNo);
|
||||
if (res != MessageBoxResult.Yes) errorMessage = "A variable with the same name already exists!";
|
||||
}
|
||||
|
||||
// Verify name doesn't contain forbidden characters
|
||||
if (errorMessage == "")
|
||||
{
|
||||
bool ok = char.IsLetter (inputVarName.Text.First());
|
||||
foreach (var i in inputVarName.Text)
|
||||
if (!char.IsLetterOrDigit(i)) ok = false;
|
||||
|
||||
if (!ok) errorMessage = "Forbidden variable name, it can only contain letters or digits!";
|
||||
}
|
||||
|
||||
// Add variable
|
||||
if (errorMessage == "")
|
||||
{
|
||||
variables[inputVarName.Text] = val;
|
||||
|
||||
// Remove if it exists already
|
||||
for (int i = 0; i < listVars.Items.Count; i++)
|
||||
{
|
||||
string str = listVars.Items[i] as string;
|
||||
if (str != null && str.StartsWith(inputVarName.Text + " = ")) listVars.Items.RemoveAt(i);
|
||||
}
|
||||
|
||||
// Add variable
|
||||
listVars.Items.Add(inputVarName.Text + " = " + inputVarValue.Text);
|
||||
|
||||
// Clear text boxes
|
||||
inputVarName.Clear();
|
||||
inputVarValue.Clear();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
outputResult.Foreground = Brushes.DarkRed;
|
||||
outputResult.Text = "Error adding variable: " + errorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
private void buttonEval_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Create expression
|
||||
Expression expression = new Expression(inputExpression.Text);
|
||||
double result = 0;
|
||||
|
||||
// Add variables
|
||||
foreach (var i in variables)
|
||||
expression.Variables.Add(i.Key, i.Value);
|
||||
|
||||
// Try to evaluate
|
||||
try {
|
||||
result = expression.Evaluate();
|
||||
}
|
||||
|
||||
catch (Exception ex) {
|
||||
outputResult.Text = "Error evaluating: " + ex.Message;
|
||||
outputResult.Foreground = Brushes.DarkRed;
|
||||
|
||||
#region Log
|
||||
Log.LogEvent("Failed to evaluate expression '{0}'. Message: {1}", inputExpression.Text, ex.Message);
|
||||
Log.LogEvent("> Stack trace: {0}", ex.StackTrace);
|
||||
|
||||
if (listVars.Items.Count > 0) Log.LogEvent("> Variables: ");
|
||||
|
||||
foreach (var i in listVars.Items)
|
||||
Log.LogEvent(">> {0}", i.ToString());
|
||||
#endregion
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Output results
|
||||
outputResult.Text = Math.Round(result, 15).ToString();
|
||||
outputResult.Foreground = Brushes.Black;
|
||||
|
||||
#region Log
|
||||
// Log what happened here
|
||||
Log.LogEvent("Evaluated expression '{0}' result={1}", inputExpression.Text, outputResult.Text);
|
||||
if (listVars.Items.Count > 0) Log.LogEvent("> WHERE: ");
|
||||
|
||||
foreach (var i in listVars.Items)
|
||||
Log.LogEvent(">> {0}", i.ToString());
|
||||
#endregion
|
||||
}
|
||||
|
||||
private void buttonClose_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void contextEdit_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Make sure we have 1 selected item
|
||||
if (listVars.SelectedItems.Count != 1) return;
|
||||
|
||||
// Get key
|
||||
var item = listVars.SelectedItem as string;
|
||||
if (item == null) return;
|
||||
string key = item.Substring(0, item.IndexOf(" = "));
|
||||
|
||||
// Place in input boxes
|
||||
inputVarName.Text = key;
|
||||
inputVarValue.Text = variables[key].ToString();
|
||||
|
||||
// Remove item
|
||||
listVars.Items.Remove(listVars.SelectedItem);
|
||||
variables.Remove(key);
|
||||
}
|
||||
|
||||
private void contextDelete_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Make sure we have 1 selected item
|
||||
if (listVars.SelectedItems.Count != 1) return;
|
||||
|
||||
// Get key
|
||||
var item = listVars.SelectedItem as string;
|
||||
if (item == null) return;
|
||||
string key = item.Substring(0, item.IndexOf(" = "));
|
||||
|
||||
// Remove
|
||||
listVars.Items.Remove(listVars.SelectedItem);
|
||||
variables.Remove(key);
|
||||
}
|
||||
|
||||
private void contextClear_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
listVars.Items.Clear();
|
||||
variables.Clear();
|
||||
}
|
||||
|
||||
private void Window_KeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
if (e.Key == Key.Escape) buttonClose_Click(this, new RoutedEventArgs());
|
||||
else if (e.Key == Key.Enter) buttonEval_Click(this, new RoutedEventArgs());
|
||||
else if (e.Key == Key.Insert) buttonAdd_Click(this, new RoutedEventArgs());
|
||||
|
||||
else e.Handled = false;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
137
Source/GraphingCalculator/Controls/GraphingCanvas.xaml
Normal file
137
Source/GraphingCalculator/Controls/GraphingCanvas.xaml
Normal file
@ -0,0 +1,137 @@
|
||||
<Canvas x:Class="GraphingCalculator.GraphingCanvas"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
mc:Ignorable="d" d:DesignHeight="234" d:DesignWidth="348"
|
||||
ClipToBounds="True"
|
||||
SizeChanged="Canvas_SizeChanged"
|
||||
MouseWheel="Canvas_MouseWheel"
|
||||
>
|
||||
|
||||
<Canvas.Resources>
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="OverridesDefaultStyle" Value="True" />
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Grid Name="grid">
|
||||
<Border Name="border" CornerRadius="4" Visibility="Collapsed"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
BorderBrush="Orange"
|
||||
BorderThickness="1">
|
||||
<Border.Background>
|
||||
<RadialGradientBrush Center=".5, .5" GradientOrigin=".5,1" RadiusX="1" RadiusY=".7">
|
||||
<GradientStop Color="#FFBF6A" Offset="0" />
|
||||
<GradientStop Color="#FFF6E2" Offset="1" />
|
||||
</RadialGradientBrush>
|
||||
</Border.Background>
|
||||
</Border>
|
||||
|
||||
<Border Name="blackness" CornerRadius="4" Background="Brown" Opacity="0" />
|
||||
|
||||
<ContentPresenter VerticalAlignment="Center" Margin="3"
|
||||
HorizontalAlignment="Center" />
|
||||
</Grid>
|
||||
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="border" Property="Visibility" Value="Visible" />
|
||||
</Trigger>
|
||||
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="blackness" Property="Opacity" Value=".3" />
|
||||
</Trigger>
|
||||
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="RepeatButton">
|
||||
<Setter Property="OverridesDefaultStyle" Value="True" />
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="RepeatButton">
|
||||
<Grid Name="grid">
|
||||
<Border Name="border" CornerRadius="4" Visibility="Collapsed"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
BorderBrush="Orange"
|
||||
BorderThickness="1">
|
||||
<Border.Background>
|
||||
<RadialGradientBrush Center=".5, .5" GradientOrigin=".5,1" RadiusX="1" RadiusY=".7">
|
||||
<GradientStop Color="#FFBF6A" Offset="0" />
|
||||
<GradientStop Color="#FFF6E2" Offset="1" />
|
||||
</RadialGradientBrush>
|
||||
</Border.Background>
|
||||
</Border>
|
||||
|
||||
<Border Name="blackness" CornerRadius="4" Background="Brown" Opacity="0" />
|
||||
|
||||
<ContentPresenter VerticalAlignment="Center" Margin="3"
|
||||
HorizontalAlignment="Center" />
|
||||
</Grid>
|
||||
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="border" Property="Visibility" Value="Visible" />
|
||||
</Trigger>
|
||||
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="blackness" Property="Opacity" Value=".3" />
|
||||
</Trigger>
|
||||
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</Canvas.Resources>
|
||||
|
||||
<RepeatButton Name="buttonUp" Canvas.Right="25" Canvas.Top="5"
|
||||
Width="20" Height="20" Click="buttonUp_Click">
|
||||
<Path Height="12" Stretch="Fill" Fill="Gray"
|
||||
Data="F1 M 190.792,238.149L 182.688,252.184L 198.895,252.184L 190.792,238.149 Z "/>
|
||||
</RepeatButton>
|
||||
|
||||
<RepeatButton Name="buttonLeft" Canvas.Right="45" Canvas.Top="25"
|
||||
Width="20" Height="20" Click="buttonLeft_Click" >
|
||||
<Path Width="12" Stretch="Fill" Fill="Gray" Data="F1 M 204.774,246.729L 218.809,254.833L 218.809,238.626L 204.774,246.729 Z "/>
|
||||
</RepeatButton>
|
||||
|
||||
<Button Name="buttonReset"
|
||||
Canvas.Right="25" Canvas.Top="25"
|
||||
Width="20" Height="20"
|
||||
Click="buttonReset_Click"
|
||||
ToolTip="Reset" >
|
||||
<Ellipse Width="12" Height="12" Fill="Gray"/>
|
||||
</Button>
|
||||
|
||||
<RepeatButton Name="buttonRight"
|
||||
Canvas.Right="5" Canvas.Top="25"
|
||||
Width="20" Height="20" Click="buttonRight_Click" >
|
||||
<Path Width="12" Stretch="Fill" Fill="Gray" Data="F1 M 214.722,227.667L 200.686,219.563L 200.686,235.77L 214.722,227.667 Z "/>
|
||||
</RepeatButton>
|
||||
|
||||
<RepeatButton Name="buttonBottom" Canvas.Right="25" Canvas.Top="45"
|
||||
Width="20" Height="20" Click="buttonBottom_Click" >
|
||||
<Path Height="12" Stretch="Fill" Fill="Gray" Data="F1 M 188.333,235.024L 196.437,220.988L 180.23,220.988L 188.333,235.024 Z "/>
|
||||
</RepeatButton>
|
||||
|
||||
<!-- Zoom buttons -->
|
||||
<RepeatButton Name="buttonZoomIn" Canvas.Right="5" Canvas.Bottom="5"
|
||||
Width="25" Height="20" Click="buttonZoomIn_Click">
|
||||
<Path Width="12" Height="12" Stretch="Fill" Fill="Gray" Data="M 139.292,225.542L 147.292,225.542L 147.292,233.542L 155.292,233.542L 155.292,241.542L 147.292,241.542L 147.292,249.542L 139.292,249.542L 139.292,241.542L 131.292,241.542L 131.292,233.542L 139.292,233.542L 139.292,225.542 Z "/>
|
||||
</RepeatButton>
|
||||
|
||||
<RepeatButton Name="buttonZoomOut" Canvas.Right="30" Canvas.Bottom="5"
|
||||
Width="25" Height="20" Click="buttonZoomOut_Click">
|
||||
<Rectangle Width="12" Height="4.32" Stretch="Fill" Fill="Gray"/>
|
||||
</RepeatButton>
|
||||
|
||||
</Canvas>
|
466
Source/GraphingCalculator/Controls/GraphingCanvas.xaml.cs
Normal file
466
Source/GraphingCalculator/Controls/GraphingCanvas.xaml.cs
Normal file
@ -0,0 +1,466 @@
|
||||
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 GraphingCanvas.xaml
|
||||
/// </summary>
|
||||
public partial class GraphingCanvas : Canvas
|
||||
{
|
||||
#region Settings
|
||||
private double PlotPrecision
|
||||
{
|
||||
get { return GraphingCalculator.Properties.Settings.Default.PlotPrecision; }
|
||||
set { GraphingCalculator.Properties.Settings.Default.PlotPrecision = value; }
|
||||
}
|
||||
|
||||
private double GridDensity
|
||||
{
|
||||
get { return GraphingCalculator.Properties.Settings.Default.GridDensity; }
|
||||
set { GraphingCalculator.Properties.Settings.Default.GridDensity = value; }
|
||||
}
|
||||
|
||||
private int RoundDoublesGraph
|
||||
{
|
||||
get { return GraphingCalculator.Properties.Settings.Default.RoundDoublesGraph; }
|
||||
set { GraphingCalculator.Properties.Settings.Default.RoundDoublesGraph = value; }
|
||||
}
|
||||
|
||||
private double NavigationSens
|
||||
{
|
||||
get { return GraphingCalculator.Properties.Settings.Default.NavigationSensitivity; }
|
||||
set { GraphingCalculator.Properties.Settings.Default.NavigationSensitivity = value; }
|
||||
}
|
||||
|
||||
private double ZoomSens
|
||||
{
|
||||
get { return GraphingCalculator.Properties.Settings.Default.ZoomSensitivity; }
|
||||
set { GraphingCalculator.Properties.Settings.Default.ZoomSensitivity = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constants
|
||||
private Point specialSeparator = new Point(double.MaxValue, double.MaxValue);
|
||||
private Point specialVisibleTrue = new Point(0, double.MaxValue);
|
||||
private Point specialVisibleFalse = new Point(0, double.MinValue);
|
||||
#endregion
|
||||
|
||||
#region Expressions
|
||||
private List<VisualExpression> expressions = new List<VisualExpression>();
|
||||
public List<VisualExpression> Expressions { get { return expressions; } }
|
||||
|
||||
/// <summary>
|
||||
/// Adds an expression to be plotted
|
||||
/// </summary>
|
||||
public void AddExpression(VisualExpression ex)
|
||||
{
|
||||
this.Expressions.Add(ex);
|
||||
EvaluateExpression(ex);
|
||||
Redraw();
|
||||
|
||||
#region Log
|
||||
Log.LogEvent("Plotted expression '{0}'", ex.ExpressionString);
|
||||
#endregion
|
||||
}
|
||||
|
||||
public void SetExpressionVisibility(int index, bool visibility)
|
||||
{
|
||||
if (Expressions[index].IsVisible == visibility) return;
|
||||
|
||||
if (queuedPoints.Count != 0) {
|
||||
int i, ci;
|
||||
for (i = 0, ci = -1; i < queuedPoints.Count && ci < index; i++)
|
||||
if (queuedPoints[i] == specialSeparator) ci++;
|
||||
|
||||
queuedPoints[i] = (visibility) ? specialVisibleTrue : specialVisibleFalse;
|
||||
}
|
||||
|
||||
Expressions[index].IsVisible = visibility;
|
||||
Redraw();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Canvas and screen bounds
|
||||
public Bounds CanvasBounds { get; set; }
|
||||
public Bounds ScreenBounds { get; set; }
|
||||
|
||||
public double CoordXToCanvas(double x)
|
||||
{
|
||||
double scrX = x - ScreenBounds.Left;
|
||||
return CanvasBounds.Left + (CanvasBounds.Width * (scrX / ScreenBounds.Width));
|
||||
}
|
||||
|
||||
public double CoordXToScreen(double x)
|
||||
{
|
||||
double canX = x - CanvasBounds.Left;
|
||||
return ScreenBounds.Left + (ScreenBounds.Width * (canX / CanvasBounds.Width));
|
||||
}
|
||||
|
||||
public double CoordYToCanvas(double y)
|
||||
{
|
||||
double scrY = y - ScreenBounds.Bottom;
|
||||
return CanvasBounds.Bottom + (CanvasBounds.Height * (scrY / ScreenBounds.Height));
|
||||
}
|
||||
|
||||
public double CoordYToScreen(double y)
|
||||
{
|
||||
double canY = y - CanvasBounds.Bottom;
|
||||
return ScreenBounds.Bottom + (ScreenBounds.Height * (canY / CanvasBounds.Height));
|
||||
}
|
||||
|
||||
public Point CoordToCanvas(double x, double y)
|
||||
{
|
||||
return new Point(CoordXToCanvas(x), CoordYToCanvas(y));
|
||||
}
|
||||
|
||||
public Point CoordToCanvas(Point p)
|
||||
{
|
||||
return new Point(CoordXToCanvas(p.X), CoordYToCanvas(p.Y));
|
||||
}
|
||||
|
||||
public Point CoordToScreen(double x, double y)
|
||||
{
|
||||
return new Point(CoordXToScreen(x), CoordYToScreen(y));
|
||||
}
|
||||
|
||||
public Point CoordToScreen(Point p)
|
||||
{
|
||||
return new Point(CoordXToScreen(p.X), CoordYToScreen(p.Y));
|
||||
}
|
||||
|
||||
public void SetCanvasBounds(Bounds b)
|
||||
{
|
||||
if (b.Width <= 0 || b.Height <= 0) return;
|
||||
|
||||
CanvasBounds.Top = b.Top;
|
||||
CanvasBounds.Bottom = b.Bottom;
|
||||
CanvasBounds.Left = b.Left;
|
||||
CanvasBounds.Right = b.Right;
|
||||
|
||||
EvaluateExpressions();
|
||||
Redraw();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
public GraphingCanvas()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
CanvasBounds = new Bounds(-5, 5, 5, -5);
|
||||
ScreenBounds = new Bounds(0, 0, this.ActualWidth, this.ActualHeight);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region UI Events
|
||||
private void Canvas_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
ScreenBounds.Right = e.NewSize.Width;
|
||||
ScreenBounds.Bottom = e.NewSize.Height;
|
||||
|
||||
Redraw();
|
||||
}
|
||||
|
||||
private void buttonReset_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
CanvasBounds.Left = -5;
|
||||
CanvasBounds.Right = 5;
|
||||
CanvasBounds.Bottom = -5;
|
||||
CanvasBounds.Top = 5;
|
||||
|
||||
EvaluateExpressions();
|
||||
Redraw();
|
||||
}
|
||||
|
||||
private void buttonUp_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
double h = CanvasBounds.Height * NavigationSens;
|
||||
CanvasBounds.Top += h;
|
||||
CanvasBounds.Bottom += h;
|
||||
|
||||
EvaluateExpressions();
|
||||
Redraw();
|
||||
}
|
||||
|
||||
private void buttonLeft_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
double w = CanvasBounds.Width * NavigationSens;
|
||||
CanvasBounds.Left -= w;
|
||||
CanvasBounds.Right -= w;
|
||||
|
||||
EvaluateExpressions();
|
||||
Redraw();
|
||||
}
|
||||
|
||||
private void buttonRight_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
double w = CanvasBounds.Width * NavigationSens;
|
||||
CanvasBounds.Left += w;
|
||||
CanvasBounds.Right += w;
|
||||
|
||||
EvaluateExpressions();
|
||||
Redraw();
|
||||
}
|
||||
|
||||
private void buttonBottom_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
double h = CanvasBounds.Height * NavigationSens;
|
||||
CanvasBounds.Top -= h;
|
||||
CanvasBounds.Bottom -= h;
|
||||
|
||||
EvaluateExpressions();
|
||||
Redraw();
|
||||
}
|
||||
|
||||
private void buttonZoomIn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
double new_w = CanvasBounds.Width / ZoomSens;
|
||||
double new_h = CanvasBounds.Height / ZoomSens;
|
||||
double diff_w = (CanvasBounds.Width - new_w) / 2 ;
|
||||
double diff_h = (CanvasBounds.Height - new_h) / 2;
|
||||
|
||||
CanvasBounds.Left += diff_w;
|
||||
CanvasBounds.Right -= diff_w;
|
||||
CanvasBounds.Bottom += diff_h;
|
||||
CanvasBounds.Top -= diff_h;
|
||||
|
||||
EvaluateExpressions();
|
||||
Redraw();
|
||||
}
|
||||
|
||||
private void buttonZoomOut_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
double new_w = CanvasBounds.Width * ZoomSens;
|
||||
double new_h = CanvasBounds.Height * ZoomSens;
|
||||
double diff_w = (CanvasBounds.Width - new_w) / 2;
|
||||
double diff_h = (CanvasBounds.Height - new_h) / 2;
|
||||
|
||||
CanvasBounds.Left += diff_w;
|
||||
CanvasBounds.Right -= diff_w;
|
||||
CanvasBounds.Bottom += diff_h;
|
||||
CanvasBounds.Top -= diff_h;
|
||||
|
||||
EvaluateExpressions();
|
||||
Redraw();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Expression evaluation
|
||||
List<Point> queuedPoints = new List<Point>();
|
||||
|
||||
public void EvaluateExpression(VisualExpression expr)
|
||||
{
|
||||
queuedPoints.Add(specialSeparator);
|
||||
queuedPoints.Add((expr.IsVisible) ? specialVisibleTrue : specialVisibleFalse);
|
||||
|
||||
for (double x = CanvasBounds.Left; x <= CanvasBounds.Right; x += CanvasBounds.Width / PlotPrecision)
|
||||
{
|
||||
expr.Variables["x"] = expr.Variables["X"] = x;
|
||||
queuedPoints.Add(new Point(x, expr.Evaluate()));
|
||||
}
|
||||
}
|
||||
|
||||
public void EvaluateExpressions()
|
||||
{
|
||||
queuedPoints.Clear();
|
||||
foreach (var expr in Expressions)
|
||||
EvaluateExpression(expr);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Rendering
|
||||
public void Redraw()
|
||||
{
|
||||
this.InvalidateVisual();
|
||||
}
|
||||
|
||||
private void RenderDouble(DrawingContext dc, double n, Point pos, bool center)
|
||||
{
|
||||
FormattedText text = new FormattedText(Math.Round(n, RoundDoublesGraph).ToString(),
|
||||
new System.Globalization.CultureInfo("en-US"), FlowDirection.LeftToRight,
|
||||
new Typeface("Arial"), 8.0, Brushes.Black);
|
||||
|
||||
if (center) dc.DrawText(text, new Point(pos.X - (text.Width / 2), pos.Y + 10));
|
||||
else dc.DrawText(text, new Point(pos.X + 2, pos.Y));
|
||||
}
|
||||
|
||||
private void RenderGridVertical(DrawingContext dc, Pen pen, double from, double to, double interv)
|
||||
{
|
||||
if (from > to) interv *= -1;
|
||||
|
||||
// Draw vertical grid
|
||||
for (double i = from; (from < to && i < to) || (from > to && i > to); i += interv)
|
||||
{
|
||||
Point text = CoordToScreen(i, 0);
|
||||
Point f = CoordToScreen(i, CanvasBounds.Bottom);
|
||||
Point t = CoordToScreen(i, CanvasBounds.Top);
|
||||
|
||||
dc.DrawLine(pen, f, t);
|
||||
RenderDouble(dc, i, text, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderGridHorizontal(DrawingContext dc, Pen pen, double from, double to, double interv)
|
||||
{
|
||||
if (from > to) interv *= -1;
|
||||
|
||||
// Draw vertical grid
|
||||
for (double i = from; (from < to && i < to) || (from > to && i > to); i += interv)
|
||||
{
|
||||
Point text = CoordToScreen(0, i);
|
||||
Point f = CoordToScreen(CanvasBounds.Left, i);
|
||||
Point t = CoordToScreen(CanvasBounds.Right, i);
|
||||
|
||||
dc.DrawLine(pen, f, t);
|
||||
RenderDouble(dc, i, text, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderGrid(DrawingContext dc)
|
||||
{
|
||||
Pen pen = new Pen(new SolidColorBrush(Color.FromRgb(0xa6, 0xdd, 0xe2)), 1);
|
||||
pen.DashStyle = DashStyles.Dash;
|
||||
|
||||
double w_div = Math.Truncate(this.ActualWidth / GridDensity);
|
||||
double h_div = Math.Truncate(this.ActualHeight / GridDensity);
|
||||
if (Convert.ToInt32(w_div) % 2 == 1) w_div += 1;
|
||||
if (Convert.ToInt32(h_div) % 2 == 1) h_div += 1;
|
||||
|
||||
double w_int = CanvasBounds.Width / w_div;
|
||||
double h_int = CanvasBounds.Height / h_div;
|
||||
|
||||
RenderGridVertical(dc, pen, 0, CanvasBounds.Right, w_int);
|
||||
RenderGridVertical(dc, pen, 0, CanvasBounds.Left, w_int);
|
||||
RenderGridHorizontal(dc, pen, 0, CanvasBounds.Top, h_int);
|
||||
RenderGridHorizontal(dc, pen, 0, CanvasBounds.Bottom, h_int);
|
||||
}
|
||||
|
||||
private void RenderAxis(DrawingContext dc)
|
||||
{
|
||||
Point dst;
|
||||
Pen lines = new Pen(Brushes.Coral, 1.5);
|
||||
|
||||
// Draw X axis
|
||||
dst = CoordToScreen(CanvasBounds.Right, 0);
|
||||
dc.DrawLine(lines, CoordToScreen(CanvasBounds.Left, 0), dst);
|
||||
dc.DrawLine(lines, dst, new Point(dst.X - 5, dst.Y + 2));
|
||||
dc.DrawLine(lines, dst, new Point(dst.X - 5, dst.Y - 2));
|
||||
|
||||
// Draw Y axis
|
||||
dst = CoordToScreen(0, CanvasBounds.Top);
|
||||
dc.DrawLine(lines, CoordToScreen(0, CanvasBounds.Bottom), dst);
|
||||
dc.DrawLine(lines, dst, new Point(dst.X - 2, dst.Y + 5));
|
||||
dc.DrawLine(lines, dst, new Point(dst.X + 2, dst.Y + 5));
|
||||
}
|
||||
|
||||
private void RenderFunctions(DrawingContext dc)
|
||||
{
|
||||
if (Expressions.Count == 0) return;
|
||||
|
||||
int exprIndex = -1;
|
||||
bool visible = true;
|
||||
Pen pen = new Pen();
|
||||
|
||||
for (int i = 0; i < queuedPoints.Count - 1; i++)
|
||||
{
|
||||
if (queuedPoints[i] == specialSeparator)
|
||||
{
|
||||
exprIndex++; i++;
|
||||
pen = new Pen(new SolidColorBrush(Expressions[exprIndex].Color), Expressions[exprIndex].Thickness);
|
||||
visible = (queuedPoints[i] == specialVisibleTrue);
|
||||
}
|
||||
|
||||
else if (visible && queuedPoints[i + 1] != specialSeparator)
|
||||
{
|
||||
Point src = CoordToScreen(queuedPoints[i]);
|
||||
Point dst = CoordToScreen(queuedPoints[i + 1]);
|
||||
|
||||
if (ScreenBounds.IsInBounds(src) || ScreenBounds.IsInBounds(dst))
|
||||
dc.DrawLine(pen, src, dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRender(DrawingContext dc)
|
||||
{
|
||||
// Reduce garbage collector intrusions
|
||||
var latency = System.Runtime.GCSettings.LatencyMode;
|
||||
System.Runtime.GCSettings.LatencyMode = System.Runtime.GCLatencyMode.LowLatency;
|
||||
|
||||
// Draw grid
|
||||
RenderGrid(dc);
|
||||
RenderAxis(dc);
|
||||
|
||||
// Render functions
|
||||
RenderFunctions(dc);
|
||||
|
||||
// Base render
|
||||
base.OnRender(dc);
|
||||
|
||||
// Restore previous garbage collector setting
|
||||
System.Runtime.GCSettings.LatencyMode = latency;
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void Canvas_MouseWheel(object sender, MouseWheelEventArgs e)
|
||||
{
|
||||
if (e.Delta > 0) buttonZoomIn_Click(this, new RoutedEventArgs());
|
||||
else buttonZoomOut_Click(this, new RoutedEventArgs());
|
||||
}
|
||||
|
||||
#region Navigation control
|
||||
public void PeformMouseWheelChange(MouseWheelEventArgs e)
|
||||
{
|
||||
Canvas_MouseWheel(this, e);
|
||||
}
|
||||
|
||||
public void PerformMoveLeft()
|
||||
{
|
||||
buttonLeft_Click(this, new RoutedEventArgs());
|
||||
}
|
||||
|
||||
public void PerformMoveRight()
|
||||
{
|
||||
buttonRight_Click(this, new RoutedEventArgs());
|
||||
}
|
||||
|
||||
public void PerformMoveUp()
|
||||
{
|
||||
buttonUp_Click(this, new RoutedEventArgs());
|
||||
}
|
||||
|
||||
public void PerformMoveDown()
|
||||
{
|
||||
buttonBottom_Click(this, new RoutedEventArgs());
|
||||
}
|
||||
|
||||
public void PerformReset()
|
||||
{
|
||||
buttonReset_Click(this, new RoutedEventArgs());
|
||||
}
|
||||
|
||||
public void PerformZoomIn()
|
||||
{
|
||||
buttonZoomIn_Click(this, new RoutedEventArgs());
|
||||
}
|
||||
|
||||
public void PerformZoomOut()
|
||||
{
|
||||
buttonZoomOut_Click(this, new RoutedEventArgs());
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
80
Source/GraphingCalculator/Controls/IntegralWindow.xaml
Normal file
80
Source/GraphingCalculator/Controls/IntegralWindow.xaml
Normal file
@ -0,0 +1,80 @@
|
||||
<Window x:Class="GraphingCalculator.Controls.IntegralWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Integral" Height="331" Width="261" WindowStyle="ToolWindow" WindowStartupLocation="CenterScreen">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="/Styles/ButtonStyle.xaml" />
|
||||
<ResourceDictionary Source="/Styles/RadioButtonStyle.xaml" />
|
||||
<ResourceDictionary Source="/Styles/GroupBoxStyle.xaml" />
|
||||
<ResourceDictionary Source="/Styles/WarningGroupBoxStyle.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Window.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint=".5,1">
|
||||
<GradientStop Color="#EEE" Offset="0" />
|
||||
<GradientStop Color="#999" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Window.Background>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<GroupBox Style="{StaticResource WarningGroupBox}"
|
||||
Grid.Row="0" Grid.ColumnSpan="2" Margin="8,5,8,2"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Header="Warning" TextBlock.TextAlignment="Center" >
|
||||
<TextBlock TextWrapping="Wrap">This feature is experimental, so the given results may not fully be accurate.</TextBlock>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Expression" Grid.Row="1">
|
||||
<TextBox Name="inputExpression" TextWrapping="Wrap" />
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Interval" Grid.Row="2">
|
||||
<StackPanel>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="32" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="32" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Column="0" VerticalAlignment="Center">From:</TextBlock>
|
||||
<TextBox Name="inputIntervalBeg" Grid.Column="1" VerticalAlignment="Center">-1</TextBox>
|
||||
<TextBlock Grid.Column="3" VerticalAlignment="Center">To:</TextBlock>
|
||||
<TextBox Name="inputIntervalEnd" Grid.Column="4" VerticalAlignment="Center">1</TextBox>
|
||||
</Grid>
|
||||
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Result" Grid.Row="3">
|
||||
<TextBox Name="outputResult" IsReadOnly="True" Background="White"/>
|
||||
</GroupBox>
|
||||
|
||||
<Grid Grid.Row="4">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Name="buttonCalculate" Grid.Column="0" HorizontalAlignment="Right" Width="80" Click="buttonCalculate_Click">Calculate</Button>
|
||||
<Button Name="buttonClose" Grid.Column="1" HorizontalAlignment="Left" Width="80" Click="buttonClose_Click">Close</Button>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
</Window>
|
93
Source/GraphingCalculator/Controls/IntegralWindow.xaml.cs
Normal file
93
Source/GraphingCalculator/Controls/IntegralWindow.xaml.cs
Normal file
@ -0,0 +1,93 @@
|
||||
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.Shapes;
|
||||
|
||||
namespace GraphingCalculator.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for LimitWindow.xaml
|
||||
/// </summary>
|
||||
public partial class IntegralWindow : Window
|
||||
{
|
||||
#region Properties
|
||||
public string ExpressionString
|
||||
{
|
||||
get { return inputExpression.Text; }
|
||||
set { inputExpression.Text = value; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public IntegralWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
ExpressionString = "";
|
||||
}
|
||||
|
||||
public IntegralWindow(string expression)
|
||||
{
|
||||
InitializeComponent();
|
||||
ExpressionString = expression;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Other routines
|
||||
private void Result (string result, bool error = false)
|
||||
{
|
||||
outputResult.Text = result;
|
||||
if (error) outputResult.Foreground = Brushes.DarkRed;
|
||||
else outputResult.Foreground = Brushes.Black;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Button handlers
|
||||
private void buttonClose_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void buttonCalculate_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
double val_beg, val_end, integr_res;
|
||||
Expression beg, end, expr;
|
||||
beg = new Expression(inputIntervalBeg.Text);
|
||||
end = new Expression(inputIntervalEnd.Text);
|
||||
expr = new Expression(inputExpression.Text);
|
||||
|
||||
// Try to evaluate interval ends
|
||||
try { val_beg = beg.Evaluate(); }
|
||||
catch { Result("Failed to evaluate interval start.", true); return; }
|
||||
|
||||
try { val_end = end.Evaluate(); }
|
||||
catch { Result("Failed to evaluate interval end.", true); return; }
|
||||
|
||||
// Try to calculate the integral
|
||||
try { integr_res = Integrator.Integrate(expr, val_beg, val_end, "x"); }
|
||||
catch (Exception ex)
|
||||
{
|
||||
Result("Failed to evaluate expression. Message: " + ex.Message, true);
|
||||
Log.LogEvent("Failed to integrate expression: {0}", expr.ExpressionString);
|
||||
Log.LogEvent("> Interval: [{0}, {1}] = [{2}, {3}]", beg.ExpressionString, end.ExpressionString, val_beg, val_end);
|
||||
Log.LogEvent("> Message: {0}", ex.Message);
|
||||
Log.LogEvent("> Stack trace: {0}", ex.StackTrace);
|
||||
return;
|
||||
}
|
||||
|
||||
// Show result
|
||||
Result(Math.Round(integr_res, 14).ToString());
|
||||
Log.LogEvent("Integrated expression: {0}", expr.ExpressionString);
|
||||
Log.LogEvent("> Interval: [{0}, {1}] = [{2}, {3}]", beg.ExpressionString, end.ExpressionString, val_beg, val_end);
|
||||
Log.LogEvent("> Result: {0}", integr_res);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
44
Source/GraphingCalculator/Controls/LogWindow.xaml
Normal file
44
Source/GraphingCalculator/Controls/LogWindow.xaml
Normal file
@ -0,0 +1,44 @@
|
||||
<Window x:Class="GraphingCalculator.LogWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Log" Height="379" Width="543" WindowStartupLocation="CenterScreen" ShowInTaskbar="True">
|
||||
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="/Styles/ButtonStyle.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ListBox Name="listEntries" Grid.Row="0" Grid.ColumnSpan="10"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled" >
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock TextWrapping="Wrap" Text="{Binding}" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
|
||||
<Button Name="buttonCopy" Grid.Row="1" Grid.Column="1" Width="60" Click="buttonCopy_Click">Copy</Button>
|
||||
<Button Name="buttonSave" Grid.Row="1" Grid.Column="2" Width="60" Click="buttonSave_Click">Save...</Button>
|
||||
<Button Name="buttonClear" Grid.Row="1" Grid.Column="3" Width="60" Click="buttonClear_Click">Clear</Button>
|
||||
<Button Name="buttonRefresh" Grid.Row="1" Grid.Column="0" Width="60" Click="buttonRefresh_Click">Refresh</Button>
|
||||
<Button Name="buttonClose" Grid.Row="1" Grid.Column="5" Width="60" Click="buttonClose_Click">Close</Button>
|
||||
</Grid>
|
||||
</Window>
|
74
Source/GraphingCalculator/Controls/LogWindow.xaml.cs
Normal file
74
Source/GraphingCalculator/Controls/LogWindow.xaml.cs
Normal file
@ -0,0 +1,74 @@
|
||||
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.Shapes;
|
||||
|
||||
namespace GraphingCalculator
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for LogWindow.xaml
|
||||
/// </summary>
|
||||
public partial class LogWindow : Window
|
||||
{
|
||||
public LogWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
buttonRefresh_Click(this, new RoutedEventArgs());
|
||||
}
|
||||
|
||||
private void buttonCopy_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (listEntries.SelectedIndex != -1)
|
||||
Clipboard.SetText(listEntries.SelectedItem.ToString());
|
||||
}
|
||||
|
||||
private void buttonClear_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
listEntries.Items.Clear();
|
||||
Log.Entries.Clear();
|
||||
}
|
||||
|
||||
private void buttonRefresh_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
listEntries.Items.Clear();
|
||||
|
||||
foreach (var i in Log.Entries)
|
||||
listEntries.Items.Add(i);
|
||||
}
|
||||
|
||||
private void buttonClose_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void buttonSave_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Microsoft.Win32.SaveFileDialog dialog = new Microsoft.Win32.SaveFileDialog();
|
||||
dialog.Title = "Save log...";
|
||||
dialog.Filter = "Text file|*.txt|Log file|*.log|All files|*.*";
|
||||
|
||||
bool? res = dialog.ShowDialog();
|
||||
if (!res.HasValue && !res.Value) return;
|
||||
|
||||
try
|
||||
{
|
||||
System.IO.File.WriteAllLines(dialog.FileName, Log.Entries.ToArray());
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.LogEvent("Failed to save log to file {0}: {1}", dialog.FileName, ex.Message);
|
||||
MessageBox.Show("Error: " + ex.Message, "Failed to save log file!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
165
Source/GraphingCalculator/Controls/SettingsWindow.xaml
Normal file
165
Source/GraphingCalculator/Controls/SettingsWindow.xaml
Normal file
@ -0,0 +1,165 @@
|
||||
<Window x:Class="GraphingCalculator.SettingsWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Settings" Height="320" Width="562"
|
||||
ShowInTaskbar="False" WindowStartupLocation="CenterScreen"
|
||||
WindowStyle="ToolWindow">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="/Styles/GroupBoxStyle.xaml" />
|
||||
<ResourceDictionary Source="/Styles/ButtonStyle.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Window.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint=".5,1">
|
||||
<GradientStop Color="#EEE" Offset="0" />
|
||||
<GradientStop Color="#BBB" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Window.Background>
|
||||
|
||||
<Grid Margin="2">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<GroupBox Header="Graph precision" Grid.Row="0">
|
||||
<StackPanel>
|
||||
<Slider Name="sliderGraphPrecision"
|
||||
Minimum="50" Maximum="2000" TickFrequency="150"
|
||||
SmallChange="10" LargeChange="50"
|
||||
TickPlacement="BottomRight"/>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock>Minimum</TextBlock>
|
||||
<TextBlock Grid.Column="2">Maximum</TextBlock>
|
||||
</Grid>
|
||||
|
||||
<TextBlock TextWrapping="Wrap" FontSize="11"
|
||||
Foreground="#444" Margin="2,4,2,2">
|
||||
A higher precision means that drawing takes longer to render, making the application slower.</TextBlock>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Grid density" Grid.Column="1" Grid.Row="0">
|
||||
<StackPanel>
|
||||
<Slider Name="sliderGridDensity"
|
||||
Minimum="10" Maximum="100" TickFrequency="5"
|
||||
SmallChange="2" LargeChange="5"
|
||||
TickPlacement="BottomRight"/>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock>Higher</TextBlock>
|
||||
<TextBlock Grid.Column="2">Lower</TextBlock>
|
||||
</Grid>
|
||||
|
||||
<TextBlock TextWrapping="Wrap" FontSize="11"
|
||||
Foreground="#444" Margin="2,4,2,2">
|
||||
A higher density means that more grid lines are drawn.</TextBlock>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Grid numbers precision" Grid.Row="2" Grid.RowSpan="2">
|
||||
<StackPanel>
|
||||
<Slider Name="sliderDoublePrecision"
|
||||
Minimum="0" Maximum="15" TickFrequency="1"
|
||||
SmallChange="1" LargeChange="1" ValueChanged="sliderDoublePrecision_ValueChanged"
|
||||
TickPlacement="BottomRight" IsSnapToTickEnabled="True"/>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock>0</TextBlock>
|
||||
<TextBlock Name="outputDoublePrecision" Grid.Column="1" HorizontalAlignment="Center">? decimals</TextBlock>
|
||||
<TextBlock Grid.Column="2">15</TextBlock>
|
||||
</Grid>
|
||||
|
||||
<TextBlock TextWrapping="Wrap" FontSize="11"
|
||||
Foreground="#444" Margin="2,4,2,2">
|
||||
A higher precision means that more decimals appear in the graph. If the value is too high, values may overlap each other.</TextBlock>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Navigation sensitivity"
|
||||
Grid.Column="1" Grid.Row="2">
|
||||
<StackPanel>
|
||||
<Slider Name="sliderNavigationSensitivity"
|
||||
Minimum=".01" Maximum="1.5" TickFrequency=".1"
|
||||
SmallChange=".01" LargeChange=".05" ValueChanged="sliderNavigationSensitivity_ValueChanged"
|
||||
TickPlacement="BottomRight"/>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock>1%</TextBlock>
|
||||
<TextBlock Name="outputNavigationSensitivity" Grid.Column="1" HorizontalAlignment="Center">?% of screen</TextBlock>
|
||||
<TextBlock Grid.Column="2">150%</TextBlock>
|
||||
</Grid>
|
||||
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Zoom sensitivity"
|
||||
Grid.Column="1" Grid.Row="3">
|
||||
<StackPanel>
|
||||
<Slider Name="sliderZoomSensitivity"
|
||||
Minimum="1.01" Maximum="2.5" TickFrequency=".1"
|
||||
SmallChange=".01" LargeChange=".05" ValueChanged="sliderZoomSensitivity_ValueChanged"
|
||||
TickPlacement="BottomRight"/>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock>1%</TextBlock>
|
||||
<TextBlock Name="outputZoomSensitivity" Grid.Column="1" HorizontalAlignment="Center">?% of screen</TextBlock>
|
||||
<TextBlock Grid.Column="2">150%</TextBlock>
|
||||
</Grid>
|
||||
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<Grid Grid.Row="5" Grid.ColumnSpan="2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Name="buttonDefaults" Width="80" Click="buttonDefaults_Click">Defaults</Button>
|
||||
<Button Name="buttonCancel" Width="80" Grid.Column="2" Click="buttonCancel_Click">Cancel</Button>
|
||||
<Button Name="buttonAccept" Width="80" Grid.Column="3" Click="buttonAccept_Click">Accept</Button>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</Window>
|
94
Source/GraphingCalculator/Controls/SettingsWindow.xaml.cs
Normal file
94
Source/GraphingCalculator/Controls/SettingsWindow.xaml.cs
Normal file
@ -0,0 +1,94 @@
|
||||
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.Shapes;
|
||||
|
||||
namespace GraphingCalculator
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for SettingsWindow.xaml
|
||||
/// </summary>
|
||||
public partial class SettingsWindow : Window
|
||||
{
|
||||
|
||||
public SettingsWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
this.Loaded += new RoutedEventHandler(SettingsWindow_Loaded);
|
||||
|
||||
}
|
||||
|
||||
void SettingsWindow_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Update();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
sliderGraphPrecision.Value = GraphingCalculator.Properties.Settings.Default.PlotPrecision;
|
||||
sliderGridDensity.Value = GraphingCalculator.Properties.Settings.Default.GridDensity;
|
||||
sliderDoublePrecision.Value = GraphingCalculator.Properties.Settings.Default.RoundDoublesGraph;
|
||||
sliderNavigationSensitivity.Value = GraphingCalculator.Properties.Settings.Default.NavigationSensitivity;
|
||||
sliderZoomSensitivity.Value = GraphingCalculator.Properties.Settings.Default.ZoomSensitivity;
|
||||
}
|
||||
|
||||
private void Save()
|
||||
{
|
||||
GraphingCalculator.Properties.Settings.Default.PlotPrecision = sliderGraphPrecision.Value;
|
||||
GraphingCalculator.Properties.Settings.Default.GridDensity = sliderGridDensity.Value;
|
||||
GraphingCalculator.Properties.Settings.Default.RoundDoublesGraph = Convert.ToInt32(sliderDoublePrecision.Value);
|
||||
GraphingCalculator.Properties.Settings.Default.NavigationSensitivity = sliderNavigationSensitivity.Value;
|
||||
GraphingCalculator.Properties.Settings.Default.ZoomSensitivity = sliderZoomSensitivity.Value;
|
||||
}
|
||||
|
||||
|
||||
private void buttonDefaults_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
sliderGraphPrecision.Value = 600;
|
||||
sliderGridDensity.Value = 41;
|
||||
sliderDoublePrecision.Value = 4;
|
||||
sliderNavigationSensitivity.Value = 0.1;
|
||||
sliderZoomSensitivity.Value = 1.075;
|
||||
}
|
||||
|
||||
private void buttonCancel_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void buttonAccept_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Save();
|
||||
this.Close();
|
||||
}
|
||||
|
||||
|
||||
private void sliderDoublePrecision_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
||||
{
|
||||
if (outputDoublePrecision != null)
|
||||
outputDoublePrecision.Text = e.NewValue.ToString() + " decimals";
|
||||
}
|
||||
|
||||
private void sliderNavigationSensitivity_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
||||
{
|
||||
if (outputNavigationSensitivity != null)
|
||||
outputNavigationSensitivity.Text = Math.Round(e.NewValue * 100, 0).ToString() + "% of screen";
|
||||
}
|
||||
|
||||
private void sliderZoomSensitivity_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
||||
{
|
||||
if (outputZoomSensitivity != null)
|
||||
outputZoomSensitivity.Text = Math.Round((e.NewValue-1) * 100, 0).ToString() + "% of screen";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
361
Source/GraphingCalculator/Expression/Expression.cs
Normal file
361
Source/GraphingCalculator/Expression/Expression.cs
Normal file
@ -0,0 +1,361 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace GraphingCalculator
|
||||
{
|
||||
public class Expression
|
||||
{
|
||||
#region Token type
|
||||
public enum Token
|
||||
{
|
||||
None, Literal, Variable, Operator, Function, FunctionArgumentSeparator,
|
||||
LeftParanthesis, RightParanthesis
|
||||
};
|
||||
#endregion
|
||||
|
||||
#region Variables, properties
|
||||
private string expressionString;
|
||||
private bool isProcessed = false;
|
||||
|
||||
private List<KeyValuePair<Token, string>> tokens = new List<KeyValuePair<Token, string>>();
|
||||
private List<KeyValuePair<Token, string>> output = new List<KeyValuePair<Token, string>>();
|
||||
private Dictionary<string, double> variables = new Dictionary<string, double>();
|
||||
|
||||
protected List<KeyValuePair<Token, string>> Tokens { get { return tokens; } }
|
||||
protected List<KeyValuePair<Token, string>> Output { get { return output; } }
|
||||
public Dictionary<string, double> Variables { get { return variables; } }
|
||||
|
||||
public string ExpressionString
|
||||
{
|
||||
get { return expressionString; }
|
||||
set
|
||||
{
|
||||
expressionString = value;
|
||||
isProcessed = false;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Other stuff
|
||||
public void AddVariable(string name, double value)
|
||||
{
|
||||
variables[name] = value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
public Expression()
|
||||
{
|
||||
Variables.Add("pi", Math.PI);
|
||||
Variables.Add("e", Math.E);
|
||||
}
|
||||
|
||||
public Expression(string expr)
|
||||
: this()
|
||||
{
|
||||
expressionString = expr;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Processor
|
||||
private void Tokenize()
|
||||
{
|
||||
tokens.Clear();
|
||||
|
||||
for (int i = 0; i < ExpressionString.Length; i++)
|
||||
{
|
||||
if (char.IsWhiteSpace(ExpressionString[i])) continue;
|
||||
|
||||
if (IsOperator(ExpressionString[i]))
|
||||
{
|
||||
// Unary minus
|
||||
if (ExpressionString[i] == '-' && (tokens.Count == 0 || tokens.Last().Key == Token.LeftParanthesis || tokens.Last().Key == Token.Operator || tokens.Last().Key == Token.FunctionArgumentSeparator))
|
||||
tokens.Add(new KeyValuePair<Token, string>(Token.Operator, "!-"));
|
||||
|
||||
// Any other operator
|
||||
else tokens.Add(new KeyValuePair<Token, string>(Token.Operator, ExpressionString[i].ToString()));
|
||||
|
||||
}
|
||||
|
||||
else if (ExpressionString[i] == '(')
|
||||
tokens.Add(new KeyValuePair<Token, string>(Token.LeftParanthesis, ExpressionString[i].ToString()));
|
||||
|
||||
else if (ExpressionString[i] == ')')
|
||||
tokens.Add(new KeyValuePair<Token, string>(Token.RightParanthesis, ExpressionString[i].ToString()));
|
||||
|
||||
else if (ExpressionString[i] == ',')
|
||||
tokens.Add(new KeyValuePair<Token, string>(Token.FunctionArgumentSeparator, ExpressionString[i].ToString()));
|
||||
|
||||
else if (Char.IsDigit(ExpressionString[i]))
|
||||
tokens.Add(new KeyValuePair<Token, string>(Token.Literal, GetLiteral(ExpressionString, ref i)));
|
||||
|
||||
else if (Char.IsLetter(ExpressionString[i]))
|
||||
{
|
||||
if (IsFunction(ExpressionString, i)) tokens.Add(new KeyValuePair<Token, string>(Token.Function, GetVariable(ExpressionString, ref i)));
|
||||
else tokens.Add(new KeyValuePair<Token, string>(Token.Variable, GetVariable(ExpressionString, ref i)));
|
||||
}
|
||||
|
||||
else throw new Exception("Unrecognized character found!");
|
||||
}
|
||||
}
|
||||
|
||||
private void ShuntingYard()
|
||||
{
|
||||
Stack<KeyValuePair<Token, string>> stack = new Stack<KeyValuePair<Token, string>>();
|
||||
|
||||
foreach (var i in Tokens) switch (i.Key)
|
||||
{
|
||||
case Token.Variable:
|
||||
case Token.Literal: output.Add(i); break;
|
||||
|
||||
case Token.Function: stack.Push(i); break;
|
||||
|
||||
case Token.FunctionArgumentSeparator:
|
||||
|
||||
while (stack.Peek().Key != Token.LeftParanthesis)
|
||||
{
|
||||
output.Add(stack.Pop());
|
||||
if (stack.Count == 0) throw new Exception("Syntax error!");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Token.Operator:
|
||||
|
||||
if (IsLeftAssociative(i.Value))
|
||||
{
|
||||
while (stack.Count != 0 && Precedence(i.Value) <= Precedence(stack.Peek().Value))
|
||||
output.Add(stack.Pop());
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
while (stack.Count != 0 && Precedence(i.Value) < Precedence(stack.Peek().Value))
|
||||
output.Add(stack.Pop());
|
||||
}
|
||||
|
||||
stack.Push(i);
|
||||
break;
|
||||
|
||||
case Token.LeftParanthesis: stack.Push(i); break;
|
||||
|
||||
case Token.RightParanthesis:
|
||||
|
||||
while (stack.Peek().Key != Token.LeftParanthesis)
|
||||
{
|
||||
output.Add(stack.Pop());
|
||||
if (stack.Count == 0) throw new Exception("Mismatched parantheses!");
|
||||
}
|
||||
|
||||
stack.Pop(); // Pop paranthesis
|
||||
if (stack.Count > 0 && stack.Peek().Key == Token.Function) output.Add(stack.Pop()); // Pop function
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
if (stack.Peek().Key == Token.LeftParanthesis) throw new Exception("Mismatched parantheses!");
|
||||
output.Add(stack.Pop());
|
||||
}
|
||||
}
|
||||
|
||||
public void Process()
|
||||
{
|
||||
if (!isProcessed)
|
||||
{
|
||||
tokens.Clear();
|
||||
output.Clear();
|
||||
|
||||
Tokenize();
|
||||
ShuntingYard();
|
||||
}
|
||||
}
|
||||
|
||||
public double Evaluate()
|
||||
{
|
||||
Process();
|
||||
if (Output.Count == 0) return 0;
|
||||
|
||||
Stack<double> stack = new Stack<double>();
|
||||
|
||||
foreach (var i in Output)
|
||||
switch (i.Key)
|
||||
{
|
||||
case Token.Variable:
|
||||
if (!Variables.ContainsKey(i.Value)) throw new Exception("Undefined variable '" + i.Value + "'.");
|
||||
stack.Push(Variables[i.Value]);
|
||||
break;
|
||||
|
||||
case Token.Literal: stack.Push(double.Parse(i.Value)); break;
|
||||
|
||||
case Token.Operator:
|
||||
switch (i.Value)
|
||||
{
|
||||
case "!-": stack.Push(stack.Pop() * -1); break;
|
||||
case "+": stack.Push(stack.Pop() + stack.Pop()); break;
|
||||
case "-":
|
||||
{
|
||||
double b = stack.Pop();
|
||||
double a = stack.Pop();
|
||||
stack.Push(a - b);
|
||||
} break;
|
||||
|
||||
case "*": stack.Push(stack.Pop() * stack.Pop()); break;
|
||||
case "/":
|
||||
{
|
||||
double b = stack.Pop();
|
||||
double a = stack.Pop();
|
||||
stack.Push(a / b);
|
||||
} break;
|
||||
|
||||
case "%":
|
||||
{
|
||||
double b = stack.Pop();
|
||||
double a = stack.Pop();
|
||||
stack.Push(a % b);
|
||||
} break;
|
||||
|
||||
case "^":
|
||||
{
|
||||
double b = stack.Pop();
|
||||
double a = stack.Pop();
|
||||
stack.Push(Math.Pow(a, b));
|
||||
} break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Token.Function:
|
||||
EvaluateFunction(i.Value, ref stack);
|
||||
break;
|
||||
}
|
||||
|
||||
return stack.Pop();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Helper routines
|
||||
|
||||
private void EvaluateFunction(string func, ref Stack<double> stack)
|
||||
{
|
||||
switch (func)
|
||||
{
|
||||
case "sin": stack.Push(Math.Sin(stack.Pop())); break;
|
||||
case "sinh": stack.Push(Math.Sinh(stack.Pop())); break;
|
||||
case "cos": stack.Push(Math.Cos(stack.Pop())); break;
|
||||
case "cosh": stack.Push(Math.Cosh(stack.Pop())); break;
|
||||
case "tan": stack.Push(Math.Tan(stack.Pop())); break;
|
||||
case "tanh": stack.Push(Math.Tanh(stack.Pop())); break;
|
||||
case "ctan": stack.Push(1 / Math.Tan(stack.Pop())); break;
|
||||
|
||||
case "arcsin": stack.Push(Math.Asin(stack.Pop())); break;
|
||||
case "asin": stack.Push(Math.Asin(stack.Pop())); break;
|
||||
case "arccos": stack.Push(Math.Acos(stack.Pop())); break;
|
||||
case "acos": stack.Push(Math.Acos(stack.Pop())); break;
|
||||
case "arctan": stack.Push(Math.Atan(stack.Pop())); break;
|
||||
case "atan": stack.Push(Math.Atan(stack.Pop())); break;
|
||||
|
||||
case "truncate":
|
||||
case "int": stack.Push(Math.Truncate(stack.Pop())); break;
|
||||
case "floor": stack.Push(Math.Floor(stack.Pop())); break;
|
||||
case "ceil":
|
||||
case "ceiling": stack.Push(Math.Ceiling(stack.Pop())); break;
|
||||
|
||||
case "sqrt": stack.Push(Math.Sqrt(stack.Pop())); break;
|
||||
case "cbrt": stack.Push(Math.Pow(stack.Pop(), 1.0 / 3.0)); break;
|
||||
case "root": stack.Push(Math.Pow(stack.Pop(), 1 / stack.Pop())); break;
|
||||
|
||||
case "abs": stack.Push(Math.Abs(stack.Pop())); break;
|
||||
case "max": stack.Push(Math.Max(stack.Pop(), stack.Pop())); break;
|
||||
case "min": stack.Push(Math.Min(stack.Pop(), stack.Pop())); break;
|
||||
case "round": {
|
||||
double dec = stack.Pop(), val = stack.Pop();
|
||||
dec = Math.Max(0, dec);
|
||||
dec = Math.Min(15, dec);
|
||||
|
||||
stack.Push(Math.Round(val, Convert.ToInt32(dec)));
|
||||
break;
|
||||
}
|
||||
|
||||
case "lg": stack.Push(Math.Log10(stack.Pop())); break;
|
||||
case "log": stack.Push(Math.Log(stack.Pop(), stack.Pop())); break;
|
||||
case "ln": stack.Push(Math.Log(stack.Pop(), Math.E)); break;
|
||||
|
||||
default: throw new Exception("Undefined function '" + func + "'.");
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsLeftAssociative(string op)
|
||||
{
|
||||
return (op != "^");
|
||||
}
|
||||
|
||||
private static int Precedence(string op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case "+":
|
||||
case "-": return 1;
|
||||
|
||||
case "*":
|
||||
case "/":
|
||||
case "%": return 2;
|
||||
|
||||
case "^": return 3;
|
||||
|
||||
case "!-": return 10;
|
||||
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsOperator(char c)
|
||||
{
|
||||
const string operators = "+-*/%^";
|
||||
return operators.Contains(c);
|
||||
}
|
||||
|
||||
private static bool IsFunction(string s, int index)
|
||||
{
|
||||
// Skip function/variable name
|
||||
while (index < s.Length && char.IsLetterOrDigit(s[index])) index++;
|
||||
while (index < s.Length && char.IsWhiteSpace(s[index])) index++;
|
||||
|
||||
// End of string? Than it's a variable
|
||||
if (index >= s.Length) return false;
|
||||
|
||||
// If an operator, function separator, or ), variable
|
||||
if (s[index] == '(') return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static string GetVariable(string s, ref int index)
|
||||
{
|
||||
StringBuilder str = new StringBuilder();
|
||||
|
||||
while (index < s.Length && (char.IsLetterOrDigit(s[index])))
|
||||
str.Append(s[index++]);
|
||||
|
||||
index -= 1;
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
private static string GetLiteral(string s, ref int index)
|
||||
{
|
||||
StringBuilder str = new StringBuilder();
|
||||
|
||||
while (index < s.Length && (char.IsDigit(s[index]) || s[index] == '.'))
|
||||
str.Append(s[index++]);
|
||||
|
||||
index -= 1;
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
116
Source/GraphingCalculator/Expression/Integrator.cs
Normal file
116
Source/GraphingCalculator/Expression/Integrator.cs
Normal file
@ -0,0 +1,116 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace GraphingCalculator
|
||||
{
|
||||
public static class Integrator
|
||||
{
|
||||
#region Settings
|
||||
private static int maximumRecursionDepth = 16;
|
||||
public static int MaximumRecursionDepth
|
||||
{
|
||||
get { return maximumRecursionDepth; }
|
||||
set { maximumRecursionDepth = value; }
|
||||
}
|
||||
|
||||
private static double initialEpsilon = 1e-10;
|
||||
public static double InitialEpsilon
|
||||
{
|
||||
get { return initialEpsilon; }
|
||||
set { initialEpsilon = value; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Some variables
|
||||
private static string variable = "x";
|
||||
private static Expression expression;
|
||||
private static Dictionary<double, double> results = new Dictionary<double, double>();
|
||||
#endregion
|
||||
|
||||
#region Swap function
|
||||
private static void Swap(ref double a, ref double b)
|
||||
{
|
||||
double c = a;
|
||||
a = b;
|
||||
b = c;
|
||||
}
|
||||
#endregion
|
||||
|
||||
private static double EvaluateCache(double x)
|
||||
{
|
||||
if (!results.ContainsKey(x))
|
||||
{
|
||||
expression.Variables[variable] = x;
|
||||
results[x] = expression.Evaluate();
|
||||
}
|
||||
|
||||
return results[x];
|
||||
}
|
||||
|
||||
private static double CalculateIntegralAux(double xA, double xB, double epsilon, double S, double yA, double yB, double yC, int depth)
|
||||
{
|
||||
double xC = (xA + xB) / 2;
|
||||
double width = (xB - xA);
|
||||
double xD = (xA + xC) / 2;
|
||||
double xE = (xC + xB) / 2;
|
||||
double yD = EvaluateCache(xD);
|
||||
double yE = EvaluateCache(xE);
|
||||
|
||||
double Sleft = (width / 12) * (yA + 4 * yD + yC);
|
||||
double Sright = (width / 12) * (yC + 4 * yE + yB);
|
||||
double S2 = Sleft + Sright;
|
||||
|
||||
if (depth <= 0 || Math.Abs(S2 - S) <= 15 * epsilon)
|
||||
return S2 + (S2 - S) / 15;
|
||||
|
||||
return CalculateIntegralAux(xA, xC, epsilon / 2, Sleft, yA, yC, yD, depth - 1) +
|
||||
CalculateIntegralAux(xC, xB, epsilon / 2, Sright, yC, yB, yE, depth - 1);
|
||||
}
|
||||
|
||||
private static double CalculateIntegral(double xA, double xB, double epsilon, int maxDepth)
|
||||
{
|
||||
double xC = (xA + xB) / 2;
|
||||
double width = xB - xA;
|
||||
|
||||
double yA = EvaluateCache(xA);
|
||||
double yC = EvaluateCache(xC);
|
||||
double yB = EvaluateCache(xB);
|
||||
|
||||
double S = (width / 6) * (yA + 4 * yC + yB);
|
||||
|
||||
return CalculateIntegralAux(xA, xB, epsilon, S, yA, yB, yC, maxDepth);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates a definite integral (the area between the function graph and the X axis, where x ranges between beg and end.
|
||||
/// </summary>
|
||||
/// <param name="expr">An expression to integrate.</param>
|
||||
/// <param name="beg">Beginning of the interval</param>
|
||||
/// <param name="end">End of the interval</param>
|
||||
/// <param name="var">The name of the variable, by default is 'x'</param>
|
||||
public static double Integrate(Expression expr, double beg, double end, string var = "x")
|
||||
{
|
||||
double result = 0;
|
||||
bool changeSign = false;
|
||||
|
||||
// Make sure beg < end
|
||||
if (beg > end)
|
||||
{
|
||||
Swap(ref beg, ref end);
|
||||
changeSign = true;
|
||||
}
|
||||
|
||||
// Initialization
|
||||
results.Clear();
|
||||
variable = var;
|
||||
expression = expr;
|
||||
|
||||
// Calculation
|
||||
result = CalculateIntegral(beg, end, initialEpsilon, maximumRecursionDepth);
|
||||
if (changeSign) return -result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
64
Source/GraphingCalculator/Expression/VisualExpression.cs
Normal file
64
Source/GraphingCalculator/Expression/VisualExpression.cs
Normal file
@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace GraphingCalculator
|
||||
{
|
||||
public class VisualExpression : Expression
|
||||
{
|
||||
private static int rand_seed = 0x250D;
|
||||
|
||||
#region Variables
|
||||
private Color color = Colors.Blue;
|
||||
public Color Color { get { return color; } set { color = value; } }
|
||||
|
||||
private double thickness = 2;
|
||||
public double Thickness { get { return thickness; } set { thickness = value; } }
|
||||
|
||||
public bool IsVisible { get; set; }
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public VisualExpression() : base()
|
||||
{
|
||||
SetRandomColor();
|
||||
IsVisible = true;
|
||||
}
|
||||
|
||||
public VisualExpression(string expr) : base(expr)
|
||||
{
|
||||
SetRandomColor();
|
||||
IsVisible = true;
|
||||
}
|
||||
|
||||
public VisualExpression(string expr, Color color, double thickness = 2) : base(expr)
|
||||
{
|
||||
this.Color = color;
|
||||
this.Thickness = thickness;
|
||||
IsVisible = true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
public void SetRandomColor()
|
||||
{
|
||||
Random random = new Random(rand_seed);
|
||||
rand_seed = 0x51 * (random.Next() - 0xA82F90) * random.Next() - 0x513511;
|
||||
|
||||
int r, g, b;
|
||||
r = random.Next(256);
|
||||
g = random.Next(256);
|
||||
b = random.Next(256);
|
||||
|
||||
int avg = (r + g + b) / 3;
|
||||
int min = Math.Min(r, Math.Min(g, b));
|
||||
|
||||
if (avg >= 182) {
|
||||
r -= min; g -= min; b -= min;
|
||||
}
|
||||
|
||||
this.Color = Color.FromRgb(Convert.ToByte(r), Convert.ToByte(g), Convert.ToByte(b));
|
||||
}
|
||||
}
|
||||
}
|
187
Source/GraphingCalculator/GraphingCalculator.csproj
Normal file
187
Source/GraphingCalculator/GraphingCalculator.csproj
Normal file
@ -0,0 +1,187 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{A1B63EB2-82CF-4589-8AE2-18FAAF51B662}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>GraphingCalculator</RootNamespace>
|
||||
<AssemblyName>GraphingCalculator</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<NoWin32Manifest>true</NoWin32Manifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release - Publish|x86'">
|
||||
<OutputPath>..\..\TibisMathematicsSuite - Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisIgnoreBuiltInRuleSets>true</CodeAnalysisIgnoreBuiltInRuleSets>
|
||||
<CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
|
||||
<CodeAnalysisFailOnMissingRules>false</CodeAnalysisFailOnMissingRules>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>graphing-logo.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Xaml">
|
||||
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="App.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Compile Include="Controls\IntegralWindow.xaml.cs">
|
||||
<DependentUpon>IntegralWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\EvaluateWindow.xaml.cs">
|
||||
<DependentUpon>EvaluateWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Expression\Integrator.cs" />
|
||||
<Compile Include="Expression\VisualExpression.cs" />
|
||||
<Compile Include="Controls\SettingsWindow.xaml.cs">
|
||||
<DependentUpon>SettingsWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Page Include="Controls\IntegralWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Controls\EvaluateWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\GraphingCanvas.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\LogWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="MainWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="App.xaml.cs">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Bounds.cs" />
|
||||
<Compile Include="Expression\Expression.cs" />
|
||||
<Compile Include="Controls\GraphingCanvas.xaml.cs">
|
||||
<DependentUpon>GraphingCanvas.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="IO\ExpressionFile.cs" />
|
||||
<Compile Include="Log.cs" />
|
||||
<Compile Include="Controls\LogWindow.xaml.cs">
|
||||
<DependentUpon>LogWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="MainWindow.xaml.cs">
|
||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Page Include="Controls\SettingsWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Styles\ButtonStyle.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Styles\GroupBoxStyle.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Styles\RadioButtonStyle.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Styles\WarningGroupBoxStyle.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<None Include="app.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
<AppDesigner Include="Properties\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Launcher\DynamicLink.csproj">
|
||||
<Project>{A04B247B-6A95-462B-9E07-3337A1C158F1}</Project>
|
||||
<Name>Launcher</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="graphing-logo.ico" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
88
Source/GraphingCalculator/IO/ExpressionFile.cs
Normal file
88
Source/GraphingCalculator/IO/ExpressionFile.cs
Normal file
@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace GraphingCalculator.IO
|
||||
{
|
||||
public class ExpressionFile
|
||||
{
|
||||
private List<VisualExpression> expressions = new List<VisualExpression>();
|
||||
public List<VisualExpression> Expressions { get { return expressions; } }
|
||||
|
||||
public void SaveToFile(string filename)
|
||||
{
|
||||
System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(filename, new System.Xml.XmlWriterSettings() { Indent = true });
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteStartElement("Document");
|
||||
|
||||
// Write expressions
|
||||
writer.WriteStartElement("ExpressionList");
|
||||
foreach (var i in Expressions)
|
||||
{
|
||||
writer.WriteStartElement("Expression");
|
||||
writer.WriteAttributeString("String", i.ExpressionString);
|
||||
writer.WriteAttributeString("IsVisible", i.IsVisible.ToString());
|
||||
writer.WriteAttributeString("Color", i.Color.ToString());
|
||||
|
||||
foreach (var j in i.Variables)
|
||||
{
|
||||
writer.WriteStartElement("Variable");
|
||||
writer.WriteAttributeString("Key", j.Key);
|
||||
writer.WriteAttributeString("Value", j.Value.ToString());
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
writer.WriteEndElement();
|
||||
|
||||
// Finish
|
||||
writer.WriteEndElement();
|
||||
writer.WriteEndDocument();
|
||||
writer.Close();
|
||||
}
|
||||
|
||||
public void LoadFromFile(string filename)
|
||||
{
|
||||
System.Xml.XmlReader reader = System.Xml.XmlReader.Create(filename);
|
||||
string varKey = "", varVal = "";
|
||||
VisualExpression expr;
|
||||
|
||||
while (reader.Read())
|
||||
switch (reader.NodeType)
|
||||
{
|
||||
case System.Xml.XmlNodeType.Element:
|
||||
// Read an expression
|
||||
if (reader.Name == "Expression")
|
||||
{
|
||||
expr = new VisualExpression();
|
||||
while (reader.MoveToNextAttribute()) {
|
||||
if (reader.Name == "String") expr.ExpressionString = reader.Value;
|
||||
else if (reader.Name == "IsVisible") expr.IsVisible = bool.Parse(reader.Value);
|
||||
else if (reader.Name == "Color") expr.Color = (System.Windows.Media.Color) System.Windows.Media.ColorConverter.ConvertFromString(reader.Value);
|
||||
}
|
||||
|
||||
this.Expressions.Add(expr);
|
||||
}
|
||||
|
||||
// A variable
|
||||
else if (reader.Name == "Variable")
|
||||
{
|
||||
while (reader.MoveToNextAttribute()) {
|
||||
if (reader.Name == "Key") varKey = reader.Value;
|
||||
else if (reader.Name == "Value") varVal = reader.Value;
|
||||
}
|
||||
|
||||
if (varKey != "")
|
||||
this.Expressions.Last().Variables[varKey] = double.Parse(varVal);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
reader.Close();
|
||||
}
|
||||
}
|
||||
}
|
18
Source/GraphingCalculator/Log.cs
Normal file
18
Source/GraphingCalculator/Log.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace GraphingCalculator
|
||||
{
|
||||
public static class Log
|
||||
{
|
||||
private static List<string> entries = new List<string>();
|
||||
public static List<string> Entries { get { return entries; } }
|
||||
|
||||
public static void LogEvent (string format, params object[] p)
|
||||
{
|
||||
entries.Add(DateTime.Now + ": " + String.Format(format, p));
|
||||
}
|
||||
}
|
||||
}
|
163
Source/GraphingCalculator/MainWindow.xaml
Normal file
163
Source/GraphingCalculator/MainWindow.xaml
Normal file
@ -0,0 +1,163 @@
|
||||
<Window x:Class="GraphingCalculator.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:my="clr-namespace:GraphingCalculator"
|
||||
Title="Graphing Calculator" Height="526" Width="891"
|
||||
MouseWheel="Window_MouseWheel"
|
||||
KeyDown="Window_KeyDown" Icon="/GraphingCalculator;component/graphing-logo.ico">
|
||||
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Styles\GroupBoxStyle.xaml" />
|
||||
<ResourceDictionary Source="Styles\ButtonStyle.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="200px" />
|
||||
<ColumnDefinition Width="5px" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Menu Grid.ColumnSpan="100">
|
||||
<MenuItem Header="_File">
|
||||
<MenuItem Name="menuFileSave" Header="Save plotted expressions..."
|
||||
Click="menuFileSave_Click" InputGestureText="Ctrl+S"/>
|
||||
<MenuItem Name="menuFileImport" Header="Import..."
|
||||
Click="menuFileImport_Click" InputGestureText="Ctrl+O"/>
|
||||
<Separator />
|
||||
<MenuItem Name="menuFileExit" Header="Exit" Click="menuFileExit_Click"
|
||||
InputGestureText="Ctrl+Q"/>
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem Header="_Application">
|
||||
<MenuItem Name="menuAppLog" Header="View log..." Click="menuAppLog_Click"/>
|
||||
<MenuItem Name="menuAppPref" Header="Preferences" Click="menuAppPref_Click" />
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem Header="_Help">
|
||||
<MenuItem Name="menuAbout" Header="_About" Click="menuAbout_Click"
|
||||
InputGestureText="Ctrl+F1"/>
|
||||
<MenuItem Name="menuHelp" Header="_Help" Click="menuHelp_Click"
|
||||
InputGestureText="F1"/>
|
||||
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
|
||||
<Border Grid.Row="2" Grid.Column="0">
|
||||
<Border.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint=".5,1">
|
||||
<GradientStop Color="#EEE" Offset="0" />
|
||||
<GradientStop Color="#BBB" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Border.Background>
|
||||
|
||||
<Grid>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Input box -->
|
||||
<GroupBox Header="Input" Grid.Row="0">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBox Name="inputExpression"
|
||||
TextWrapping="Wrap" Height="50px"
|
||||
Grid.ColumnSpan="10" Margin="0,0,0,1" />
|
||||
|
||||
<Button Name="buttonPlot" Grid.Row="1" Grid.Column="0" Click="buttonPlot_Click">Plot</Button>
|
||||
<Button Name="buttonEvaluate" Grid.Row="1" Grid.Column="1" Click="buttonEvaluate_Click">Evaluate</Button>
|
||||
<Button Name="buttonIntegrate" Grid.Row="1" Grid.Column="2" Click="buttonIntegrate_Click">Integrate</Button>
|
||||
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<!-- Plotted functions list -->
|
||||
<GroupBox Header="Plotted expressions" Grid.Row="1">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ListBox Name="listExpressions" Grid.ColumnSpan="10" Margin="0,0,0,1"/>
|
||||
|
||||
<Button Name="buttonDelete" Grid.Row="1" Grid.Column="0" Click="buttonDelete_Click">Delete</Button>
|
||||
<Button Name="buttonClear" Grid.Row="1" Grid.Column="1" Click="buttonClear_Click">Clear</Button>
|
||||
<Button Name="buttonHideAll" Grid.Row="1" Grid.Column="2" Click="buttonHideAll_Click">Hide all</Button>
|
||||
|
||||
</Grid>
|
||||
|
||||
</GroupBox>
|
||||
|
||||
|
||||
<!-- Range box -->
|
||||
<GroupBox Header="Range" Grid.Row="2">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="2*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" VerticalAlignment="Center">Bottom:</TextBlock>
|
||||
<TextBlock Grid.Row="1" VerticalAlignment="Center">Left:</TextBlock>
|
||||
<TextBlock Grid.Row="2" VerticalAlignment="Center">Top:</TextBlock>
|
||||
<TextBlock Grid.Row="3" VerticalAlignment="Center">Right:</TextBlock>
|
||||
|
||||
<TextBox Name="inputBoundsBottom" Grid.Column="1" Grid.Row="0" />
|
||||
<TextBox Name="inputBoundsLeft" Grid.Column="1" Grid.Row="1" />
|
||||
<TextBox Name="inputBoundsTop" Grid.Column="1" Grid.Row="2" />
|
||||
<TextBox Name="inputBoundsRight" Grid.Column="1" Grid.Row="3" />
|
||||
|
||||
<Button Name="buttonChangeBounds" Margin="1,2,1,1"
|
||||
Grid.Row="4" Grid.ColumnSpan="10"
|
||||
Click="buttonChangeBounds_Click">Change</Button>
|
||||
|
||||
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<GridSplitter Grid.Column="1" Grid.Row="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
|
||||
|
||||
<my:GraphingCanvas x:Name="graphingCanvas" Grid.Column="2" Grid.Row="2" />
|
||||
|
||||
</Grid>
|
||||
</Window>
|
389
Source/GraphingCalculator/MainWindow.xaml.cs
Normal file
389
Source/GraphingCalculator/MainWindow.xaml.cs
Normal file
@ -0,0 +1,389 @@
|
||||
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
|
||||
}
|
||||
}
|
55
Source/GraphingCalculator/Properties/AssemblyInfo.cs
Normal file
55
Source/GraphingCalculator/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,55 @@
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Graphing Calculator")]
|
||||
[assembly: AssemblyDescription("Plots expressions, and calculates integrals and limits.")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Tibi Software")]
|
||||
[assembly: AssemblyProduct("Tibi's Mathematics Suite")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2012")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
//In order to begin building localizable applications, set
|
||||
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||
//inside a <PropertyGroup>. For example, if you are using US english
|
||||
//in your source files, set the <UICulture> to en-US. Then uncomment
|
||||
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
||||
//the line below to match the UICulture setting in the project file.
|
||||
|
||||
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
||||
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
71
Source/GraphingCalculator/Properties/Resources.Designer.cs
generated
Normal file
71
Source/GraphingCalculator/Properties/Resources.Designer.cs
generated
Normal file
@ -0,0 +1,71 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.261
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace GraphingCalculator.Properties
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources
|
||||
{
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if ((resourceMan == null))
|
||||
{
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GraphingCalculator.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture
|
||||
{
|
||||
get
|
||||
{
|
||||
return resourceCulture;
|
||||
}
|
||||
set
|
||||
{
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
117
Source/GraphingCalculator/Properties/Resources.resx
Normal file
117
Source/GraphingCalculator/Properties/Resources.resx
Normal file
@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
86
Source/GraphingCalculator/Properties/Settings.Designer.cs
generated
Normal file
86
Source/GraphingCalculator/Properties/Settings.Designer.cs
generated
Normal file
@ -0,0 +1,86 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.261
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace GraphingCalculator.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default {
|
||||
get {
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("600")]
|
||||
public double PlotPrecision {
|
||||
get {
|
||||
return ((double)(this["PlotPrecision"]));
|
||||
}
|
||||
set {
|
||||
this["PlotPrecision"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("41")]
|
||||
public double GridDensity {
|
||||
get {
|
||||
return ((double)(this["GridDensity"]));
|
||||
}
|
||||
set {
|
||||
this["GridDensity"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("4")]
|
||||
public int RoundDoublesGraph {
|
||||
get {
|
||||
return ((int)(this["RoundDoublesGraph"]));
|
||||
}
|
||||
set {
|
||||
this["RoundDoublesGraph"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("0.1")]
|
||||
public double NavigationSensitivity {
|
||||
get {
|
||||
return ((double)(this["NavigationSensitivity"]));
|
||||
}
|
||||
set {
|
||||
this["NavigationSensitivity"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("1.075")]
|
||||
public double ZoomSensitivity {
|
||||
get {
|
||||
return ((double)(this["ZoomSensitivity"]));
|
||||
}
|
||||
set {
|
||||
this["ZoomSensitivity"] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
21
Source/GraphingCalculator/Properties/Settings.settings
Normal file
21
Source/GraphingCalculator/Properties/Settings.settings
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="GraphingCalculator.Properties" GeneratedClassName="Settings">
|
||||
<Profiles />
|
||||
<Settings>
|
||||
<Setting Name="PlotPrecision" Type="System.Double" Scope="User">
|
||||
<Value Profile="(Default)">600</Value>
|
||||
</Setting>
|
||||
<Setting Name="GridDensity" Type="System.Double" Scope="User">
|
||||
<Value Profile="(Default)">41</Value>
|
||||
</Setting>
|
||||
<Setting Name="RoundDoublesGraph" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">4</Value>
|
||||
</Setting>
|
||||
<Setting Name="NavigationSensitivity" Type="System.Double" Scope="User">
|
||||
<Value Profile="(Default)">0.1</Value>
|
||||
</Setting>
|
||||
<Setting Name="ZoomSensitivity" Type="System.Double" Scope="User">
|
||||
<Value Profile="(Default)">1.075</Value>
|
||||
</Setting>
|
||||
</Settings>
|
||||
</SettingsFile>
|
55
Source/GraphingCalculator/Styles/ButtonStyle.xaml
Normal file
55
Source/GraphingCalculator/Styles/ButtonStyle.xaml
Normal file
@ -0,0 +1,55 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="Margin" Value="1" />
|
||||
<Setter Property="MinHeight" Value="22" />
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="OverridesDefaultStyle" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border Name="border" Padding="2" CornerRadius="4"
|
||||
BorderBrush="Gray" BorderThickness="1">
|
||||
<Border.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
|
||||
<GradientStop Color="#EEE" Offset="0" />
|
||||
<GradientStop Color="#BBB" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Border.Background>
|
||||
|
||||
<ContentPresenter HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center" />
|
||||
</Border>
|
||||
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="border" Property="Background">
|
||||
<Setter.Value>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
|
||||
<GradientStop Color="#FFF" Offset="0" />
|
||||
<GradientStop Color="#C8C8C8" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="border" Property="Background">
|
||||
<Setter.Value>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
|
||||
<GradientStop Color="#BBB" Offset="0" />
|
||||
<GradientStop Color="#DDD" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
|
||||
</ControlTemplate.Triggers>
|
||||
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
40
Source/GraphingCalculator/Styles/GroupBoxStyle.xaml
Normal file
40
Source/GraphingCalculator/Styles/GroupBoxStyle.xaml
Normal file
@ -0,0 +1,40 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<Style TargetType="GroupBox">
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="OverridesDefaultStyle" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="GroupBox">
|
||||
<Border Background="#FAF8F8"
|
||||
BorderBrush="White"
|
||||
BorderThickness="1"
|
||||
CornerRadius="5"
|
||||
Margin="4">
|
||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<ContentPresenter Margin="3,0,0,0" ContentSource="Header" >
|
||||
<ContentPresenter.Resources>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="Gray" />
|
||||
</Style>
|
||||
</ContentPresenter.Resources>
|
||||
</ContentPresenter>
|
||||
|
||||
<ContentPresenter HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Margin="4" Grid.Row="1" />
|
||||
|
||||
</Grid>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
63
Source/GraphingCalculator/Styles/RadioButtonStyle.xaml
Normal file
63
Source/GraphingCalculator/Styles/RadioButtonStyle.xaml
Normal file
@ -0,0 +1,63 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<Style TargetType="RadioButton">
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="OverridesDefaultStyle" Value="True" />
|
||||
<Setter Property="TextBlock.TextAlignment" Value="Center" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="RadioButton">
|
||||
<Grid>
|
||||
<Border Name="border" BorderBrush="Gray" BorderThickness="1">
|
||||
<Border.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
|
||||
<GradientStop Color="#EEE" Offset="0" />
|
||||
<GradientStop Color="#BBB" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Border.Background>
|
||||
</Border>
|
||||
<ContentPresenter Margin="4,1,4,1" />
|
||||
</Grid>
|
||||
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="Background" Value="White">
|
||||
<Setter TargetName="border" Property="CornerRadius" Value="5,0,0,5" />
|
||||
<Setter TargetName="border" Property="BorderThickness" Value="1,1,0,1" />
|
||||
</Trigger>
|
||||
<Trigger Property="Background" Value="Black">
|
||||
<Setter TargetName="border" Property="CornerRadius" Value="0,5,5,0" />
|
||||
<Setter TargetName="border" Property="BorderThickness" Value="1,1,1,1" />
|
||||
</Trigger>
|
||||
<Trigger Property="Background" Value="Gray">
|
||||
<Setter TargetName="border" Property="CornerRadius" Value="0" />
|
||||
<Setter TargetName="border" Property="BorderThickness" Value="1,1,0,1" />
|
||||
</Trigger>
|
||||
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="border" Property="Background">
|
||||
<Setter.Value>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
|
||||
<GradientStop Color="#FFF" Offset="0" />
|
||||
<GradientStop Color="#C8C8C8" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
|
||||
<Trigger Property="IsChecked" Value="True">
|
||||
<Setter TargetName="border" Property="Background">
|
||||
<Setter.Value>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
|
||||
<GradientStop Color="#BBB" Offset="0" />
|
||||
<GradientStop Color="#DDD" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
58
Source/GraphingCalculator/Styles/WarningGroupBoxStyle.xaml
Normal file
58
Source/GraphingCalculator/Styles/WarningGroupBoxStyle.xaml
Normal file
@ -0,0 +1,58 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<Style x:Key="WarningGroupBox" TargetType="{x:Type GroupBox}">
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="OverridesDefaultStyle" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type GroupBox}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.RowSpan="2" BorderBrush="Yellow"
|
||||
BorderThickness="1" CornerRadius="5" >
|
||||
<Border.Background>
|
||||
<LinearGradientBrush MappingMode="Absolute"
|
||||
SpreadMethod="Repeat"
|
||||
StartPoint="0,0"
|
||||
EndPoint="5,5">
|
||||
<GradientStop Color="#fde245" Offset=".5" />
|
||||
<GradientStop Color="#caae65" Offset=".5" />
|
||||
</LinearGradientBrush>
|
||||
</Border.Background>
|
||||
</Border>
|
||||
|
||||
<Border Grid.RowSpan="2" CornerRadius="5">
|
||||
<Border.Background>
|
||||
<RadialGradientBrush GradientOrigin=".5,0" Center=".5,.1"
|
||||
RadiusX=".9" RadiusY=".8" >
|
||||
<GradientStop Color="#e0FFFFFF" Offset="0" />
|
||||
<GradientStop Color="#10FFFFFF" Offset="1" />
|
||||
</RadialGradientBrush>
|
||||
</Border.Background>
|
||||
</Border>
|
||||
|
||||
<ContentPresenter Margin="7,4,4,0" ContentSource="Header" >
|
||||
<ContentPresenter.Resources>
|
||||
<Style TargetType="{x:Type TextBlock}">
|
||||
<Setter Property="FontWeight" Value="Bold" />
|
||||
<Setter Property="Foreground" Value="#835f01" />
|
||||
</Style>
|
||||
</ContentPresenter.Resources>
|
||||
</ContentPresenter>
|
||||
|
||||
<ContentPresenter HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Margin="5" Grid.Row="1" />
|
||||
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
27
Source/GraphingCalculator/app.config
Normal file
27
Source/GraphingCalculator/app.config
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<configSections>
|
||||
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
|
||||
<section name="GraphingCalculator.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
<userSettings>
|
||||
<GraphingCalculator.Properties.Settings>
|
||||
<setting name="PlotPrecision" serializeAs="String">
|
||||
<value>600</value>
|
||||
</setting>
|
||||
<setting name="GridDensity" serializeAs="String">
|
||||
<value>41</value>
|
||||
</setting>
|
||||
<setting name="RoundDoublesGraph" serializeAs="String">
|
||||
<value>4</value>
|
||||
</setting>
|
||||
<setting name="NavigationSensitivity" serializeAs="String">
|
||||
<value>0.1</value>
|
||||
</setting>
|
||||
<setting name="ZoomSensitivity" serializeAs="String">
|
||||
<value>1.075</value>
|
||||
</setting>
|
||||
</GraphingCalculator.Properties.Settings>
|
||||
</userSettings>
|
||||
</configuration>
|
BIN
Source/GraphingCalculator/graphing-logo.ico
Normal file
BIN
Source/GraphingCalculator/graphing-logo.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
Reference in New Issue
Block a user