Front View plug-in does not init if no sensor added.
Fixing some format to make strings shorter.
Now trying to start SoundGraphAccess.exe process from same directory.
Packed mode now can display three sensors along with the current time.
1 // --------------------------------------------------------------------------------------------------------------------
2 // <copyright file="Plot.cs" company="OxyPlot">
3 // The MIT License (MIT)
5 // Copyright (c) 2012 Oystein Bjorke
7 // Permission is hereby granted, free of charge, to any person obtaining a
8 // copy of this software and associated documentation files (the
9 // "Software"), to deal in the Software without restriction, including
10 // without limitation the rights to use, copy, modify, merge, publish,
11 // distribute, sublicense, and/or sell copies of the Software, and to
12 // permit persons to whom the Software is furnished to do so, subject to
13 // the following conditions:
15 // The above copyright notice and this permission notice shall be included
16 // in all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 // Represents a control that displays a plot.
29 // --------------------------------------------------------------------------------------------------------------------
30 namespace OxyPlot.WindowsForms
33 using System.ComponentModel;
34 using System.Diagnostics;
36 using System.Runtime.InteropServices;
37 using System.Windows.Forms;
43 /// Represents a control that displays a plot.
46 public class Plot : Control, IPlotControl
49 /// The category for the properties of this control.
51 private const string OxyPlotCategory = "OxyPlot";
54 /// The invalidate lock.
56 private readonly object invalidateLock = new object();
61 private readonly object modelLock = new object();
64 /// The rendering lock.
66 private readonly object renderingLock = new object();
69 /// The current model (holding a reference to this plot control).
72 private PlotModel currentModel;
75 /// The is model invalidated.
77 private bool isModelInvalidated;
82 private PlotModel model;
85 /// The mouse manipulator.
88 private ManipulatorBase mouseManipulator;
91 /// The update data flag.
93 private bool updateDataFlag = true;
96 /// The zoom rectangle.
98 private Rectangle zoomRectangle;
101 /// The render context.
103 private GraphicsRenderContext renderContext;
106 /// Initializes a new instance of the <see cref="Plot"/> class.
110 this.renderContext = new GraphicsRenderContext();
112 // ReSharper disable DoNotCallOverridableMethodsInConstructor
113 this.DoubleBuffered = true;
114 // ReSharper restore DoNotCallOverridableMethodsInConstructor
115 this.KeyboardPanHorizontalStep = 0.1;
116 this.KeyboardPanVerticalStep = 0.1;
117 this.PanCursor = Cursors.Hand;
118 this.ZoomRectangleCursor = Cursors.SizeNWSE;
119 this.ZoomHorizontalCursor = Cursors.SizeWE;
120 this.ZoomVerticalCursor = Cursors.SizeNS;
124 /// Gets the actual model.
126 /// <value> The actual model. </value>
127 public PlotModel ActualModel
136 /// Gets or sets the keyboard pan horizontal step.
138 /// <value> The keyboard pan horizontal step. </value>
139 [Category(OxyPlotCategory)]
140 public double KeyboardPanHorizontalStep { get; set; }
143 /// Gets or sets the keyboard pan vertical step.
145 /// <value> The keyboard pan vertical step. </value>
146 [Category(OxyPlotCategory)]
147 public double KeyboardPanVerticalStep { get; set; }
150 /// Gets or sets the model.
154 [Category(OxyPlotCategory)]
155 public PlotModel Model
164 if (this.model != value)
167 this.OnModelChanged();
173 /// Gets or sets the pan cursor.
175 [Category(OxyPlotCategory)]
176 public Cursor PanCursor { get; set; }
179 /// Gets or sets the horizontal zoom cursor.
181 [Category(OxyPlotCategory)]
182 public Cursor ZoomHorizontalCursor { get; set; }
185 /// Gets or sets the rectangle zoom cursor.
187 [Category(OxyPlotCategory)]
188 public Cursor ZoomRectangleCursor { get; set; }
191 /// Gets or sets vertical zoom cursor.
193 [Category(OxyPlotCategory)]
194 public Cursor ZoomVerticalCursor { get; set; }
197 /// Get the axes from a point.
199 /// <param name="pt">
202 /// <param name="xaxis">
205 /// <param name="yaxis">
208 public void GetAxesFromPoint(ScreenPoint pt, out Axis xaxis, out Axis yaxis)
210 if (this.Model == null)
217 this.Model.GetAxesFromPoint(pt, out xaxis, out yaxis);
221 /// Get the series from a point.
223 /// <param name="pt">
224 /// The point (screen coordinates).
226 /// <param name="limit">
232 public Series GetSeriesFromPoint(ScreenPoint pt, double limit)
234 if (this.Model == null)
239 return this.Model.GetSeriesFromPoint(pt, limit);
243 /// The hide tracker.
245 public void HideTracker()
250 /// The hide zoom rectangle.
252 public void HideZoomRectangle()
254 this.zoomRectangle = Rectangle.Empty;
259 /// The invalidate plot.
261 /// <param name="updateData">
264 public void InvalidatePlot(bool updateData)
266 lock (this.invalidateLock)
268 this.isModelInvalidated = true;
269 this.updateDataFlag = this.updateDataFlag || updateData;
276 /// Called when the Model property has been changed.
278 public void OnModelChanged()
280 lock (this.modelLock)
282 if (this.currentModel != null)
284 this.currentModel.AttachPlotControl(null);
287 if (this.Model != null)
289 if (this.Model.PlotControl != null)
291 throw new InvalidOperationException(
292 "This PlotModel is already in use by some other plot control.");
295 this.Model.AttachPlotControl(this);
296 this.currentModel = this.Model;
300 this.InvalidatePlot(true);
306 /// <param name="axis">
309 /// <param name="x0">
312 /// <param name="x1">
315 public void Pan(Axis axis, ScreenPoint x0, ScreenPoint x1)
318 this.InvalidatePlot(false);
324 /// <param name="deltax">
325 /// The horizontal delta.
327 /// <param name="deltay">
328 /// The vertical delta.
330 public void PanAll(double deltax, double deltay)
332 foreach (var a in this.ActualModel.Axes)
334 a.Pan(a.IsHorizontal() ? deltax : deltay);
337 this.InvalidatePlot(false);
341 /// The refresh plot.
343 /// <param name="updateData">
346 public void RefreshPlot(bool updateData)
348 lock (this.invalidateLock)
350 this.isModelInvalidated = true;
351 this.updateDataFlag = this.updateDataFlag || updateData;
360 /// <param name="axis">
363 public void Reset(Axis axis)
366 this.InvalidatePlot(false);
370 /// Sets the cursor type.
372 /// <param name="cursorType">
375 public void SetCursorType(CursorType cursorType)
380 this.Cursor = this.PanCursor;
382 case CursorType.ZoomRectangle:
383 this.Cursor = this.ZoomRectangleCursor;
385 case CursorType.ZoomHorizontal:
386 this.Cursor = this.ZoomHorizontalCursor;
388 case CursorType.ZoomVertical:
389 this.Cursor = this.ZoomVerticalCursor;
392 this.Cursor = Cursors.Arrow;
398 /// The show tracker.
400 /// <param name="data">
403 public void ShowTracker(TrackerHitResult data)
405 // not implemented for WindowsForms
409 /// The show zoom rectangle.
414 public void ShowZoomRectangle(OxyRect r)
416 this.zoomRectangle = new Rectangle((int)r.Left, (int)r.Top, (int)r.Width, (int)r.Height);
423 /// <param name="axis">
426 /// <param name="p1">
429 /// <param name="p2">
432 public void Zoom(Axis axis, double p1, double p2)
435 this.InvalidatePlot(false);
441 public void ZoomAll()
443 foreach (var a in this.Model.Axes)
448 this.InvalidatePlot(false);
454 /// <param name="delta">
457 public void ZoomAllAxes(double delta)
459 foreach (var a in this.ActualModel.Axes)
461 this.ZoomAt(a, delta);
464 this.RefreshPlot(false);
470 /// <param name="axis">
473 /// <param name="factor">
479 public void ZoomAt(Axis axis, double factor, double x = double.NaN)
483 double sx = (axis.Transform(axis.ActualMaximum) + axis.Transform(axis.ActualMinimum)) * 0.5;
484 x = axis.InverseTransform(sx);
487 axis.ZoomAt(factor, x);
488 this.InvalidatePlot(false);
492 /// The on mouse down.
497 protected override void OnMouseDown(MouseEventArgs e)
501 if (this.mouseManipulator != null)
509 if (this.ActualModel != null)
511 var args = this.CreateMouseEventArgs(e);
512 this.ActualModel.HandleMouseDown(this, args);
519 this.mouseManipulator = this.GetManipulator(e);
521 if (this.mouseManipulator != null)
523 this.mouseManipulator.Started(this.CreateManipulationEventArgs(e));
528 /// The on mouse move.
533 protected override void OnMouseMove(MouseEventArgs e)
537 if (this.ActualModel != null)
539 var args = this.CreateMouseEventArgs(e);
540 this.ActualModel.HandleMouseMove(this, args);
547 if (this.mouseManipulator != null)
549 this.mouseManipulator.Delta(this.CreateManipulationEventArgs(e));
554 /// Raises the <see cref="E:System.Windows.Forms.Control.MouseUp"/> event.
557 /// A <see cref="T:System.Windows.Forms.MouseEventArgs"/> that contains the event data.
559 protected override void OnMouseUp(MouseEventArgs e)
562 this.Capture = false;
564 if (this.ActualModel != null)
566 var args = this.CreateMouseEventArgs(e);
567 this.ActualModel.HandleMouseUp(this, args);
574 if (this.mouseManipulator != null)
576 this.mouseManipulator.Completed(this.CreateManipulationEventArgs(e));
579 this.mouseManipulator = null;
583 /// Raises the <see cref="E:System.Windows.Forms.Control.MouseWheel"/> event.
586 /// A <see cref="T:System.Windows.Forms.MouseEventArgs"/> that contains the event data.
588 protected override void OnMouseWheel(MouseEventArgs e)
590 base.OnMouseWheel(e);
591 bool isControlDown = ModifierKeys == Keys.Control;
592 var m = new ZoomStepManipulator(this, e.Delta * 0.001, isControlDown);
593 m.Started(new ManipulationEventArgs(e.Location.ToScreenPoint()));
597 /// Raises the <see cref="E:System.Windows.Forms.Control.Paint"/> event.
600 /// A <see cref="T:System.Windows.Forms.PaintEventArgs"/> that contains the event data.
602 protected override void OnPaint(PaintEventArgs e)
607 lock (this.invalidateLock)
609 if (this.isModelInvalidated)
611 if (this.model != null)
613 this.model.Update(this.updateDataFlag);
614 this.updateDataFlag = false;
617 this.isModelInvalidated = false;
621 lock (this.renderingLock)
623 this.renderContext.SetGraphicsTarget(e.Graphics);
624 if (this.model != null)
626 this.model.Render(this.renderContext, this.Width, this.Height);
629 if (this.zoomRectangle != Rectangle.Empty)
631 using (var zoomBrush = new SolidBrush(Color.FromArgb(0x40, 0xFF, 0xFF, 0x00)))
632 using (var zoomPen = new Pen(Color.Black))
634 zoomPen.DashPattern = new float[] { 3, 1 };
635 e.Graphics.FillRectangle(zoomBrush, this.zoomRectangle);
636 e.Graphics.DrawRectangle(zoomPen, this.zoomRectangle);
641 catch (Exception paintException)
643 var trace = new StackTrace(paintException);
644 Debug.WriteLine(paintException);
645 Debug.WriteLine(trace);
646 using (var font = new Font("Arial", 10))
648 e.Graphics.DrawString(
649 "OxyPlot paint exception: " + paintException.Message, font, Brushes.Red, 10, 10);
655 /// Raises the <see cref="E:System.Windows.Forms.Control.PreviewKeyDown"/> event.
658 /// A <see cref="T:System.Windows.Forms.PreviewKeyDownEventArgs"/> that contains the event data.
660 protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
662 base.OnPreviewKeyDown(e);
663 if (e.KeyCode == Keys.A)
668 bool control = (e.Modifiers & Keys.Control) == Keys.Control;
669 bool alt = (e.Modifiers & Keys.Alt) == Keys.Alt;
700 if ((deltax * deltax) + (deltay * deltay) > 0)
702 deltax = deltax * this.ActualModel.PlotArea.Width * this.KeyboardPanHorizontalStep;
703 deltay = deltay * this.ActualModel.PlotArea.Height * this.KeyboardPanVerticalStep;
705 // small steps if the user is pressing control
712 this.PanAll(deltax, deltay);
717 if (Math.Abs(zoom) > 1e-8)
724 this.ZoomAllAxes(1 + (zoom * 0.12));
729 if (control && alt && this.ActualModel != null)
734 this.SetClipboardText(this.ActualModel.CreateTextReport());
737 this.SetClipboardText(this.ActualModel.ToCode());
741 // this.SetClipboardText(this.ActualModel.ToXml());
748 /// Raises the <see cref="E:System.Windows.Forms.Control.Resize"/> event.
751 /// An <see cref="T:System.EventArgs"/> that contains the event data.
753 protected override void OnResize(EventArgs e)
756 this.InvalidatePlot(false);
760 /// Converts the changed button.
763 /// The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.
766 /// The mouse button.
768 private static OxyMouseButton ConvertChangedButton(MouseEventArgs e)
772 case MouseButtons.Left:
773 return OxyMouseButton.Left;
774 case MouseButtons.Middle:
775 return OxyMouseButton.Middle;
776 case MouseButtons.Right:
777 return OxyMouseButton.Right;
778 case MouseButtons.XButton1:
779 return OxyMouseButton.XButton1;
780 case MouseButtons.XButton2:
781 return OxyMouseButton.XButton2;
784 return OxyMouseButton.Left;
788 /// Creates the mouse event arguments.
791 /// The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.
794 /// Mouse event arguments.
796 private OxyMouseEventArgs CreateMouseEventArgs(MouseEventArgs e)
798 return new OxyMouseEventArgs
800 ChangedButton = ConvertChangedButton(e),
801 Position = new ScreenPoint(e.Location.X, e.Location.Y),
802 IsShiftDown = (ModifierKeys & Keys.Shift) == Keys.Shift,
803 IsControlDown = (ModifierKeys & Keys.Control) == Keys.Control,
804 IsAltDown = (ModifierKeys & Keys.Alt) == Keys.Alt,
809 /// Creates the manipulation event args.
812 /// The MouseEventArgs instance containing the event data.
815 /// A manipulation event args object.
817 private ManipulationEventArgs CreateManipulationEventArgs(MouseEventArgs e)
819 return new ManipulationEventArgs(e.Location.ToScreenPoint());
823 /// Gets the manipulator for the current mouse button and modifier keys.
829 /// A manipulator or null if no gesture was recognized.
831 private ManipulatorBase GetManipulator(MouseEventArgs e)
833 bool control = (ModifierKeys & Keys.Control) == Keys.Control;
834 bool shift = (ModifierKeys & Keys.Shift) == Keys.Shift;
835 bool alt = (ModifierKeys & Keys.Alt) == Keys.Alt;
837 bool lmb = e.Button == MouseButtons.Left;
838 bool rmb = e.Button == MouseButtons.Right;
839 bool mmb = e.Button == MouseButtons.Middle;
840 bool xb1 = e.Button == MouseButtons.XButton1;
841 bool xb2 = e.Button == MouseButtons.XButton2;
843 // MMB / control RMB / control+alt LMB
844 if (mmb || (control && lmb) || (control && alt && rmb))
846 return new ZoomRectangleManipulator(this);
849 // Right mouse button / alt+left mouse button
850 if (lmb || (rmb && alt))
854 return new ResetManipulator(this);
856 return new PanManipulator(this);
862 return new TrackerManipulator(this) { Snap = !control, PointsOnly = shift };
865 // XButtons are zoom-stepping
868 double d = xb1 ? 0.05 : -0.05;
869 return new ZoomStepManipulator(this, d, control);
876 /// The set clipboard text.
878 /// <param name="text">
881 private void SetClipboardText(string text)
885 // todo: can't get the following solution to work
886 // http://stackoverflow.com/questions/5707990/requested-clipboard-operation-did-not-succeed
887 Clipboard.SetText(text);
889 catch (ExternalException ee)
891 // Requested Clipboard operation did not succeed.
892 MessageBox.Show(this, ee.Message, "OxyPlot");