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: }