moel@391: // -------------------------------------------------------------------------------------------------------------------- moel@391: // moel@391: // The MIT License (MIT) moel@391: // moel@391: // Copyright (c) 2012 Oystein Bjorke moel@391: // moel@391: // Permission is hereby granted, free of charge, to any person obtaining a moel@391: // copy of this software and associated documentation files (the moel@391: // "Software"), to deal in the Software without restriction, including moel@391: // without limitation the rights to use, copy, modify, merge, publish, moel@391: // distribute, sublicense, and/or sell copies of the Software, and to moel@391: // permit persons to whom the Software is furnished to do so, subject to moel@391: // the following conditions: moel@391: // moel@391: // The above copyright notice and this permission notice shall be included moel@391: // in all copies or substantial portions of the Software. moel@391: // moel@391: // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS moel@391: // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF moel@391: // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. moel@391: // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY moel@391: // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, moel@391: // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE moel@391: // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. moel@391: // moel@391: // moel@391: // Represents a control that displays a plot. moel@391: // moel@391: // -------------------------------------------------------------------------------------------------------------------- moel@391: namespace OxyPlot.WindowsForms moel@391: { moel@391: using System; moel@391: using System.ComponentModel; moel@391: using System.Diagnostics; moel@391: using System.Drawing; moel@391: using System.Runtime.InteropServices; moel@391: using System.Windows.Forms; moel@391: moel@391: using OxyPlot.Axes; moel@391: using OxyPlot.Series; moel@391: moel@391: /// moel@391: /// Represents a control that displays a plot. moel@391: /// moel@391: [Serializable] moel@391: public class Plot : Control, IPlotControl moel@391: { moel@391: /// moel@391: /// The category for the properties of this control. moel@391: /// moel@391: private const string OxyPlotCategory = "OxyPlot"; moel@391: moel@391: /// moel@391: /// The invalidate lock. moel@391: /// moel@391: private readonly object invalidateLock = new object(); moel@391: moel@391: /// moel@391: /// The model lock. moel@391: /// moel@391: private readonly object modelLock = new object(); moel@391: moel@391: /// moel@391: /// The rendering lock. moel@391: /// moel@391: private readonly object renderingLock = new object(); moel@391: moel@391: /// moel@391: /// The current model (holding a reference to this plot control). moel@391: /// moel@391: [NonSerialized] moel@391: private PlotModel currentModel; moel@391: moel@391: /// moel@391: /// The is model invalidated. moel@391: /// moel@391: private bool isModelInvalidated; moel@391: moel@391: /// moel@391: /// The model. moel@391: /// moel@391: private PlotModel model; moel@391: moel@391: /// moel@391: /// The mouse manipulator. moel@391: /// moel@391: [NonSerialized] moel@391: private ManipulatorBase mouseManipulator; moel@391: moel@391: /// moel@391: /// The update data flag. moel@391: /// moel@391: private bool updateDataFlag = true; moel@391: moel@391: /// moel@391: /// The zoom rectangle. moel@391: /// moel@391: private Rectangle zoomRectangle; moel@391: moel@391: /// moel@391: /// The render context. moel@391: /// moel@391: private GraphicsRenderContext renderContext; moel@391: moel@391: /// moel@391: /// Initializes a new instance of the class. moel@391: /// moel@391: public Plot() moel@391: { moel@391: this.renderContext = new GraphicsRenderContext(); moel@391: moel@391: // ReSharper disable DoNotCallOverridableMethodsInConstructor moel@391: this.DoubleBuffered = true; moel@391: // ReSharper restore DoNotCallOverridableMethodsInConstructor moel@391: this.KeyboardPanHorizontalStep = 0.1; moel@391: this.KeyboardPanVerticalStep = 0.1; moel@391: this.PanCursor = Cursors.Hand; moel@391: this.ZoomRectangleCursor = Cursors.SizeNWSE; moel@391: this.ZoomHorizontalCursor = Cursors.SizeWE; moel@391: this.ZoomVerticalCursor = Cursors.SizeNS; moel@391: } moel@391: moel@391: /// moel@391: /// Gets the actual model. moel@391: /// moel@391: /// The actual model. moel@391: public PlotModel ActualModel moel@391: { moel@391: get moel@391: { moel@391: return this.Model; moel@391: } moel@391: } moel@391: moel@391: /// moel@391: /// Gets or sets the keyboard pan horizontal step. moel@391: /// moel@391: /// The keyboard pan horizontal step. moel@391: [Category(OxyPlotCategory)] moel@391: public double KeyboardPanHorizontalStep { get; set; } moel@391: moel@391: /// moel@391: /// Gets or sets the keyboard pan vertical step. moel@391: /// moel@391: /// The keyboard pan vertical step. moel@391: [Category(OxyPlotCategory)] moel@391: public double KeyboardPanVerticalStep { get; set; } moel@391: moel@391: /// moel@391: /// Gets or sets the model. moel@391: /// moel@391: [Browsable(false)] moel@391: [DefaultValue(null)] moel@391: [Category(OxyPlotCategory)] moel@391: public PlotModel Model moel@391: { moel@391: get moel@391: { moel@391: return this.model; moel@391: } moel@391: moel@391: set moel@391: { moel@391: if (this.model != value) moel@391: { moel@391: this.model = value; moel@391: this.OnModelChanged(); moel@391: } moel@391: } moel@391: } moel@391: moel@391: /// moel@391: /// Gets or sets the pan cursor. moel@391: /// moel@391: [Category(OxyPlotCategory)] moel@391: public Cursor PanCursor { get; set; } moel@391: moel@391: /// moel@391: /// Gets or sets the horizontal zoom cursor. moel@391: /// moel@391: [Category(OxyPlotCategory)] moel@391: public Cursor ZoomHorizontalCursor { get; set; } moel@391: moel@391: /// moel@391: /// Gets or sets the rectangle zoom cursor. moel@391: /// moel@391: [Category(OxyPlotCategory)] moel@391: public Cursor ZoomRectangleCursor { get; set; } moel@391: moel@391: /// moel@391: /// Gets or sets vertical zoom cursor. moel@391: /// moel@391: [Category(OxyPlotCategory)] moel@391: public Cursor ZoomVerticalCursor { get; set; } moel@391: moel@391: /// moel@391: /// Get the axes from a point. moel@391: /// moel@391: /// moel@391: /// The point. moel@391: /// moel@391: /// moel@391: /// The x axis. moel@391: /// moel@391: /// moel@391: /// The y axis. moel@391: /// moel@391: public void GetAxesFromPoint(ScreenPoint pt, out Axis xaxis, out Axis yaxis) moel@391: { moel@391: if (this.Model == null) moel@391: { moel@391: xaxis = null; moel@391: yaxis = null; moel@391: return; moel@391: } moel@391: moel@391: this.Model.GetAxesFromPoint(pt, out xaxis, out yaxis); moel@391: } moel@391: moel@391: /// moel@391: /// Get the series from a point. moel@391: /// moel@391: /// moel@391: /// The point (screen coordinates). moel@391: /// moel@391: /// moel@391: /// The limit. moel@391: /// moel@391: /// moel@391: /// The series. moel@391: /// moel@391: public Series GetSeriesFromPoint(ScreenPoint pt, double limit) moel@391: { moel@391: if (this.Model == null) moel@391: { moel@391: return null; moel@391: } moel@391: moel@391: return this.Model.GetSeriesFromPoint(pt, limit); moel@391: } moel@391: moel@391: /// moel@391: /// The hide tracker. moel@391: /// moel@391: public void HideTracker() moel@391: { moel@391: } moel@391: moel@391: /// moel@391: /// The hide zoom rectangle. moel@391: /// moel@391: public void HideZoomRectangle() moel@391: { moel@391: this.zoomRectangle = Rectangle.Empty; moel@391: this.Invalidate(); moel@391: } moel@391: moel@391: /// moel@391: /// The invalidate plot. moel@391: /// moel@391: /// moel@391: /// The update data. moel@391: /// moel@391: public void InvalidatePlot(bool updateData) moel@391: { moel@391: lock (this.invalidateLock) moel@391: { moel@391: this.isModelInvalidated = true; moel@391: this.updateDataFlag = this.updateDataFlag || updateData; moel@391: } moel@391: moel@391: this.Invalidate(); moel@391: } moel@391: moel@391: /// moel@391: /// Called when the Model property has been changed. moel@391: /// moel@391: public void OnModelChanged() moel@391: { moel@391: lock (this.modelLock) moel@391: { moel@391: if (this.currentModel != null) moel@391: { moel@391: this.currentModel.AttachPlotControl(null); moel@391: } moel@391: moel@391: if (this.Model != null) moel@391: { moel@391: if (this.Model.PlotControl != null) moel@391: { moel@391: throw new InvalidOperationException( moel@391: "This PlotModel is already in use by some other plot control."); moel@391: } moel@391: moel@391: this.Model.AttachPlotControl(this); moel@391: this.currentModel = this.Model; moel@391: } moel@391: } moel@391: moel@391: this.InvalidatePlot(true); moel@391: } moel@391: moel@391: /// moel@391: /// The pan. moel@391: /// moel@391: /// moel@391: /// The axis. moel@391: /// moel@391: /// moel@391: /// The x 0. moel@391: /// moel@391: /// moel@391: /// The x 1. moel@391: /// moel@391: public void Pan(Axis axis, ScreenPoint x0, ScreenPoint x1) moel@391: { moel@391: axis.Pan(x0, x1); moel@391: this.InvalidatePlot(false); moel@391: } moel@391: moel@391: /// moel@391: /// Pans all axes. moel@391: /// moel@391: /// moel@391: /// The horizontal delta. moel@391: /// moel@391: /// moel@391: /// The vertical delta. moel@391: /// moel@391: public void PanAll(double deltax, double deltay) moel@391: { moel@391: foreach (var a in this.ActualModel.Axes) moel@391: { moel@391: a.Pan(a.IsHorizontal() ? deltax : deltay); moel@391: } moel@391: moel@391: this.InvalidatePlot(false); moel@391: } moel@391: moel@391: /// moel@391: /// The refresh plot. moel@391: /// moel@391: /// moel@391: /// The update data. moel@391: /// moel@391: public void RefreshPlot(bool updateData) moel@391: { moel@391: lock (this.invalidateLock) moel@391: { moel@391: this.isModelInvalidated = true; moel@391: this.updateDataFlag = this.updateDataFlag || updateData; moel@391: } moel@391: moel@391: this.Refresh(); moel@391: } moel@391: moel@391: /// moel@391: /// The reset. moel@391: /// moel@391: /// moel@391: /// The axis. moel@391: /// moel@391: public void Reset(Axis axis) moel@391: { moel@391: axis.Reset(); moel@391: this.InvalidatePlot(false); moel@391: } moel@391: moel@391: /// moel@391: /// Sets the cursor type. moel@391: /// moel@391: /// moel@391: /// The cursor type. moel@391: /// moel@391: public void SetCursorType(CursorType cursorType) moel@391: { moel@391: switch (cursorType) moel@391: { moel@391: case CursorType.Pan: moel@391: this.Cursor = this.PanCursor; moel@391: break; moel@391: case CursorType.ZoomRectangle: moel@391: this.Cursor = this.ZoomRectangleCursor; moel@391: break; moel@391: case CursorType.ZoomHorizontal: moel@391: this.Cursor = this.ZoomHorizontalCursor; moel@391: break; moel@391: case CursorType.ZoomVertical: moel@391: this.Cursor = this.ZoomVerticalCursor; moel@391: break; moel@391: default: moel@391: this.Cursor = Cursors.Arrow; moel@391: break; moel@391: } moel@391: } moel@391: moel@391: /// moel@391: /// The show tracker. moel@391: /// moel@391: /// moel@391: /// The data. moel@391: /// moel@391: public void ShowTracker(TrackerHitResult data) moel@391: { moel@391: // not implemented for WindowsForms moel@391: } moel@391: moel@391: /// moel@391: /// The show zoom rectangle. moel@391: /// moel@391: /// moel@391: /// The r. moel@391: /// moel@391: public void ShowZoomRectangle(OxyRect r) moel@391: { moel@391: this.zoomRectangle = new Rectangle((int)r.Left, (int)r.Top, (int)r.Width, (int)r.Height); moel@391: this.Invalidate(); moel@391: } moel@391: moel@391: /// moel@391: /// The zoom. moel@391: /// moel@391: /// moel@391: /// The axis. moel@391: /// moel@391: /// moel@391: /// The p 1. moel@391: /// moel@391: /// moel@391: /// The p 2. moel@391: /// moel@391: public void Zoom(Axis axis, double p1, double p2) moel@391: { moel@391: axis.Zoom(p1, p2); moel@391: this.InvalidatePlot(false); moel@391: } moel@391: moel@391: /// moel@391: /// The zoom all. moel@391: /// moel@391: public void ZoomAll() moel@391: { moel@391: foreach (var a in this.Model.Axes) moel@391: { moel@391: a.Reset(); moel@391: } moel@391: moel@391: this.InvalidatePlot(false); moel@391: } moel@391: moel@391: /// moel@391: /// Zooms all axes. moel@391: /// moel@391: /// moel@391: /// The delta. moel@391: /// moel@391: public void ZoomAllAxes(double delta) moel@391: { moel@391: foreach (var a in this.ActualModel.Axes) moel@391: { moel@391: this.ZoomAt(a, delta); moel@391: } moel@391: moel@391: this.RefreshPlot(false); moel@391: } moel@391: moel@391: /// moel@391: /// The zoom at. moel@391: /// moel@391: /// moel@391: /// The axis. moel@391: /// moel@391: /// moel@391: /// The factor. moel@391: /// moel@391: /// moel@391: /// The x. moel@391: /// moel@391: public void ZoomAt(Axis axis, double factor, double x = double.NaN) moel@391: { moel@391: if (double.IsNaN(x)) moel@391: { moel@391: double sx = (axis.Transform(axis.ActualMaximum) + axis.Transform(axis.ActualMinimum)) * 0.5; moel@391: x = axis.InverseTransform(sx); moel@391: } moel@391: moel@391: axis.ZoomAt(factor, x); moel@391: this.InvalidatePlot(false); moel@391: } moel@391: moel@391: /// moel@391: /// The on mouse down. moel@391: /// moel@391: /// moel@391: /// The e. moel@391: /// moel@391: protected override void OnMouseDown(MouseEventArgs e) moel@391: { moel@391: base.OnMouseDown(e); moel@391: moel@391: if (this.mouseManipulator != null) moel@391: { moel@391: return; moel@391: } moel@391: moel@391: this.Focus(); moel@391: this.Capture = true; moel@391: moel@391: if (this.ActualModel != null) moel@391: { moel@391: var args = this.CreateMouseEventArgs(e); moel@391: this.ActualModel.HandleMouseDown(this, args); moel@391: if (args.Handled) moel@391: { moel@391: return; moel@391: } moel@391: } moel@391: moel@391: this.mouseManipulator = this.GetManipulator(e); moel@391: moel@391: if (this.mouseManipulator != null) moel@391: { moel@391: this.mouseManipulator.Started(this.CreateManipulationEventArgs(e)); moel@391: } moel@391: } moel@391: moel@391: /// moel@391: /// The on mouse move. moel@391: /// moel@391: /// moel@391: /// The e. moel@391: /// moel@391: protected override void OnMouseMove(MouseEventArgs e) moel@391: { moel@391: base.OnMouseMove(e); moel@391: moel@391: if (this.ActualModel != null) moel@391: { moel@391: var args = this.CreateMouseEventArgs(e); moel@391: this.ActualModel.HandleMouseMove(this, args); moel@391: if (args.Handled) moel@391: { moel@391: return; moel@391: } moel@391: } moel@391: moel@391: if (this.mouseManipulator != null) moel@391: { moel@391: this.mouseManipulator.Delta(this.CreateManipulationEventArgs(e)); moel@391: } moel@391: } moel@391: moel@391: /// moel@391: /// Raises the event. moel@391: /// moel@391: /// moel@391: /// A that contains the event data. moel@391: /// moel@391: protected override void OnMouseUp(MouseEventArgs e) moel@391: { moel@391: base.OnMouseUp(e); moel@391: this.Capture = false; moel@391: moel@391: if (this.ActualModel != null) moel@391: { moel@391: var args = this.CreateMouseEventArgs(e); moel@391: this.ActualModel.HandleMouseUp(this, args); moel@391: if (args.Handled) moel@391: { moel@391: return; moel@391: } moel@391: } moel@391: moel@391: if (this.mouseManipulator != null) moel@391: { moel@391: this.mouseManipulator.Completed(this.CreateManipulationEventArgs(e)); moel@391: } moel@391: moel@391: this.mouseManipulator = null; moel@391: } moel@391: moel@391: /// moel@391: /// Raises the event. moel@391: /// moel@391: /// moel@391: /// A that contains the event data. moel@391: /// moel@391: protected override void OnMouseWheel(MouseEventArgs e) moel@391: { moel@391: base.OnMouseWheel(e); moel@391: bool isControlDown = ModifierKeys == Keys.Control; moel@391: var m = new ZoomStepManipulator(this, e.Delta * 0.001, isControlDown); moel@391: m.Started(new ManipulationEventArgs(e.Location.ToScreenPoint())); moel@391: } moel@391: moel@391: /// moel@391: /// Raises the event. moel@391: /// moel@391: /// moel@391: /// A that contains the event data. moel@391: /// moel@391: protected override void OnPaint(PaintEventArgs e) moel@391: { moel@391: base.OnPaint(e); moel@391: try moel@391: { moel@391: lock (this.invalidateLock) moel@391: { moel@391: if (this.isModelInvalidated) moel@391: { moel@391: if (this.model != null) moel@391: { moel@391: this.model.Update(this.updateDataFlag); moel@391: this.updateDataFlag = false; moel@391: } moel@391: moel@391: this.isModelInvalidated = false; moel@391: } moel@391: } moel@391: moel@391: lock (this.renderingLock) moel@391: { moel@391: this.renderContext.SetGraphicsTarget(e.Graphics); moel@391: if (this.model != null) moel@391: { moel@391: this.model.Render(this.renderContext, this.Width, this.Height); moel@391: } moel@391: moel@391: if (this.zoomRectangle != Rectangle.Empty) moel@391: { moel@391: using (var zoomBrush = new SolidBrush(Color.FromArgb(0x40, 0xFF, 0xFF, 0x00))) moel@391: using (var zoomPen = new Pen(Color.Black)) moel@391: { moel@391: zoomPen.DashPattern = new float[] { 3, 1 }; moel@391: e.Graphics.FillRectangle(zoomBrush, this.zoomRectangle); moel@391: e.Graphics.DrawRectangle(zoomPen, this.zoomRectangle); moel@391: } moel@391: } moel@391: } moel@391: } moel@391: catch (Exception paintException) moel@391: { moel@391: var trace = new StackTrace(paintException); moel@391: Debug.WriteLine(paintException); moel@391: Debug.WriteLine(trace); moel@391: using (var font = new Font("Arial", 10)) moel@391: { moel@391: e.Graphics.DrawString( moel@391: "OxyPlot paint exception: " + paintException.Message, font, Brushes.Red, 10, 10); moel@391: } moel@391: } moel@391: } moel@391: moel@391: /// moel@391: /// Raises the event. moel@391: /// moel@391: /// moel@391: /// A that contains the event data. moel@391: /// moel@391: protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e) moel@391: { moel@391: base.OnPreviewKeyDown(e); moel@391: if (e.KeyCode == Keys.A) moel@391: { moel@391: this.ZoomAll(); moel@391: } moel@391: moel@391: bool control = (e.Modifiers & Keys.Control) == Keys.Control; moel@391: bool alt = (e.Modifiers & Keys.Alt) == Keys.Alt; moel@391: moel@391: double deltax = 0; moel@391: double deltay = 0; moel@391: double zoom = 0; moel@391: switch (e.KeyCode) moel@391: { moel@391: case Keys.Up: moel@391: deltay = -1; moel@391: break; moel@391: case Keys.Down: moel@391: deltay = 1; moel@391: break; moel@391: case Keys.Left: moel@391: deltax = -1; moel@391: break; moel@391: case Keys.Right: moel@391: deltax = 1; moel@391: break; moel@391: case Keys.Add: moel@391: case Keys.Oemplus: moel@391: case Keys.PageUp: moel@391: zoom = 1; moel@391: break; moel@391: case Keys.Subtract: moel@391: case Keys.OemMinus: moel@391: case Keys.PageDown: moel@391: zoom = -1; moel@391: break; moel@391: } moel@391: moel@391: if ((deltax * deltax) + (deltay * deltay) > 0) moel@391: { moel@391: deltax = deltax * this.ActualModel.PlotArea.Width * this.KeyboardPanHorizontalStep; moel@391: deltay = deltay * this.ActualModel.PlotArea.Height * this.KeyboardPanVerticalStep; moel@391: moel@391: // small steps if the user is pressing control moel@391: if (control) moel@391: { moel@391: deltax *= 0.2; moel@391: deltay *= 0.2; moel@391: } moel@391: moel@391: this.PanAll(deltax, deltay); moel@391: moel@391: // e.Handled = true; moel@391: } moel@391: moel@391: if (Math.Abs(zoom) > 1e-8) moel@391: { moel@391: if (control) moel@391: { moel@391: zoom *= 0.2; moel@391: } moel@391: moel@391: this.ZoomAllAxes(1 + (zoom * 0.12)); moel@391: moel@391: // e.Handled = true; moel@391: } moel@391: moel@391: if (control && alt && this.ActualModel != null) moel@391: { moel@391: switch (e.KeyCode) moel@391: { moel@391: case Keys.R: moel@391: this.SetClipboardText(this.ActualModel.CreateTextReport()); moel@391: break; moel@391: case Keys.C: moel@391: this.SetClipboardText(this.ActualModel.ToCode()); moel@391: break; moel@391: case Keys.X: moel@391: moel@391: // this.SetClipboardText(this.ActualModel.ToXml()); moel@391: break; moel@391: } moel@391: } moel@391: } moel@391: moel@391: /// moel@391: /// Raises the event. moel@391: /// moel@391: /// moel@391: /// An that contains the event data. moel@391: /// moel@391: protected override void OnResize(EventArgs e) moel@391: { moel@391: base.OnResize(e); moel@391: this.InvalidatePlot(false); moel@391: } moel@391: moel@391: /// moel@391: /// Converts the changed button. moel@391: /// moel@391: /// moel@391: /// The instance containing the event data. moel@391: /// moel@391: /// moel@391: /// The mouse button. moel@391: /// moel@391: private static OxyMouseButton ConvertChangedButton(MouseEventArgs e) moel@391: { moel@391: switch (e.Button) moel@391: { moel@391: case MouseButtons.Left: moel@391: return OxyMouseButton.Left; moel@391: case MouseButtons.Middle: moel@391: return OxyMouseButton.Middle; moel@391: case MouseButtons.Right: moel@391: return OxyMouseButton.Right; moel@391: case MouseButtons.XButton1: moel@391: return OxyMouseButton.XButton1; moel@391: case MouseButtons.XButton2: moel@391: return OxyMouseButton.XButton2; moel@391: } moel@391: moel@391: return OxyMouseButton.Left; moel@391: } moel@391: moel@391: /// moel@391: /// Creates the mouse event arguments. moel@391: /// moel@391: /// moel@391: /// The instance containing the event data. moel@391: /// moel@391: /// moel@391: /// Mouse event arguments. moel@391: /// moel@391: private OxyMouseEventArgs CreateMouseEventArgs(MouseEventArgs e) moel@391: { moel@391: return new OxyMouseEventArgs moel@391: { moel@391: ChangedButton = ConvertChangedButton(e), moel@391: Position = new ScreenPoint(e.Location.X, e.Location.Y), moel@391: IsShiftDown = (ModifierKeys & Keys.Shift) == Keys.Shift, moel@391: IsControlDown = (ModifierKeys & Keys.Control) == Keys.Control, moel@391: IsAltDown = (ModifierKeys & Keys.Alt) == Keys.Alt, moel@391: }; moel@391: } moel@391: moel@391: /// moel@391: /// Creates the manipulation event args. moel@391: /// moel@391: /// moel@391: /// The MouseEventArgs instance containing the event data. moel@391: /// moel@391: /// moel@391: /// A manipulation event args object. moel@391: /// moel@391: private ManipulationEventArgs CreateManipulationEventArgs(MouseEventArgs e) moel@391: { moel@391: return new ManipulationEventArgs(e.Location.ToScreenPoint()); moel@391: } moel@391: moel@391: /// moel@391: /// Gets the manipulator for the current mouse button and modifier keys. moel@391: /// moel@391: /// moel@391: /// The event args. moel@391: /// moel@391: /// moel@391: /// A manipulator or null if no gesture was recognized. moel@391: /// moel@391: private ManipulatorBase GetManipulator(MouseEventArgs e) moel@391: { moel@391: bool control = (ModifierKeys & Keys.Control) == Keys.Control; moel@391: bool shift = (ModifierKeys & Keys.Shift) == Keys.Shift; moel@391: bool alt = (ModifierKeys & Keys.Alt) == Keys.Alt; moel@391: moel@391: bool lmb = e.Button == MouseButtons.Left; moel@391: bool rmb = e.Button == MouseButtons.Right; moel@391: bool mmb = e.Button == MouseButtons.Middle; moel@391: bool xb1 = e.Button == MouseButtons.XButton1; moel@391: bool xb2 = e.Button == MouseButtons.XButton2; moel@391: moel@391: // MMB / control RMB / control+alt LMB moel@393: if (mmb || (control && lmb) || (control && alt && rmb)) moel@393: { moel@393: return new ZoomRectangleManipulator(this); moel@393: } moel@393: moel@393: // Right mouse button / alt+left mouse button moel@393: if (lmb || (rmb && alt)) moel@391: { moel@391: if (e.Clicks == 2) moel@391: { moel@391: return new ResetManipulator(this); moel@391: } moel@391: return new PanManipulator(this); moel@391: } moel@391: moel@391: // Left mouse button moel@393: if (rmb) moel@391: { moel@391: return new TrackerManipulator(this) { Snap = !control, PointsOnly = shift }; moel@391: } moel@391: moel@391: // XButtons are zoom-stepping moel@391: if (xb1 || xb2) moel@391: { moel@391: double d = xb1 ? 0.05 : -0.05; moel@391: return new ZoomStepManipulator(this, d, control); moel@391: } moel@391: moel@391: return null; moel@391: } moel@391: moel@391: /// moel@391: /// The set clipboard text. moel@391: /// moel@391: /// moel@391: /// The text. moel@391: /// moel@391: private void SetClipboardText(string text) moel@391: { moel@391: try moel@391: { moel@391: // todo: can't get the following solution to work moel@391: // http://stackoverflow.com/questions/5707990/requested-clipboard-operation-did-not-succeed moel@391: Clipboard.SetText(text); moel@391: } moel@391: catch (ExternalException ee) moel@391: { moel@391: // Requested Clipboard operation did not succeed. moel@391: MessageBox.Show(this, ee.Message, "OxyPlot"); moel@391: } moel@391: } moel@391: } moel@391: }