External/OxyPlot/OxyPlot.WindowsForms/Plot.cs
author StephaneLenclud
Sun, 03 Feb 2013 18:01:50 +0100
branchMiniDisplay
changeset 433 090259cfd699
parent 391 5be8f2773237
permissions -rw-r--r--
Adding SoundGraphDisplay and SensorFrontView classes.
They were respectively based on SystemTray and SensorNotifyIcon.
SoundGraphDisplay is now able to load iMONDisplay.dll providing it lives on your PATH.
Adding option to sensor context menu for adding it into FrontView.
moel@391
     1
// --------------------------------------------------------------------------------------------------------------------
moel@391
     2
// <copyright file="Plot.cs" company="OxyPlot">
moel@391
     3
//   The MIT License (MIT)
moel@391
     4
//
moel@391
     5
//   Copyright (c) 2012 Oystein Bjorke
moel@391
     6
//
moel@391
     7
//   Permission is hereby granted, free of charge, to any person obtaining a
moel@391
     8
//   copy of this software and associated documentation files (the
moel@391
     9
//   "Software"), to deal in the Software without restriction, including
moel@391
    10
//   without limitation the rights to use, copy, modify, merge, publish,
moel@391
    11
//   distribute, sublicense, and/or sell copies of the Software, and to
moel@391
    12
//   permit persons to whom the Software is furnished to do so, subject to
moel@391
    13
//   the following conditions:
moel@391
    14
//
moel@391
    15
//   The above copyright notice and this permission notice shall be included
moel@391
    16
//   in all copies or substantial portions of the Software.
moel@391
    17
//
moel@391
    18
//   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
moel@391
    19
//   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
moel@391
    20
//   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
moel@391
    21
//   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
moel@391
    22
//   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
moel@391
    23
//   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
moel@391
    24
//   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
moel@391
    25
// </copyright>
moel@391
    26
// <summary>
moel@391
    27
//   Represents a control that displays a plot.
moel@391
    28
// </summary>
moel@391
    29
// --------------------------------------------------------------------------------------------------------------------
moel@391
    30
