External/OxyPlot/OxyPlot.WindowsForms/Plot.cs
author moel.mich
Tue, 30 Dec 2014 17:35:29 +0000
changeset 429 5d87c9fc69f6
parent 391 5be8f2773237
permissions -rw-r--r--
Changed the settings save code to use a two file based approach in order to reduce cases where settings are lost or reset (Fixed Issue 501).
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
}