double x = paddingLeft;
double y = 42;
string[] parts = formula.Split('=');
for (int i = 0; i < parts.Length; i++)
{
string part = parts[i].Trim();
if (part.Contains("/"))
x = DrawFraction(dc, part, x, y, font, regular);
else
{
Typeface tf = i == 0 && part.Length <= 3 ? italic : regular;
x = DrawText(dc, part, x, y + 16, font, tf, WpfBrushes.White);
}
if (i < parts.Length - 1)
x = DrawText(dc, "=", x + 10, y + 16, font, regular, WpfBrushes.White) + 10;
}
}
RenderTargetBitmap bmp = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
bmp.Render(visual);
string dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "NinjaTrader 8", "templates", "WTFormulaImages");
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
string file = Path.Combine(dir, "formula_" + DateTime.Now.ToString("yyyyMMdd_HHmmss_fff") + ".png");
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bmp));
using (FileStream fs = new FileStream(file, FileMode.Create))
encoder.Save(fs);
return file;
}
private double MeasureFormulaContentWidth(string formula, double size, Typeface regular, Typeface italic)
{
double x = 0;
string[] parts = formula.Split('=');
for (int i = 0; i < parts.Length; i++)
{
string part = parts[i].Trim();
if (part.Contains("/"))
x += MeasureFractionWidth(part, size, regular);
else
{
Typeface tf = i == 0 && part.Length <= 3 ? italic : regular;
FormattedText ft = new FormattedText(part, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, tf, size, WpfBrushes.White);
x += ft.WidthIncludingTrailingWhitespace;
}
if (i < parts.Length - 1)
{
FormattedText eq = new FormattedText("=", CultureInfo.InvariantCulture, FlowDirection.LeftToRight, regular, size, WpfBrushes.White);
x += 20 + eq.WidthIncludingTrailingWhitespace;
}
}
return x;
}
private double MeasureFractionWidth(string frac, double size, Typeface typeface)
{
string numerator = "";
string denominator = "";
ParseFraction(frac, out numerator, out denominator);
numerator = CleanFormulaText(numerator);
denominator = CleanFormulaText(denominator);
FormattedText top = new FormattedText(numerator, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, typeface, size, WpfBrushes.White);
FormattedText bottom = new FormattedText(denominator, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, typeface, size, WpfBrushes.White);
return Math.Max(top.Width, bottom.Width) + 26;
}
private double DrawText(DrawingContext dc, string text, double x, double y, double size, Typeface typeface, WpfBrush brush)
{
FormattedText ft = new FormattedText(text, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, typeface, size, brush);
dc.DrawText(ft, new WpfPoint(x, y));
return x + ft.WidthIncludingTrailingWhitespace;
}
private double DrawFraction(DrawingContext dc, string frac, double x, double y, double size, Typeface typeface)
{
string numerator = "";
string denominator = "";
ParseFraction(frac, out numerator, out denominator);
numerator = CleanFormulaText(numerator);
denominator = CleanFormulaText(denominator);
FormattedText top = new FormattedText(numerator, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, typeface, size, WpfBrushes.White);
FormattedText bottom = new FormattedText(denominator, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, typeface, size, WpfBrushes.White);
double w = Math.Max(top.Width, bottom.Width) + 18;
double topX = x + (w - top.Width) / 2;
double bottomX = x + (w - bottom.Width) / 2;
dc.DrawText(top, new WpfPoint(topX, y - 18));
Pen linePen = new Pen(WpfBrushes.White, 2);
dc.DrawLine(linePen, new WpfPoint(x, y + 24), new WpfPoint(x + w, y + 24));
dc.DrawText(bottom, new WpfPoint(bottomX, y + 30));
return x + w + 8;
}
private void ParseFraction(string text, out string numerator, out string denominator)
{
numerator = text;
denominator = "1";
int slash = text.IndexOf('/');
if (slash < 0)
return;
numerator = text.Substring(0, slash).Trim();
denominator = text.Substring(slash + 1).Trim();
numerator = StripOuterParentheses(numerator);
denominator = StripOuterParentheses(denominator);
}
private string StripOuterParentheses(string s)
{
s = s.Trim();
while (s.StartsWith("(") && s.EndsWith(")") && s.Length > 2)
s = s.Substring(1, s.Length - 2).Trim();
return s;
}
private string CleanFormulaText(string s)
{
s = s.Replace("-", " − ");
s = s.Replace("+", " + ");
s = s.Replace("*", " × ");
s = s.Replace(" ", " ");
return s.Trim();
}
private void LoadImageFromFile()
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = "Image Files|*.png;*.jpg;*.jpeg;*.bmp";
dlg.Title = "Choose Image";
if (dlg.ShowDialog() != true)
return;
ImageNote note = new ImageNote();
note.FilePath = dlg.FileName;
note.Position = new WpfPoint(100, 100);
try
{
BitmapImage temp = new BitmapImage();
temp.BeginInit();
temp.UriSource = new Uri(dlg.FileName);
temp.CacheOption = BitmapCacheOption.OnLoad;
temp.EndInit();
double originalW = temp.PixelWidth;
double originalH = temp.PixelHeight;
note.Width = 280;
note.Height = originalW > 0 ? 280 * (originalH / originalW) : 140;
}
catch
{
note.Width = 280;
note.Height = 140;
}
imageNotes.Add(note);
selectedImageIndex = imageNotes.Count - 1;
selectedTextIndex = -1;
selectedStrokeIndex = -1;
UpdateSelectedControls();
ForceRefresh();
}
private void DeleteSelected()
{
if (selectedImageIndex >= 0 && selectedImageIndex < imageNotes.Count)
imageNotes.RemoveAt(selectedImageIndex);
else if (selectedTextIndex >= 0 && selectedTextIndex < textNotes.Count)
textNotes.RemoveAt(selectedTextIndex);
else if (selectedStrokeIndex >= 0 && selectedStrokeIndex < strokes.Count)
strokes.RemoveAt(selectedStrokeIndex);
selectedImageIndex = -1;
selectedTextIndex = -1;
selectedStrokeIndex = -1;
UpdateSelectedControls();
ForceRefresh();
}
private void SelectItemAtPoint(WpfPoint p)
{
selectedImageIndex = HitTestImage(p);
selectedTextIndex = selectedImageIndex == -1 ? HitTestText(p) : -1;
selectedStrokeIndex = selectedImageIndex == -1 && selectedTextIndex == -1 ? HitTestStroke(p) : -1;
}
private int HitTestImage(WpfPoint p)
{
for (int i = imageNotes.Count - 1; i >= 0; i--)
{
ImageNote img = imageNotes[i];
if (p.X >= img.Position.X - 22 && p.X <= img.Position.X + img.Width && p.Y >= img.Position.Y - 8 && p.Y <= img.Position.Y + img.Height)
return i;
}
return -1;
}
private int HitTestText(WpfPoint p)
{
for (int i = textNotes.Count - 1; i >= 0; i--)
{
TextNote note = textNotes[i];
double width = EstimateTextWidth(note.Text, note.Size);
double height = EstimateTextHeight(note.Text, note.Size);
if (p.X >= note.Position.X - 22 && p.X <= note.Position.X + width + 20 && p.Y >= note.Position.Y - 8 && p.Y <= note.Position.Y + height + 20)
return i;
}
return -1;
}
private int HitTestStroke(WpfPoint p)
{
for (int i = strokes.Count - 1; i >= 0; i--)
{
if (strokes[i] == null || strokes[i].Points == null || strokes[i].Points.Count == 0)
continue;
double minX = double.MaxValue;
double minY = double.MaxValue;
double maxX = double.MinValue;
double maxY = double.MinValue;
foreach (WpfPoint pt in strokes[i].Points)
{
minX = Math.Min(minX, pt.X);
minY = Math.Min(minY, pt.Y);
maxX = Math.Max(maxX, pt.X);
maxY = Math.Max(maxY, pt.Y);
}
double pad = strokes[i].Width + 14;
if (p.X >= minX - pad && p.X <= maxX + pad && p.Y >= minY - pad && p.Y <= maxY + pad)
return i;
}
return -1;
}
private double EstimateTextWidth(string text, int size)
{
if (string.IsNullOrEmpty(text))
return 40;
string[] lines = text.Split('\n');
double max = 0;
foreach (string line in lines)
{
double w = line.Length * size * 0.58;
if (w > max)
max = w;
}
return Math.Max(40, max);
}
private double EstimateTextHeight(string text, int size)
{
int lines = 1;
if (!string.IsNullOrEmpty(text))
lines = Math.Max(1, text.Split('\n').Length);
return Math.Max(40, lines * (size + 8));
}
private bool TryDeleteAtPoint(WpfPoint p)
{
for (int i = textNotes.Count - 1; i >= 0; i--)
{
TextNote note = textNotes[i];
if (p.X >= note.Position.X - 24 &&
p.X <= note.Position.X - 2 &&
p.Y >= note.Position.Y - 4 &&
p.Y <= note.Position.Y + 20)
{
textNotes.RemoveAt(i);
selectedTextIndex = -1;
selectedStrokeIndex = -1;
selectedImageIndex = -1;
UpdateSelectedControls();
return true;
}
}
for (int i = imageNotes.Count - 1; i >= 0; i--)
{
ImageNote img = imageNotes[i];
if (p.X >= img.Position.X - 24 &&
p.X <= img.Position.X - 2 &&
p.Y >= img.Position.Y - 4 &&
p.Y <= img.Position.Y + 20)
{
imageNotes.RemoveAt(i);
selectedTextIndex = -1;
selectedStrokeIndex = -1;
selectedImageIndex = -1;
UpdateSelectedControls();
return true;
}
}
for (int i = strokes.Count - 1; i >= 0; i--)
{
WpfPoint pos = GetStrokeTopRight(strokes[i]);
if (p.X >= pos.X + 6 &&
p.X <= pos.X + 24 &&
p.Y >= pos.Y - 10 &&
p.Y <= pos.Y + 12)
{
strokes.RemoveAt(i);
selectedTextIndex = -1;
selectedStrokeIndex = -1;
selectedImageIndex = -1;
UpdateSelectedControls();
return true;
}
}
return false;
}
private void MoveStroke(int index, double dx, double dy)
{
if (index < 0 || index >= strokes.Count)
return;
for (int i = 0; i < strokes[index].Points.Count; i++)
{
strokes[index].Points[i] = new WpfPoint(strokes[index].Points[i].X + dx, strokes[index].Points[i].Y + dy);
}
}
private WpfPoint GetStrokeTopRight(StrokeItem stroke)
{
double maxX = double.MinValue;
double minY = double.MaxValue;
foreach (WpfPoint p in stroke.Points)
{
maxX = Math.Max(maxX, p.X);
minY = Math.Min(minY, p.Y);
}
return new WpfPoint(maxX, minY);
}
private void DrawStrokeDeleteX(StrokeItem stroke)
{
WpfPoint pos = GetStrokeTopRight(stroke);
using (D2D1Brush red = MakeDxBrush(WpfBrushes.Red))
{
float x = (float)(ChartPanel.X + pos.X + 8);
float y = (float)(ChartPanel.Y + pos.Y - 8);
RenderTarget.DrawLine(new Vector2(x, y), new Vector2(x + 12, y + 12), red, 3);
RenderTarget.DrawLine(new Vector2(x + 12, y), new Vector2(x, y + 12), red, 3);
}
}
private void DrawTextDeleteX(TextNote note)
{
using (D2D1Brush red = MakeDxBrush(WpfBrushes.Red))
{
float x = (float)(ChartPanel.X + note.Position.X - 18);
float y = (float)(ChartPanel.Y + note.Position.Y);
RenderTarget.DrawLine(new Vector2(x, y), new Vector2(x + 12, y + 12), red, 3);
RenderTarget.DrawLine(new Vector2(x + 12, y), new Vector2(x, y + 12), red, 3);
}
}
private void DrawImageDeleteX(ImageNote img)
{
using (D2D1Brush red = MakeDxBrush(WpfBrushes.Red))
{
float x = (float)(ChartPanel.X + img.Position.X - 18);
float y = (float)(ChartPanel.Y + img.Position.Y);
RenderTarget.DrawLine(new Vector2(x, y), new Vector2(x + 12, y + 12), red, 3);
RenderTarget.DrawLine(new Vector2(x + 12, y), new Vector2(x, y + 12), red, 3);
}
}
private void OpenCalculator()
{
if (calculatorWindow != null)
{
calculatorWindow.Activate();
return;
}
calculatorWindow = new Window();
calculatorWindow.Title = "WT Calculator";
calculatorWindow.Width = 520;
calculatorWindow.Height = 760;
calculatorWindow.MinWidth = 520;
calculatorWindow.MinHeight = 650;
calculatorWindow.Topmost = true;
calculatorWindow.ResizeMode = ResizeMode.CanResize;
calculatorWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen;
calculatorWindow.Background = SciFiPanelBrush();
Grid outer = new Grid();
outer.Margin = new Thickness(12);
outer.Background = SciFiPanelBrush();
outer.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
outer.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
outer.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
outer.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
outer.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
Grid header = new Grid();
header.Margin = new Thickness(0, 0, 0, 10);
header.ColumnDefinitions.Add(new ColumnDefinition());
header.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(48) });
TextBlock title = new TextBlock();
title.Text = "WT CALCULATOR";
title.Foreground = WpfBrushes.DodgerBlue;
title.FontWeight = FontWeights.Bold;
title.FontSize = 17;
title.VerticalAlignment = VerticalAlignment.Center;
Grid.SetColumn(title, 0);
header.Children.Add(title);
Button closeBtn = new Button();
closeBtn.Content = "X";
closeBtn.Height = 34;
closeBtn.Width = 42;
closeBtn.Margin = new Thickness(0);
StyleButton(closeBtn, WpfBrushes.Red, WpfBrushes.Red);
closeBtn.Click += (s, e) => CloseCalculator();
Grid.SetColumn(closeBtn, 1);
header.Children.Add(closeBtn);
calculatorDisplay = new TextBox();
calculatorDisplay.Height = 50;
calculatorDisplay.FontSize = 22;
calculatorDisplay.TextAlignment = TextAlignment.Right;
calculatorDisplay.Margin = new Thickness(0, 0, 0, 12);
calculatorDisplay.Padding = new Thickness(8, 6, 8, 6);
StyleTextBox(calculatorDisplay, WpfBrushes.DodgerBlue);
ScrollViewer calcScroll = new ScrollViewer();
calcScroll.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
calcScroll.Background = SciFiPanelBrush();
StackPanel calcMain = new StackPanel();
calcMain.Background = SciFiPanelBrush();
TextBlock basicLabel = MakeSectionLabel("BASIC CALCULATOR", WpfBrushes.Cyan);
calcMain.Children.Add(basicLabel);
UniformGrid grid = new UniformGrid();
grid.Columns = 4;
grid.Rows = 5;
grid.Margin = new Thickness(0, 0, 0, 12);
string[] keys = new string[]
{
"7", "8", "9", "/",
"4", "5", "6", "*",
"1", "2", "3", "-",
"0", ".", "(", ")",
"C", "DEL", "^", "+"
};
for (int i = 0; i < keys.Length; i++)
{
Button b = new Button();
b.Content = keys[i];
b.MinHeight = 48;
b.Margin = new Thickness(4);
StyleButton(b, WpfBrushes.Cyan, WpfBrushes.White);
string key = keys[i];
b.Click += (s, e) => CalculatorKey(key);
grid.Children.Add(b);
}
calcMain.Children.Add(grid);
TextBlock algebraLabel = MakeSectionLabel("ALGEBRA PRESETS", WpfBrushes.MediumPurple);
calcMain.Children.Add(algebraLabel);
UniformGrid algebraGrid = new UniformGrid();
algebraGrid.Columns = 2;
algebraGrid.Margin = new Thickness(0, 0, 0, 12);
algebraGrid.Children.Add(MakeCalculatorPresetButton("Slope", "m=(y2-y1)/(x2-x1)", WpfBrushes.MediumPurple));
algebraGrid.Children.Add(MakeCalculatorPresetButton("Point Slope", "y-y1=m(x-x1)", WpfBrushes.MediumPurple));
algebraGrid.Children.Add(MakeCalculatorPresetButton("Slope Intercept", "y=mx+b", WpfBrushes.MediumPurple));
algebraGrid.Children.Add(MakeCalculatorPresetButton("Quadratic", "x=(-b+sqrt(b^2-4ac))/(2a)", WpfBrushes.MediumPurple));
algebraGrid.Children.Add(MakeCalculatorPresetButton("Difference", "change=(new-old)/(old)", WpfBrushes.MediumPurple));
algebraGrid.Children.Add(MakeCalculatorPresetButton("Percent", "percent=part/whole", WpfBrushes.MediumPurple));
calcMain.Children.Add(algebraGrid);
TextBlock geometryLabel = MakeSectionLabel("GEOMETRY PRESETS", WpfBrushes.DarkCyan);
calcMain.Children.Add(geometryLabel);
UniformGrid geometryGrid = new UniformGrid();
geometryGrid.Columns = 2;
geometryGrid.Margin = new Thickness(0, 0, 0, 12);
geometryGrid.Children.Add(MakeCalculatorPresetButton("Triangle Area", "A=(b*h)/2", WpfBrushes.DarkCyan));
geometryGrid.Children.Add(MakeCalculatorPresetButton("Rectangle Area", "A=l*w", WpfBrushes.DarkCyan));
geometryGrid.Children.Add(MakeCalculatorPresetButton("Circle Area", "A=pi*r^2", WpfBrushes.DarkCyan));
geometryGrid.Children.Add(MakeCalculatorPresetButton("Pythagorean", "c^2=a^2+b^2", WpfBrushes.DarkCyan));
geometryGrid.Children.Add(MakeCalculatorPresetButton("Distance", "d=sqrt((x2-x1)^2+(y2-y1)^2)", WpfBrushes.DarkCyan));
geometryGrid.Children.Add(MakeCalculatorPresetButton("Midpoint X", "Mx=(x1+x2)/2", WpfBrushes.DarkCyan));
geometryGrid.Children.Add(MakeCalculatorPresetButton("Midpoint Y", "My=(y1+y2)/2", WpfBrushes.DarkCyan));
geometryGrid.Children.Add(MakeCalculatorPresetButton("Circle Circumference", "C=2*pi*r", WpfBrushes.DarkCyan));
calcMain.Children.Add(geometryGrid);
calcScroll.Content = calcMain;
Grid actionRow = new Grid();
actionRow.Margin = new Thickness(0, 10, 0, 10);
actionRow.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
actionRow.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
Button equalsBtn = new Button();
equalsBtn.Content = "=";
equalsBtn.Height = 42;
equalsBtn.Margin = new Thickness(0, 0, 6, 0);
StyleButton(equalsBtn, WpfBrushes.LimeGreen, WpfBrushes.LimeGreen);
equalsBtn.Click += (s, e) => CalculateDisplay();
Grid.SetColumn(equalsBtn, 0);
actionRow.Children.Add(equalsBtn);
Button sendFormulaBtn = new Button();
sendFormulaBtn.Content = "SEND TO FORMULA";
sendFormulaBtn.Height = 42;
sendFormulaBtn.Margin = new Thickness(6, 0, 0, 0);
StyleButton(sendFormulaBtn, WpfBrushes.MediumPurple, WpfBrushes.MediumPurple);
sendFormulaBtn.Click += (s, e) =>
{
if (formulaBox != null && calculatorDisplay != null)
formulaBox.Text = calculatorDisplay.Text;
};
Grid.SetColumn(sendFormulaBtn, 1);
actionRow.Children.Add(sendFormulaBtn);
TextBlock help = new TextBlock();
help.Text = "Basic math evaluates with =. Algebra and geometry presets are sent to the formula renderer.";
help.Foreground = WpfBrushes.LightGray;
help.TextWrapping = TextWrapping.Wrap;
help.Margin = new Thickness(0, 2, 0, 0);
Grid.SetRow(header, 0);
Grid.SetRow(calculatorDisplay, 1);
Grid.SetRow(calcScroll, 2);
Grid.SetRow(actionRow, 3);
Grid.SetRow(help, 4);
outer.Children.Add(header);
outer.Children.Add(calculatorDisplay);
outer.Children.Add(calcScroll);
outer.Children.Add(actionRow);
outer.Children.Add(help);
calculatorWindow.Content = outer;
calculatorWindow.Closed += (s, e) => calculatorWindow = null;
calculatorWindow.Show();
}
private Button MakeCalculatorPresetButton(string label, string formula, WpfBrush color)
{
Button b = new Button();
b.Content = label;
b.MinHeight = 38;
b.Margin = new Thickness(4);
StyleButton(b, color, color);
b.Click += (s, e) =>
{
if (calculatorDisplay != null)
{
calculatorDisplay.Text = formula;
calculatorDisplay.CaretIndex = calculatorDisplay.Text.Length;
}
};
return b;
}
private void CloseCalculator()
{
if (calculatorWindow != null)
{
Window temp = calculatorWindow;
calculatorWindow = null;
temp.Close();
}
}
private void CalculatorKey(string key)
{
if (calculatorDisplay == null)
return;
if (key == "C")
{
calculatorDisplay.Text = "";
return;
}
if (key == "DEL")
{
if (calculatorDisplay.Text.Length > 0)
calculatorDisplay.Text = calculatorDisplay.Text.Substring(0, calculatorDisplay.Text.Length - 1);
return;
}
calculatorDisplay.Text += key;
calculatorDisplay.CaretIndex = calculatorDisplay.Text.Length;
}
private void CalculateDisplay()
{
if (calculatorDisplay == null)
return;
try
{
double result = EvaluateExpression(calculatorDisplay.Text);
calculatorDisplay.Text = result.ToString("0.########", CultureInfo.InvariantCulture);
calculatorDisplay.CaretIndex = calculatorDisplay.Text.Length;
}
catch (Exception ex)
{
calculatorDisplay.Text = "ERROR: " + ex.Message;
calculatorDisplay.CaretIndex = calculatorDisplay.Text.Length;
}
}
private double EvaluateExpression(string expression)
{
MathParser parser = new MathParser(expression);
return parser.Parse();
}
private class MathParser
{
private readonly string text;
private int pos;
public MathParser(string expression)
{
text = expression == null ? "" : expression.Replace(" ", "");
pos = 0;
}
public double Parse()
{
double value = ParseExpression();
if (pos < text.Length)
throw new Exception("Bad input");
return value;
}
private double ParseExpression()
{
double value = ParseTerm();
while (pos < text.Length)
{
char op = text[pos];
if (op != '+' && op != '-')
break;
pos++;
double right = ParseTerm();
if (op == '+')
value += right;
else
value -= right;
}
return value;
}
private double ParseTerm()
{
double value = ParsePower();
while (pos < text.Length)
{
char op = text[pos];
if (op != '*' && op != '/')
break;
pos++;
double right = ParsePower();
if (op == '*')
value *= right;
else
value /= right;
}
return value;
}
private double ParsePower()
{
double value = ParseFactor();
while (pos < text.Length && text[pos] == '^')
{
pos++;
double right = ParseFactor();
value = Math.Pow(value, right);
}
return value;
}
private double ParseFactor()
{
if (pos >= text.Length)
throw new Exception("Missing value");
if (text[pos] == '+')
{
pos++;
return ParseFactor();
}
if (text[pos] == '-')
{
pos++;
return -ParseFactor();
}
if (text[pos] == '(')
{
pos++;
double value = ParseExpression();
if (pos >= text.Length || text[pos] != ')')
throw new Exception("Missing )");
pos++;
return value;
}
return ParseNumber();
}
private double ParseNumber()
{
int start = pos;
while (pos < text.Length && (char.IsDigit(text[pos]) || text[pos] == '.'))
pos++;
if (start == pos)
throw new Exception("Number expected");
string number = text.Substring(start, pos - start);
double value;
if (!double.TryParse(number, NumberStyles.Float, CultureInfo.InvariantCulture, out value))
throw new Exception("Bad number");
return value;
}
}
private void UpdateSelectedControls()
{
if (selectedInfo == null)
return;
if (selectedStrokeIndex >= 0 && selectedStrokeIndex < strokes.Count)
{
selectedInfo.Text = "Selected: Drawing #" + (selectedStrokeIndex + 1);
selectedWidthSlider.Value = strokes[selectedStrokeIndex].Width;
}
else if (selectedTextIndex >= 0 && selectedTextIndex < textNotes.Count)
{
selectedInfo.Text = "Selected: Text #" + (selectedTextIndex + 1);
selectedTextSizeSlider.Value = textNotes[selectedTextIndex].Size;
if (textBackgroundCheckBox != null)
textBackgroundCheckBox.IsChecked = textNotes[selectedTextIndex].ShowBackground;
}
else if (selectedImageIndex >= 0 && selectedImageIndex < imageNotes.Count)
{
selectedInfo.Text = "Selected: Formula / Image #" + (selectedImageIndex + 1);
selectedImageSizeSlider.Value = imageNotes[selectedImageIndex].Width;
}
else
{
selectedInfo.Text = "Selected: None";
}
}
private void ClosePanel()
{
if (panelWindow != null)
{
Window temp = panelWindow;
panelWindow = null;
temp.Close();
}
}
#region Properties
[Range(1, 50)]
[Display(Name = "Marker Width", Order = 1, GroupName = "Marker Settings")]
public int MarkerWidth { get; set; }
[XmlIgnore]
[Display(Name = "Marker Color", Order = 2, GroupName = "Marker Settings")]
public WpfBrush MarkerColor { get; set; }
[Range(8, 60)]
[Display(Name = "Text Size", Order = 3, GroupName = "Marker Settings")]
public int TextSize { get; set; }
[XmlIgnore]
[Display(Name = "Text Color", Order = 4, GroupName = "Marker Settings")]
public WpfBrush TextColor { get; set; }
[Display(Name = "Show Text Background", Order = 5, GroupName = "Marker Settings")]
public bool ShowTextBackground { get; set; }
#endregion
}
}