namespace OxyPlot.WindowsForms
moel@391
    31
{
moel@391
    32
    using System;
moel@391
    33
    using System.ComponentModel;
moel@391
    34
    using System.Diagnostics;
moel@391
    35
    using System.Drawing;
moel@391
    36
    using System.Runtime.InteropServices;
moel@391
    37
    using System.Windows.Forms;
moel@391
    38
moel@391
    39
    using OxyPlot.Axes;
moel@391
    40
    using OxyPlot.Series;
moel@391
    41
moel@391
    42
    /// <summary>
moel@391
    43
    /// Represents a control that displays a plot.
moel@391
    44
    /// </summary>
moel@391
    45
    [Serializable]
moel@391
    46
    public class Plot : Control, IPlotControl
moel@391
    47
    {
moel@391
    48
        /// <summary>
moel@391
    49
        /// The category for the properties of this control.
moel@391
    50
        /// </summary>
moel@391
    51
        private const string OxyPlotCategory = "OxyPlot";
moel@391
    52
moel@391
    53
        /// <summary>
moel@391
    54
        /// The invalidate lock.
moel@391
    55
        /// </summary>
moel@391
    56
        private readonly object invalidateLock = new object();
moel@391
    57
moel@391
    58
        /// <summary>
moel@391
    59
        /// The model lock.
moel@391
    60
        /// </summary>
moel@391
    61
        private readonly object modelLock = new object();
moel@391
    62
moel@391
    63
        /// <summary>
moel@391
    64
        /// The rendering lock.
moel@391
    65
        /// </summary>
moel@391
    66
        private readonly object renderingLock = new object();
moel@391
    67
moel@391
    68
        /// <summary>
moel@391
    69
        /// The current model (holding a reference to this plot control).
moel@391
    70
        /// </summary>
moel@391
    71
        [NonSerialized]
moel@391
    72
        private PlotModel currentModel;
moel@391
    73
moel@391
    74
        /// <summary>
moel@391
    75
        /// The is model invalidated.
moel@391
    76
        /// </summary>
moel@391
    77
        private bool isModelInvalidated;
moel@391
    78
moel@391
    79
        /// <summary>
moel@391
    80
        /// The model.
moel@391
    81
        /// </summary>
moel@391
    82
        private PlotModel model;
moel@391
    83
moel@391
    84
        /// <summary>
moel@391
    85
        /// The mouse manipulator.
moel@391
    86
        /// </summary>
moel@391
    87
        [NonSerialized]
moel@391
    88
        private ManipulatorBase mouseManipulator;
moel@391
    89
moel@391
    90
        /// <summary>
moel@391
    91
        /// The update data flag.
moel@391
    92
        /// </summary>
moel@391
    93
        private bool updateDataFlag = true;
moel@391
    94
moel@391
    95
        /// <summary>
moel@391
    96
        /// The zoom rectangle.
moel@391
    97
        /// </summary>
moel@391
    98
        private Rectangle zoomRectangle;
moel@391
    99
moel@391
   100
        /// <summary>
moel@391
   101
        /// The render context.
moel@391
   102
        /// </summary>
moel@391
   103
        private GraphicsRenderContext renderContext;
moel@391
   104
moel@391
   105
        /// <summary>
moel@391
   106
        /// Initializes a new instance of the <see cref="Plot"/> class.
moel@391
   107
        /// </summary>
moel@391
   108
        public Plot()
moel@391
   109
        {
moel@391
   110
            this.renderContext = new GraphicsRenderContext();
moel@391
   111
moel@391
   112
            // ReSharper disable DoNotCallOverridableMethodsInConstructor
moel@391
   113
            this.DoubleBuffered = true;
moel@391
   114
            // ReSharper restore DoNotCallOverridableMethodsInConstructor
moel@391
   115
            this.KeyboardPanHorizontalStep = 0.1;
moel@391
   116
            this.KeyboardPanVerticalStep = 0.1;
moel@391
   117
            this.PanCursor = Cursors.Hand;
moel@391
   118
            this.ZoomRectangleCursor = Cursors.SizeNWSE;
moel@391
   119
            this.ZoomHorizontalCursor = Cursors.SizeWE;
moel@391
   120
            this.ZoomVerticalCursor = Cursors.SizeNS;
moel@391
   121
        }
moel@391
   122
moel@391
   123
        /// <summary>
moel@391
   124
        /// Gets the actual model.
moel@391
   125
        /// </summary>
moel@391
   126
        /// <value> The actual model. </value>
moel@391
   127
        public PlotModel ActualModel
moel@391
   128
        {
moel@391
   129
            get
moel@391
   130
            {
moel@391
   131
                return this.Model;
moel@391
   132
            }
moel@391
   133
        }
moel@391
   134
moel@391
   135
        /// <summary>
moel@391
   136
        /// Gets or sets the keyboard pan horizontal step.
moel@391
   137
        /// </summary>
moel@391
   138
        /// <value> The keyboard pan horizontal step. </value>
moel@391
   139
        [Category(OxyPlotCategory)]
moel@391
   140
        public double KeyboardPanHorizontalStep { get; set; }
moel@391
   141
moel@391
   142
        /// <summary>
moel@391
   143
        /// Gets or sets the keyboard pan vertical step.
moel@391
   144
        /// </summary>
moel@391
   145
        /// <value> The keyboard pan vertical step. </value>
moel@391
   146
        [Category(OxyPlotCategory)]
moel@391
   147
        public double KeyboardPanVerticalStep { get; set; }
moel@391
   148
moel@391
   149
        /// <summary>
moel@391
   150
        /// Gets or sets the model.
moel@391
   151
        /// </summary>
moel@391
   152
        [Browsable(false)]
moel@391
   153
        [DefaultValue(null)]
moel@391
   154
        [Category(OxyPlotCategory)]
moel@391
   155
        public PlotModel Model
moel@391
   156
        {
moel@391
   157
            get
moel@391
   158
            {
moel@391
   159
                return this.model;
moel@391
   160
            }
moel@391
   161
moel@391
   162
            set
moel@391
   163
            {
moel@391
   164
                if (this.model != value)
moel@391
   165
                {
moel@391
   166
                    this.model = value;
moel@391
   167
                    this.OnModelChanged();
moel@391
   168
                }
moel@391
   169
            }
moel@391
   170
        }
moel@391
   171
moel@391
   172
        /// <summary>
moel@391
   173
        /// Gets or sets the pan cursor.
moel@391
   174
        /// </summary>
moel@391
   175
        [Category(OxyPlotCategory)]
moel@391
   176
        public Cursor PanCursor { get; set; }
moel@391
   177
moel@391
   178
        /// <summary>
moel@391
   179
        /// Gets or sets the horizontal zoom cursor.
moel@391
   180
        /// </summary>
moel@391
   181
        [Category(OxyPlotCategory)]
moel@391
   182
        public Cursor ZoomHorizontalCursor { get; set; }
moel@391
   183
moel@391
   184
        /// <summary>
moel@391
   185
        /// Gets or sets the rectangle zoom cursor.
moel@391
   186
        /// </summary>
moel@391
   187
        [Category(OxyPlotCategory)]
moel@391
   188
        public Cursor ZoomRectangleCursor { get; set; }
moel@391
   189
moel@391
   190
        /// <summary>
moel@391
   191
        /// Gets or sets vertical zoom cursor.
moel@391
   192
        /// </summary>
moel@391
   193
        [Category(OxyPlotCategory)]
moel@391
   194
        public Cursor ZoomVerticalCursor { get; set; }
moel@391
   195
moel@391
   196
        /// <summary>
moel@391
   197
        /// Get the axes from a point.
moel@391
   198
        /// </summary>
moel@391
   199
        /// <param name="pt">
moel@391
   200
        /// The point.
moel@391
   201
        /// </param>
moel@391
   202
        /// <param name="xaxis">
moel@391
   203
        /// The x axis.
moel@391
   204
        /// </param>
moel@391
   205
        /// <param name="yaxis">
moel@391
   206
        /// The y axis.
moel@391
   207
        /// </param>
moel@391
   208
        public void GetAxesFromPoint(ScreenPoint pt, out Axis xaxis, out Axis yaxis)
moel@391
   209
        {
moel@391
   210
            if (this.Model == null)
moel@391
   211
            {
moel@391
   212
                xaxis = null;
moel@391
   213
                yaxis = null;
moel@391
   214
                return;
moel@391
   215
            }
moel@391
   216
moel@391
   217
            this.Model.GetAxesFromPoint(pt, out xaxis, out yaxis);
moel@391
   218
        }
moel@391
   219
moel@391
   220
        /// <summary>
moel@391
   221
        /// Get the series from a point.
moel@391
   222
        /// </summary>
moel@391
   223
        /// <param name="pt">
moel@391
   224
        /// The point (screen coordinates).
moel@391
   225
        /// </param>
moel@391
   226
        /// <param name="limit">
moel@391
   227
        /// The limit.
moel@391
   228
        /// </param>
moel@391
   229
        /// <returns>
moel@391
   230
        /// The series.
moel@391
   231
        /// </returns>
moel@391
   232
        public Series GetSeriesFromPoint(ScreenPoint pt, double limit)
moel@391
   233
        {
moel@391
   234
            if (this.Model == null)
moel@391
   235
            {
moel@391
   236
                return null;
moel@391
   237
            }
moel@391
   238
moel@391
   239
            return this.Model.GetSeriesFromPoint(pt, limit);
moel@391
   240
        }
moel@391
   241
moel@391
   242
        /// <summary>
moel@391
   243
        /// The hide tracker.
moel@391
   244
        /// </summary>
moel@391
   245
        public void HideTracker()
moel@391
   246
        {
moel@391
   247
        }
moel@391
   248
moel@391
   249
        /// <summary>
moel@391
   250
        /// The hide zoom rectangle.
moel@391
   251
        /// </summary>
moel@391
   252
        public void HideZoomRectangle()
moel@391
   253
        {
moel@391
   254
            this.zoomRectangle = Rectangle.Empty;
moel@391
   255
            this.Invalidate();
moel@391
   256
        }
moel@391
   257
moel@391
   258
        /// <summary>
moel@391
   259
        /// The invalidate plot.
moel@391
   260
        /// </summary>
moel@391
   261
        /// <param name="updateData">
moel@391
   262
        /// The update data.
moel@391
   263
        /// </param>
moel@391
   264
        public void InvalidatePlot(bool updateData)
moel@391
   265
        {
moel@391
   266
            lock (this.invalidateLock)
moel@391
   267
            {
moel@391
   268
                this.isModelInvalidated = true;
moel@391
   269
                this.updateDataFlag = this.updateDataFlag || updateData;
moel@391
   270
            }
moel@391
   271
moel@391
   272
            this.Invalidate();
moel@391
   273
        }
moel@391
   274
moel@391
   275
        /// <summary>
moel@391
   276
        /// Called when the Model property has been changed.
moel@391
   277
        /// </summary>
moel@391
   278
        public void OnModelChanged()
moel@391
   279
        {
moel@391
   280
            lock (this.modelLock)
moel@391
   281
            {
moel@391
   282
                if (this.currentModel != null)
moel@391
   283
                {
moel@391
   284
                    this.currentModel.AttachPlotControl(null);
moel@391
   285
                }
moel@391
   286
moel@391
   287
                if (this.Model != null)
moel@391
   288
                {
moel@391
   289
                    if (this.Model.PlotControl != null)
moel@391
   290
                    {
moel@391
   291
                        throw new InvalidOperationException(
moel@391
   292
                            "This PlotModel is already in use by some other plot control.");
moel@391
   293
                    }
moel@391
   294
moel@391
   295
                    this.Model.AttachPlotControl(this);
moel@391
   296
                    this.currentModel = this.Model;
moel@391
   297
                }
moel@391
   298
            }
moel@391
   299
moel@391
   300
            this.InvalidatePlot(true);
moel@391
   301
        }
moel@391
   302
moel@391
   303
        /// <summary>
moel@391
   304
        /// The pan.
moel@391
   305
        /// </summary>
moel@391
   306
        /// <param name="axis">
moel@391
   307
        /// The axis.
moel@391
   308
        /// </param>
moel@391
   309
        /// <param name="x0">
moel@391
   310
        /// The x 0.
moel@391
   311
        /// </param>
moel@391
   312
        /// <param name="x1">
moel@391
   313
        /// The x 1.
moel@391
   314
        /// </param>
moel@391
   315
        public void Pan(Axis axis, ScreenPoint x0, ScreenPoint x1)
moel@391
   316
        {
moel@391
   317
            axis.Pan(x0, x1);
moel@391
   318
            this.InvalidatePlot(false);
moel@391
   319
        }
moel@391
   320
moel@391
   321
        /// <summary>
moel@391
   322
        /// Pans all axes.
moel@391
   323
        /// </summary>
moel@391
   324
        /// <param name="deltax">
moel@391
   325
        /// The horizontal delta.
moel@391
   326
        /// </param>
moel@391
   327
        /// <param name="deltay">
moel@391
   328
        /// The vertical delta.
moel@391
   329
        /// </param>
moel@391
   330
        public void PanAll(double deltax, double deltay)
moel@391
   331
        {
moel@391
   332
            foreach (var a in this.ActualModel.Axes)
moel@391
   333
            {
moel@391
   334
                a.Pan(a.IsHorizontal() ? deltax : deltay);
moel@391
   335
            }
moel@391
   336
moel@391
   337
            this.InvalidatePlot(false);
moel@391
   338
        }
moel@391
   339
moel@391
   340
        /// <summary>
moel@391
   341
        /// The refresh plot.
moel@391
   342
        /// </summary>
moel@391
   343
        /// <param name="updateData">
moel@391
   344
        /// The update data.
moel@391
   345
        /// </param>
moel@391
   346
        public void RefreshPlot(bool updateData)
moel@391
   347
        {
moel@391
   348
            lock (this.invalidateLock)
moel@391
   349
            {
moel@391
   350
                this.isModelInvalidated = true;
moel@391
   351
                this.updateDataFlag = this.updateDataFlag || updateData;
moel@391
   352
            }
moel@391
   353
moel@391
   354
            this.Refresh();
moel@391
   355
        }
moel@391
   356
moel@391
   357
        /// <summary>
moel@391
   358
        /// The reset.
moel@391
   359
        /// </summary>
moel@391
   360
        /// <param name="axis">
moel@391
   361
        /// The axis.
moel@391
   362
        /// </param>
moel@391
   363
        public void Reset(Axis axis)
moel@391
   364
        {
moel@391
   365
            axis.Reset();
moel@391
   366
            this.InvalidatePlot(false);
moel@391
   367
        }
moel@391
   368
moel@391
   369
        /// <summary>
moel@391
   370
        /// Sets the cursor type.
moel@391
   371
        /// </summary>
moel@391
   372
        /// <param name="cursorType">
moel@391
   373
        /// The cursor type.
moel@391
   374
        /// </param>
moel@391
   375
        public void SetCursorType(CursorType cursorType)
moel@391
   376
        {
moel@391
   377
            switch (cursorType)
moel@391
   378
            {
moel@391
   379
                case CursorType.Pan:
moel@391
   380
                    this.Cursor = this.PanCursor;
moel@391
   381
                    break;
moel@391
   382
                case CursorType.ZoomRectangle:
moel@391
   383
                    this.Cursor = this.ZoomRectangleCursor;
moel@391
   384
                    break;
moel@391
   385
                case CursorType.ZoomHorizontal:
moel@391
   386
                    this.Cursor = this.ZoomHorizontalCursor;
moel@391
   387
                    break;
moel@391
   388
                case CursorType.ZoomVertical:
moel@391
   389
                    this.Cursor = this.ZoomVerticalCursor;
moel@391
   390
                    break;
moel@391
   391
                default:
moel@391
   392
                    this.Cursor = Cursors.Arrow;
moel@391
   393
                    break;
moel@391
   394
            }
moel@391
   395
        }
moel@391
   396
moel@391
   397
        /// <summary>
moel@391
   398
        /// The show tracker.
moel@391
   399
        /// </summary>
moel@391
   400
        /// <param name="data">
moel@391
   401
        /// The data.
moel@391
   402
        /// </param>
moel@391
   403
        public void ShowTracker(TrackerHitResult data)
moel@391
   404
        {
moel@391
   405
            // not implemented for WindowsForms
moel@391
   406
        }
moel@391
   407
moel@391
   408
        /// <summary>
moel@391
   409
        /// The show zoom rectangle.
moel@391
   410
        /// </summary>
moel@391
   411
        /// <param name="r">
moel@391
   412
        /// The r.
moel@391
   413
        /// </param>
moel@391
   414
        public void ShowZoomRectangle(OxyRect r)
moel@391
   415
        {
moel@391
   416
            this.zoomRectangle = new Rectangle((int)r.Left, (int)r.Top, (int)r.Width, (int)r.Height);
moel@391
   417
            this.Invalidate();
moel@391
   418
        }
moel@391
   419
moel@391
   420
        /// <summary>
moel@391
   421
        /// The zoom.
moel@391
   422
        /// </summary>
moel@391
   423
        /// <param name="axis">
moel@391
   424
        /// The axis.
moel@391
   425
        /// </param>
moel@391
   426
        /// <param name="p1">
moel@391
   427
        /// The p 1.
moel@391
   428
        /// </param>
moel@391
   429
        /// <param name="p2">
moel@391
   430
        /// The p 2.
moel@391
   431
        /// </param>
moel@391
   432
        public void Zoom(Axis axis, double p1, double p2)
moel@391
   433
        {
moel@391
   434
            axis.Zoom(p1, p2);
moel@391
   435
            this.InvalidatePlot(false);
moel@391
   436
        }
moel@391
   437
moel@391
   438
        /// <summary>
moel@391
   439
        /// The zoom all.
moel@391
   440
        /// </summary>
moel@391
   441
        public void ZoomAll()
moel@391
   442
        {
moel@391
   443
            foreach (var a in this.Model.Axes)
moel@391
   444
            {
moel@391
   445
                a.Reset();
moel@391
   446
            }
moel@391
   447
moel@391
   448
            this.InvalidatePlot(false);
moel@391
   449
        }
moel@391
   450
moel@391
   451
        /// <summary>
moel@391
   452
        /// Zooms all axes.
moel@391
   453
        /// </summary>
moel@391
   454
        /// <param name="delta">
moel@391
   455
        /// The delta.
moel@391
   456
        /// </param>
moel@391
   457
        public void ZoomAllAxes(double delta)
moel@391
   458
        {
moel@391
   459
            foreach (var a in this.ActualModel.Axes)
moel@391
   460
            {
moel@391
   461
                this.ZoomAt(a, delta);
moel@391
   462
            }
moel@391
   463
moel@391
   464
            this.RefreshPlot(false);
moel@391
   465
        }
moel@391
   466
moel@391
   467
        /// <summary>
moel@391
   468
        /// The zoom at.
moel@391
   469
        /// </summary>
moel@391
   470
        /// <param name="axis">
moel@391
   471
        /// The axis.
moel@391
   472
        /// </param>
moel@391
   473
        /// <param name="factor">
moel@391
   474
        /// The factor.
moel@391
   475
        /// </param>
moel@391
   476
        /// <param name="x">
moel@391
   477
        /// The x.
moel@391
   478
        /// </param>
moel@391
   479
        public void ZoomAt(Axis axis, double factor, double x = double.NaN)
moel@391
   480
        {
moel@391
   481
            if (double.IsNaN(x))
moel@391
   482
            {
moel@391
   483
                double sx = (axis.Transform(axis.ActualMaximum) + axis.Transform(axis.ActualMinimum)) * 0.5;
moel@391
   484
                x = axis.InverseTransform(sx);
moel@391
   485
            }
moel@391
   486
moel@391
   487
            axis.ZoomAt(factor, x);
moel@391
   488
            this.InvalidatePlot(false);
moel@391
   489
        }
moel@391
   490
moel@391
   491
        /// <summary>
moel@391
   492
        /// The on mouse down.
moel@391
   493
        /// </summary>
moel@391
   494
        /// <param name="e">
moel@391
   495
        /// The e.
moel@391
   496
        /// </param>
moel@391
   497
        protected override void OnMouseDown(MouseEventArgs e)
moel@391
   498
        {
moel@391
   499
            base.OnMouseDown(e);
moel@391
   500
moel@391
   501
            if (this.mouseManipulator != null)
moel@391
   502
            {
moel@391
   503
                return;
moel@391
   504
            }
moel@391
   505
moel@391
   506
            this.Focus();
moel@391
   507
            this.Capture = true;
moel@391
   508
moel@391
   509
            if (this.ActualModel != null)
moel@391
   510
            {
moel@391
   511
                var args = this.CreateMouseEventArgs(e);
moel@391
   512
                this.ActualModel.HandleMouseDown(this, args);
moel@391
   513
                if (args.Handled)
moel@391
   514
                {
moel@391
   515
                    return;
moel@391
   516
                }
moel@391
   517
            }
moel@391
   518
moel@391
   519
            this.mouseManipulator = this.GetManipulator(e);
moel@391
   520
moel@391
   521
            if (this.mouseManipulator != null)
moel@391
   522
            {
moel@391
   523
                this.mouseManipulator.Started(this.CreateManipulationEventArgs(e));
moel@391
   524
            }
moel@391
   525
        }
moel@391
   526
moel@391
   527
        /// <summary>
moel@391
   528
        /// The on mouse move.
moel@391
   529
        /// </summary>
moel@391
   530
        /// <param name="e">
moel@391
   531
        /// The e.
moel@391
   532
        /// </param>
moel@391
   533
        protected override void OnMouseMove(MouseEventArgs e)
moel@391
   534
        {
moel@391
   535
            base.OnMouseMove(e);
moel@391
   536
moel@391
   537
            if (this.ActualModel != null)
moel@391
   538
            {
moel@391
   539
                var args = this.CreateMouseEventArgs(e);
moel@391
   540
                this.ActualModel.HandleMouseMove(this, args);
moel@391
   541
                if (args.Handled)
moel@391
   542
                {
moel@391
   543
                    return;
moel@391
   544
                }
moel@391
   545
            }
moel@391
   546
moel@391
   547
            if (this.mouseManipulator != null)
moel@391
   548
            {
moel@391
   549
                this.mouseManipulator.Delta(this.CreateManipulationEventArgs(e));
moel@391
   550
            }
moel@391
   551
        }
moel@391
   552
moel@391
   553
        /// <summary>
moel@391
   554
        /// Raises the <see cref="E:System.Windows.Forms.Control.MouseUp"/> event.
moel@391
   555
        /// </summary>
moel@391
   556
        /// <param name="e">
moel@391
   557
        /// A <see cref="T:System.Windows.Forms.MouseEventArgs"/> that contains the event data.
moel@391
   558
        /// </param>
moel@391
   559
        protected override void OnMouseUp(MouseEventArgs e)
moel@391
   560
        {
moel@391
   561
            base.OnMouseUp(e);
moel@391
   562
            this.Capture = false;
moel@391
   563
moel@391
   564
            if (this.ActualModel != null)
moel@391
   565
            {
moel@391
   566
                var args = this.CreateMouseEventArgs(e);
moel@391
   567
                this.ActualModel.HandleMouseUp(this, args);
moel@391
   568
                if (args.Handled)
moel@391
   569
                {
moel@391
   570
                    return;
moel@391
   571
                }
moel@391
   572
            }
moel@391
   573
moel@391
   574
            if (this.mouseManipulator != null)
moel@391
   575
            {
moel@391
   576
                this.mouseManipulator.Completed(this.CreateManipulationEventArgs(e));
moel@391
   577
            }
moel@391
   578
moel@391
   579
            this.mouseManipulator = null;
moel@391
   580
        }
moel@391
   581
moel@391
   582
        /// <summary>
moel@391
   583
        /// Raises the <see cref="E:System.Windows.Forms.Control.MouseWheel"/> event.
moel@391
   584
        /// </summary>
moel@391
   585
        /// <param name="e">
moel@391
   586
        /// A <see cref="T:System.Windows.Forms.MouseEventArgs"/> that contains the event data.
moel@391
   587
        /// </param>
moel@391
   588
        protected override void OnMouseWheel(MouseEventArgs e)
moel@391
   589
        {
moel@391
   590
            base.OnMouseWheel(e);
moel@391
   591
            bool isControlDown = ModifierKeys == Keys.Control;
moel@391
   592
            var m = new ZoomStepManipulator(this, e.Delta * 0.001, isControlDown);
moel@391
   593
            m.Started(new ManipulationEventArgs(e.Location.ToScreenPoint()));
moel@391
   594
        }
moel@391
   595
moel@391
   596
        /// <summary>
moel@391
   597
        /// Raises the <see cref="E:System.Windows.Forms.Control.Paint"/> event.
moel@391
   598
        /// </summary>
moel@391
   599
        /// <param name="e">
moel@391
   600
        /// A <see cref="T:System.Windows.Forms.PaintEventArgs"/> that contains the event data.
moel@391
   601
        /// </param>
moel@391
   602
        protected override void OnPaint(PaintEventArgs e)
moel@391
   603
        {
moel@391
   604
            base.OnPaint(e);
moel@391
   605
            try
moel@391
   606
            {
moel@391
   607
                lock (this.invalidateLock)
moel@391
   608
                {
moel@391
   609
                    if (this.isModelInvalidated)
moel@391
   610
                    {
moel@391
   611
                        if (this.model != null)
moel@391
   612
                        {
moel@391
   613
                            this.model.Update(this.updateDataFlag);
moel@391
   614
                            this.updateDataFlag = false;
moel@391
   615
                        }
moel@391
   616
moel@391
   617
                        this.isModelInvalidated = false;
moel@391
   618
                    }
moel@391
   619
                }
moel@391
   620
moel@391
   621
                lock (this.renderingLock)
moel@391
   622
                {
moel@391
   623
                    this.renderContext.SetGraphicsTarget(e.Graphics);
moel@391
   624
                    if (this.model != null)
moel@391
   625
                    {
moel@391
   626
                        this.model.Render(this.renderContext, this.Width, this.Height);
moel@391
   627
                    }
moel@391
   628
moel@391
   629
                    if (this.zoomRectangle != Rectangle.Empty)
moel@391
   630
                    {
moel@391
   631
                        using (var zoomBrush = new SolidBrush(Color.FromArgb(0x40, 0xFF, 0xFF, 0x00)))
moel@391
   632
                        using (var zoomPen = new Pen(Color.Black))
moel@391
   633
                        {
moel@391
   634
                            zoomPen.DashPattern = new float[] { 3, 1 };
moel@391
   635
                            e.Graphics.FillRectangle(zoomBrush, this.zoomRectangle);
moel@391
   636
                            e.Graphics.DrawRectangle(zoomPen, this.zoomRectangle);
moel@391
   637
                        }
moel@391
   638
                    }
moel@391
   639
                }
moel@391
   640
            }
moel@391
   641
            catch (Exception paintException)
moel@391
   642
            {
moel@391
   643
                var trace = new StackTrace(paintException);
moel@391
   644
                Debug.WriteLine(paintException);
moel@391
   645
                Debug.WriteLine(trace);
moel@391
   646
                using (var font = new Font("Arial", 10))
moel@391
   647
                {
moel@391
   648
                    e.Graphics.DrawString(
moel@391
   649
                        "OxyPlot paint exception: " + paintException.Message, font, Brushes.Red, 10, 10);
moel@391
   650
                }
moel@391
   651
            }
moel@391
   652
        }
moel@391
   653
moel@391
   654
        /// <summary>
moel@391
   655
        /// Raises the <see cref="E:System.Windows.Forms.Control.PreviewKeyDown"/> event.
moel@391
   656
        /// </summary>
moel@391
   657
        /// <param name="e">
moel@391
   658
        /// A <see cref="T:System.Windows.Forms.PreviewKeyDownEventArgs"/> that contains the event data.
moel@391
   659
        /// </param>
moel@391
   660
        protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
moel@391
   661
        {
moel@391
   662
            base.OnPreviewKeyDown(e);
moel@391
   663
            if (e.KeyCode == Keys.A)
moel@391
   664
            {
moel@391
   665
                this.ZoomAll();
moel@391
   666
            }
moel@391
   667
moel@391
   668
            bool control = (e.Modifiers & Keys.Control) == Keys.Control;
moel@391
   669
            bool alt = (e.Modifiers & Keys.Alt) == Keys.Alt;
moel@391
   670
moel@391
   671
            double deltax = 0;
moel@391
   672
            double deltay = 0;
moel@391
   673
            double zoom = 0;
moel@391
   674
            switch (e.KeyCode)
moel@391
   675
            {
moel@391
   676
                case Keys.Up:
moel@391
   677
                    deltay = -1;
moel@391
   678
                    break;
moel@391
   679
                case Keys.Down:
moel@391
   680
                    deltay = 1;
moel@391
   681
                    break;
moel@391
   682
                case Keys.Left:
moel@391
   683
                    deltax = -1;
moel@391
   684
                    break;
moel@391
   685
                case Keys.Right:
moel@391
   686
                    deltax = 1;
moel@391
   687
                    break;
moel@391
   688
                case Keys.Add:
moel@391
   689
                case Keys.Oemplus:
moel@391
   690
                case Keys.PageUp:
moel@391
   691
                    zoom = 1;
moel@391
   692
                    break;
moel@391
   693
                case Keys.Subtract:
moel@391
   694
                case Keys.OemMinus:
moel@391
   695
                case Keys.PageDown:
moel@391
   696
                    zoom = -1;
moel@391
   697
                    break;
moel@391
   698
            }
moel@391
   699
moel@391
   700
            if ((deltax * deltax) + (deltay * deltay) > 0)
moel@391
   701
            {
moel@391
   702
                deltax = deltax * this.ActualModel.PlotArea.Width * this.KeyboardPanHorizontalStep;
moel@391
   703
                deltay = deltay * this.ActualModel.PlotArea.Height * this.KeyboardPanVerticalStep;
moel@391
   704
moel@391
   705
                // small steps if the user is pressing control
moel@391
   706
                if (control)
moel@391
   707
                {
moel@391
   708
                    deltax *= 0.2;
moel@391
   709
                    deltay *= 0.2;
moel@391
   710
                }
moel@391
   711
moel@391
   712
                this.PanAll(deltax, deltay);
moel@391
   713
moel@391
   714
                // e.Handled = true;
moel@391
   715
            }
moel@391
   716
moel@391
   717
            if (Math.Abs(zoom) > 1e-8)
moel@391
   718
            {
moel@391
   719
                if (control)
moel@391
   720
                {
moel@391
   721
                    zoom *= 0.2;
moel@391
   722
                }
moel@391
   723
moel@391
   724
                this.ZoomAllAxes(1 + (zoom * 0.12));
moel@391
   725
moel@391
   726
                // e.Handled = true;
moel@391
   727
            }
moel@391
   728
moel@391
   729
            if (control && alt && this.ActualModel != null)
moel@391
   730
            {
moel@391
   731
                switch (e.KeyCode)
moel@391
   732
                {
moel@391
   733
                    case Keys.R:
moel@391
   734
                        this.SetClipboardText(this.ActualModel.CreateTextReport());
moel@391
   735
                        break;
moel@391
   736
                    case Keys.C:
moel@391
   737
                        this.SetClipboardText(this.ActualModel.ToCode());
moel@391
   738
                        break;
moel@391
   739
                    case Keys.X:
moel@391
   740
moel@391
   741
                        // this.SetClipboardText(this.ActualModel.ToXml());
moel@391
   742
                        break;
moel@391
   743
                }
moel@391
   744
            }
moel@391
   745
        }
moel@391
   746
moel@391
   747
        /// <summary>
moel@391
   748
        /// Raises the <see cref="E:System.Windows.Forms.Control.Resize"/> event.
moel@391
   749
        /// </summary>
moel@391
   750
        /// <param name="e">
moel@391
   751
        /// An <see cref="T:System.EventArgs"/> that contains the event data.
moel@391
   752
        /// </param>
moel@391
   753
        protected override void OnResize(EventArgs e)
moel@391
   754
        {
moel@391
   755
            base.OnResize(e);
moel@391
   756
            this.InvalidatePlot(false);
moel@391
   757
        }
moel@391
   758
moel@391
   759
        /// <summary>
moel@391
   760
        /// Converts the changed button.
moel@391
   761
        /// </summary>
moel@391
   762
        /// <param name="e">
moel@391
   763
        /// The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.
moel@391
   764
        /// </param>
moel@391
   765
        /// <returns>
moel@391
   766
        /// The mouse button.
moel@391
   767
        /// </returns>
moel@391
   768
        private static OxyMouseButton ConvertChangedButton(MouseEventArgs e)
moel@391
   769
        {
moel@391
   770
            switch (e.Button)
moel@391
   771
            {
moel@391
   772
                case MouseButtons.Left:
moel@391
   773
                    return OxyMouseButton.Left;
moel@391
   774
                case MouseButtons.Middle:
moel@391
   775
                    return OxyMouseButton.Middle;
moel@391
   776
                case MouseButtons.Right:
moel@391
   777
                    return OxyMouseButton.Right;
moel@391
   778
                case MouseButtons.XButton1:
moel@391
   779
                    return OxyMouseButton.XButton1;
moel@391
   780
                case MouseButtons.XButton2:
moel@391
   781
                    return OxyMouseButton.XButton2;
moel@391
   782
            }
moel@391
   783
moel@391
   784
            return OxyMouseButton.Left;
moel@391
   785
        }
moel@391
   786
moel@391
   787
        /// <summary>
moel@391
   788
        /// Creates the mouse event arguments.
moel@391
   789
        /// </summary>
moel@391
   790
        /// <param name="e">
moel@391
   791
        /// The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.
moel@391
   792
        /// </param>
moel@391
   793
        /// <returns>
moel@391
   794
        /// Mouse event arguments.
moel@391
   795
        /// </returns>
moel@391
   796
        private OxyMouseEventArgs CreateMouseEventArgs(MouseEventArgs e)
moel@391
   797
        {
moel@391
   798
            return new OxyMouseEventArgs
moel@391
   799
            {
moel@391
   800
                ChangedButton = ConvertChangedButton(e),
moel@391
   801
                Position = new ScreenPoint(e.Location.X, e.Location.Y),
moel@391
   802
                IsShiftDown = (ModifierKeys & Keys.Shift) == Keys.Shift,
moel@391
   803
                IsControlDown = (ModifierKeys & Keys.Control) == Keys.Control,
moel@391
   804
                IsAltDown = (ModifierKeys & Keys.Alt) == Keys.Alt,
moel@391
   805
            };
moel@391
   806
        }
moel@391
   807
moel@391
   808
        /// <summary>
moel@391
   809
        /// Creates the manipulation event args.
moel@391
   810
        /// </summary>
moel@391
   811
        /// <param name="e">
moel@391
   812
        /// The MouseEventArgs instance containing the event data.
moel@391
   813
        /// </param>
moel@391
   814
        /// <returns>
moel@391
   815
        /// A manipulation event args object.
moel@391
   816
        /// </returns>
moel@391
   817
        private ManipulationEventArgs CreateManipulationEventArgs(MouseEventArgs e)
moel@391
   818
        {
moel@391
   819
            return new ManipulationEventArgs(e.Location.ToScreenPoint());
moel@391
   820
        }
moel@391
   821
moel@391
   822
        /// <summary>
moel@391
   823
        /// Gets the manipulator for the current mouse button and modifier keys.
moel@391
   824
        /// </summary>
moel@391
   825
        /// <param name="e">
moel@391
   826
        /// The event args.
moel@391
   827
        /// </param>
moel@391
   828
        /// <returns>
moel@391
   829
        /// A manipulator or null if no gesture was recognized.
moel@391
   830
        /// </returns>
moel@391
   831
        private ManipulatorBase GetManipulator(MouseEventArgs e)
moel@391
   832
        {
moel@391
   833
            bool control = (ModifierKeys & Keys.Control) == Keys.Control;
moel@391
   834
            bool shift = (ModifierKeys & Keys.Shift) == Keys.Shift;
moel@391
   835
            bool alt = (ModifierKeys & Keys.Alt) == Keys.Alt;
moel@391
   836
moel@391
   837
            bool lmb = e.Button == MouseButtons.Left;
moel@391
   838
            bool rmb = e.Button == MouseButtons.Right;
moel@391
   839
            bool mmb = e.Button == MouseButtons.Middle;
moel@391
   840
            bool xb1 = e.Button == MouseButtons.XButton1;
moel@391
   841
            bool xb2 = e.Button == MouseButtons.XButton2;
moel@391
   842
moel@391
   843
            // MMB / control RMB / control+alt LMB
moel@393
   844
            if (mmb || (control && lmb) || (control && alt && rmb))
moel@393
   845
            {
moel@393
   846
                return new ZoomRectangleManipulator(this);
moel@393
   847
            }
moel@393
   848
moel@393
   849
            // Right mouse button / alt+left mouse button
moel@393
   850
            if (lmb || (rmb && alt))
moel@391
   851
            {
moel@391
   852
                if (e.Clicks == 2)
moel@391
   853
                {
moel@391
   854
                    return new ResetManipulator(this);
moel@391
   855
                }
moel@391
   856
                return new PanManipulator(this);
moel@391
   857
            }
moel@391
   858
moel@391
   859
            // Left mouse button
moel@393
   860
            if (rmb)
moel@391
   861
            {
moel@391
   862
                return new TrackerManipulator(this) { Snap = !control, PointsOnly = shift };
moel@391
   863
            }
moel@391
   864
moel@391
   865
            // XButtons are zoom-stepping
moel@391
   866
            if (xb1 || xb2)
moel@391
   867
            {
moel@391
   868
                double d = xb1 ? 0.05 : -0.05;
moel@391
   869
                return new ZoomStepManipulator(this, d, control);
moel@391
   870
            }
moel@391
   871
moel@391
   872
            return null;
moel@391
   873
        }
moel@391
   874
moel@391
   875
        /// <summary>
moel@391
   876
        /// The set clipboard text.
moel@391
   877
        /// </summary>
moel@391
   878
        /// <param name="text">
moel@391
   879
        /// The text.
moel@391
   880
        /// </param>
moel@391
   881
        private void SetClipboardText(string text)
moel@391
   882
        {
moel@391
   883
            try
moel@391
   884
            {
moel@391
   885
                // todo: can't get the following solution to work
moel@391
   886
                // http://stackoverflow.com/questions/5707990/requested-clipboard-operation-did-not-succeed
moel@391
   887
                Clipboard.SetText(text);
moel@391
   888
            }
moel@391
   889
            catch (ExternalException ee)
moel@391
   890
            {
moel@391
   891
                // Requested Clipboard operation did not succeed.
moel@391
   892
                MessageBox.Show(this, ee.Message, "OxyPlot");
moel@391
   893
            }
moel@391
   894
        }
moel@391
   895
    }
moel@391
   896
}