nplot-gtk/lib/Windows.PlotSurface2D.cs

2943 строки
89 KiB
C#
Исходник Постоянная ссылка Обычный вид История

/*
NPlot - A charting library for .NET
Windows.PlotSurface2d.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Drawing.Printing;
using NPlot;
namespace NPlot.Windows
{
/// <summary>
/// A Windows.Forms PlotSurface2D control.
/// </summary>
/// <remarks>
/// Unfortunately it's not possible to derive from both Control and NPlot.PlotSurface2D.
/// </remarks>
[ ToolboxBitmapAttribute(typeof(NPlot.Windows.PlotSurface2D),"PlotSurface2D.ico") ]
public class PlotSurface2D : System.Windows.Forms.Control, IPlotSurface2D, ISurface
{
private System.Windows.Forms.ToolTip coordinates_;
private System.Collections.ArrayList selectedObjects_;
private NPlot.PlotSurface2D ps_;
private Axis xAxis1ZoomCache_;
private Axis yAxis1ZoomCache_;
private Axis xAxis2ZoomCache_;
private Axis yAxis2ZoomCache_;
/// <summary>
/// Flag to display a coordinates in a tooltip.
/// </summary>
[
Category("PlotSurface2D"),
Description("Whether or not to show coordinates in a tool tip when the mouse hovers above the plot area."),
Browsable(true),
Bindable(true)
]
public bool ShowCoordinates
{
get
{
return this.coordinates_.Active;
}
set
{
this.coordinates_.Active = value;
}
}
/// <summary>
/// Default constructor.
/// </summary>
public PlotSurface2D()
{
// This call is required by the Windows.Forms Form Designer.
InitializeComponent();
// double buffer, and update when resize.
base.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
base.SetStyle(ControlStyles.DoubleBuffer, true);
base.SetStyle(ControlStyles.UserPaint, true);
base.ResizeRedraw = true;
ps_ = new NPlot.PlotSurface2D();
this.InteractionOccured += new InteractionHandler( OnInteractionOccured );
this.PreRefresh += new PreRefreshHandler( OnPreRefresh );
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
/// <remarks>Modified! :-)</remarks>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.coordinates_ = new System.Windows.Forms.ToolTip(this.components);
//
// PlotSurface2D
//
this.BackColor = System.Drawing.SystemColors.ControlLightLight;
this.Size = new System.Drawing.Size(328, 272);
}
KeyEventArgs lastKeyEventArgs_ = null;
/// <summary>
/// the key down callback
/// </summary>
/// <param name="e">information pertaining to the event</param>
protected override void OnKeyDown(KeyEventArgs e)
{
lastKeyEventArgs_ = e;
}
/// <summary>
/// The key up callback.
/// </summary>
/// <param name="e">information pertaining to the event</param>
protected override void OnKeyUp(KeyEventArgs e)
{
lastKeyEventArgs_ = e;
}
/// <summary>
/// the paint event callback.
/// </summary>
/// <param name="pe">the PaintEventArgs</param>
protected override void OnPaint( PaintEventArgs pe )
{
DoPaint( pe, this.Width, this.Height );
base.OnPaint(pe);
}
/// <summary>
/// All functionality of the OnPaint method is provided by this function.
/// This allows use of the all encompasing PlotSurface.
/// </summary>
/// <param name="pe">the PaintEventArgs from paint event.</param>
/// <param name="width">width of the control</param>
/// <param name="height">height of the control</param>
public void DoPaint( PaintEventArgs pe, int width, int height )
{
this.PreRefresh(this);
foreach (Interactions.Interaction i in interactions_)
{
i.DoPaint(pe,width,height);
}
/*
// make sure don't redraw after a refresh.
this.horizontalBarPos_ = -1;
this.verticalBarPos_ = -1;
*/
Graphics g = pe.Graphics;
Rectangle border = new Rectangle( 0, 0, width, height );
if ( g == null )
{
throw (new NPlotException("null graphics context!"));
}
if ( ps_ == null )
{
throw (new NPlotException("null NPlot.PlotSurface2D"));
}
if ( border == Rectangle.Empty )
{
throw (new NPlotException("null border context"));
}
this.Draw( g, border );
}
/// <summary>
/// Draws the plot surface on the supplied graphics surface [not the control surface].
/// </summary>
/// <param name="g">The graphics surface on which to draw</param>
/// <param name="bounds">A bounding box on this surface that denotes the area on the
/// surface to confine drawing to.</param>
public void Draw( Graphics g, Rectangle bounds )
{
// If we are not in design mode then draw as normal.
if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
{
this.drawDesignMode( g, bounds );
}
ps_.Draw( g, bounds );
}
/// <summary>
/// Draw a lightweight representation of us for design mode.
/// </summary>
private void drawDesignMode( Graphics g, Rectangle bounds )
{
g.DrawRectangle( new Pen(Color.Black), bounds.X + 2, bounds.Y + 2, bounds.Width-4, bounds.Height-4 );
g.DrawString( "PlotSurface2D: " + this.Title, this.TitleFont, this.TitleBrush, bounds.X + bounds.Width/2.0f, bounds.Y + bounds.Height/2.0f );
}
/// <summary>
/// Clears the plot and resets to default values.
/// </summary>
public void Clear()
{
xAxis1ZoomCache_ = null;
yAxis1ZoomCache_ = null;
xAxis2ZoomCache_ = null;
yAxis2ZoomCache_ = null;
ps_.Clear();
interactions_.Clear();
}
/// <summary>
/// Adds a drawable object to the plot surface. If the object is an IPlot,
/// the PlotSurface2D axes will also be updated.
/// </summary>
/// <param name="p">The IDrawable object to add to the plot surface.</param>
public void Add( IDrawable p )
{
ps_.Add( p );
}
/// <summary>
/// Adds a drawable object to the plot surface against the specified axes. If
/// the object is an IPlot, the PlotSurface2D axes will also be updated.
/// </summary>
/// <param name="p">the IDrawable object to add to the plot surface</param>
/// <param name="xp">the x-axis to add the plot against.</param>
/// <param name="yp">the y-axis to add the plot against.</param>
public void Add( IDrawable p, NPlot.PlotSurface2D.XAxisPosition xp, NPlot.PlotSurface2D.YAxisPosition yp )
{
ps_.Add( p, xp, yp );
}
/// <summary>
/// Adds a drawable object to the plot surface. If the object is an IPlot,
/// the PlotSurface2D axes will also be updated.
/// </summary>
/// <param name="p">The IDrawable object to add to the plot surface.</param>
/// <param name="zOrder">The z-ordering when drawing (objects with lower numbers are drawn first)</param>
public void Add( IDrawable p, int zOrder )
{
ps_.Add( p, zOrder );
}
/// <summary>
/// Adds a drawable object to the plot surface against the specified axes. If
/// the object is an IPlot, the PlotSurface2D axes will also be updated.
/// </summary>
/// <param name="p">the IDrawable object to add to the plot surface</param>
/// <param name="xp">the x-axis to add the plot against.</param>
/// <param name="yp">the y-axis to add the plot against.</param>
/// <param name="zOrder">The z-ordering when drawing (objects with lower numbers are drawn first)</param>
public void Add( IDrawable p, NPlot.PlotSurface2D.XAxisPosition xp,
NPlot.PlotSurface2D.YAxisPosition yp, int zOrder )
{
ps_.Add( p, xp, yp , zOrder);
}
/// <summary>
/// Gets or Sets the legend to use with this plot surface.
/// </summary>
[
Browsable(false),
Bindable(false)
]
public NPlot.Legend Legend
{
get
{
return ps_.Legend;
}
set
{
ps_.Legend = value;
}
}
/// <summary>
/// Gets or Sets the legend z-order.
/// </summary>
[
Browsable(true),
Bindable(true),
Category("PlotSurface2D"),
Description("Determines the order with respect to other IDrawables on the plot surface in which the legend is drawn. " +
"The higher this value, the higher the position in the draw order." )
]
public int LegendZOrder
{
get
{
return ps_.LegendZOrder;
}
set
{
ps_.LegendZOrder = value;
}
}
/// <summary>
/// Whether or not the title will be scaled according to size of the plot
/// surface.
/// </summary>
[
Browsable(true),
Bindable(true),
Description("Whether or not the title will be scaled according to size of the plot surface."),
Category("PlotSurface2D")
]
public bool AutoScaleTitle
{
get
{
return ps_.AutoScaleTitle;
}
set
{
ps_.AutoScaleTitle = value;
}
}
/// <summary>
/// When plots are added to the plot surface, the axes they are attached to
/// are immediately modified to reflect data of the plot. If
/// AutoScaleAutoGeneratedAxes is true when a plot is added, the axes will
/// be turned in to auto scaling ones if they are not already [tick marks,
/// tick text and label size scaled to size of plot surface]. If false,
/// axes will not be autoscaling.
/// </summary>
[
Browsable(true),
Bindable(true),
Description( "When plots are added to the plot surface, the axes they are attached to are immediately modified " +
"to reflect data of the plot. If AutoScaleAutoGeneratedAxes is true when a plot is added, the axes will be " +
"turned in to auto scaling ones if they are not already [tick marks, tick text and label size scaled to size " +
"of plot surface]. If false, axes will not be autoscaling." ),
Category("PlotSurface2D")
]
public bool AutoScaleAutoGeneratedAxes
{
get
{
return ps_.AutoScaleAutoGeneratedAxes;
}
set
{
ps_.AutoScaleAutoGeneratedAxes = value;
}
}
/// <summary>
/// The plot surface title.
/// </summary>
[
Category("PlotSurface2D"),
Description("The plot surface title"),
Browsable(true),
Bindable(true)
]
public string Title
{
get
{
return ps_.Title;
}
set
{
ps_.Title = value;
//helpful in design view. But crap in applications!
//this.Refresh();
}
}
/// <summary>
/// The font used to draw the title.
/// </summary>
[
Category("PlotSurface2D"),
Description("The font used to draw the title."),
Browsable(true),
Bindable(false)
]
public Font TitleFont
{
get
{
return ps_.TitleFont;
}
set
{
ps_.TitleFont = value;
}
}
/// <summary>
/// Padding of this width will be left between what is drawn and the control border.
/// </summary>
[
Category("PlotSurface2D"),
Description("Padding of this width will be left between what is drawn and the control border."),
Browsable(true),
Bindable(true)
]
public int Padding
{
get
{
return ps_.Padding;
}
set
{
ps_.Padding = value;
}
}
/// <summary>
/// The first abscissa axis.
/// </summary>
///
[
Browsable(false)
]
public Axis XAxis1
{
get
{
return ps_.XAxis1;
}
set
{
ps_.XAxis1 = value;
}
}
/// <summary>
/// The first ordinate axis.
/// </summary>
[
Browsable(false)
]
public Axis YAxis1
{
get
{
return ps_.YAxis1;
}
set
{
ps_.YAxis1 = value;
}
}
/// <summary>
/// The second abscissa axis.
/// </summary>
[
Browsable(false)
]
public Axis XAxis2
{
get
{
return ps_.XAxis2;
}
set
{
ps_.XAxis2 = value;
}
}
/// <summary>
/// The second ordinate axis.
/// </summary>
[
Browsable(false)
]
public Axis YAxis2
{
get
{
return ps_.YAxis2;
}
set
{
ps_.YAxis2 = value;
}
}
/// <summary>
/// The physical XAxis1 that was last drawn.
/// </summary>
[
Browsable(false)
]
public PhysicalAxis PhysicalXAxis1Cache
{
get
{
return ps_.PhysicalXAxis1Cache;
}
}
/// <summary>
/// The physical YAxis1 that was last drawn.
/// </summary>
[
Browsable(false)
]
public PhysicalAxis PhysicalYAxis1Cache
{
get
{
return ps_.PhysicalYAxis1Cache;
}
}
/// <summary>
/// The physical XAxis2 that was last drawn.
/// </summary>
[
Browsable(false)
]
public PhysicalAxis PhysicalXAxis2Cache
{
get
{
return ps_.PhysicalXAxis2Cache;
}
}
/// <summary>
/// The physical YAxis2 that was last drawn.
/// </summary>
[
Browsable(false)
]
public PhysicalAxis PhysicalYAxis2Cache
{
get
{
return ps_.PhysicalYAxis2Cache;
}
}
/// <summary>
/// A color used to paint the plot background. Mutually exclusive with PlotBackImage and PlotBackBrush
/// </summary>
/// <remarks>not browsable or bindable because only set method.</remarks>
[
Category("PlotSurface2D"),
Description("Set the plot background color."),
Browsable(true),
Bindable(false)
]
public System.Drawing.Color PlotBackColor
{
set
{
ps_.PlotBackColor = value;
}
}
/// <summary>
/// An imaged used to paint the plot background. Mutually exclusive with PlotBackColor and PlotBackBrush
/// </summary>
/// <remarks>not browsable or bindable because only set method.</remarks>
[
Browsable(false),
Bindable(false)
]
public System.Drawing.Bitmap PlotBackImage
{
set
{
ps_.PlotBackImage = value;
}
}
/// <summary>
/// A Rectangle brush used to paint the plot background. Mutually exclusive with PlotBackColor and PlotBackBrush
/// </summary>
/// <remarks>not browsable or bindable because only set method.</remarks>
[
Browsable(false),
Bindable(false)
]
public IRectangleBrush PlotBackBrush
{
set
{
ps_.PlotBackBrush = value;
}
}
/// <summary>
/// Sets the title to be drawn using a solid brush of this color.
/// </summary>
/// <remarks>not browsable or bindable because only set method.</remarks>
[
Browsable(false),
Bindable(false)
]
public Color TitleColor
{
set
{
ps_.TitleColor = value;
}
}
/// <summary>
/// The brush used for drawing the title.
/// </summary>
[
Browsable(true),
Bindable(true),
Description("The brush used for drawing the title."),
Category("PlotSurface2D")
]
public Brush TitleBrush
{
get
{
return ps_.TitleBrush;
}
set
{
ps_.TitleBrush = value;
}
}
/// <summary>
/// Set smoothing mode for drawing plot objects.
/// </summary>
[
Category("PlotSurface2D"),
Description("Set smoothing mode for drawing plot objects."),
Browsable(true),
Bindable(true)
]
public System.Drawing.Drawing2D.SmoothingMode SmoothingMode
{
get
{
return ps_.SmoothingMode;
}
set
{
ps_.SmoothingMode = value;
}
}
/// <summary>
/// Mouse down event handler.
/// </summary>
/// <param name="e">the event args.</param>
protected override void OnMouseDown(MouseEventArgs e)
{
DoMouseDown(e);
base.OnMouseDown(e);
}
/// <summary>
/// All functionality of the OnMouseDown function is contained here.
/// This allows use of the all encompasing PlotSurface.
/// </summary>
/// <param name="e">The mouse event args from the window we are drawing to.</param>
public void DoMouseDown( MouseEventArgs e )
{
bool dirty = false;
foreach (Interactions.Interaction i in interactions_)
{
i.DoMouseDown(e,this);
dirty |= i.DoMouseDown(e,this);
}
if (dirty)
{
Refresh();
}
}
/// <summary>
/// Mouse Wheel event handler.
/// </summary>
/// <param name="e">the event args</param>
protected override void OnMouseWheel( System.Windows.Forms.MouseEventArgs e )
{
DoMouseWheel(e);
base.OnMouseWheel(e);
}
/// <summary>
/// All functionality of the OnMouseWheel function is containd here.
/// This allows use of the all encompasing PlotSurface.
/// </summary>
/// <param name="e">the event args.</param>
public void DoMouseWheel(MouseEventArgs e)
{
bool dirty = false;
foreach (Interactions.Interaction i in interactions_)
{
i.DoMouseWheel(e, this);
dirty |= i.DoMouseWheel(e, this);
}
if (dirty)
{
Refresh();
}
}
/// <summary>
/// All functionality of the OnMouseMove function is contained here.
/// This allows use of the all encompasing PlotSurface.
/// </summary>
/// <param name="e">The mouse event args from the window we are drawing to.</param>
/// <param name="ctr">The control that the mouse event happened in.</param>
public void DoMouseMove( MouseEventArgs e, System.Windows.Forms.Control ctr )
{
bool dirty = false;
foreach (Interactions.Interaction i in interactions_)
{
i.DoMouseMove(e, ctr, lastKeyEventArgs_);
dirty |= i.DoMouseMove(e, ctr, lastKeyEventArgs_);
}
if (dirty)
{
Refresh();
}
// Update coordinates if necessary.
if ( coordinates_.Active )
{
// we are here
Point here = new Point( e.X, e.Y );
if ( ps_.PlotAreaBoundingBoxCache.Contains(here) )
{
coordinates_.ShowAlways = true;
// according to M<>ns Erlandson, this can sometimes be the case.
if (this.PhysicalXAxis1Cache == null)
return;
if (this.PhysicalYAxis1Cache == null)
return;
double x = this.PhysicalXAxis1Cache.PhysicalToWorld( here, true );
double y = this.PhysicalYAxis1Cache.PhysicalToWorld( here, true );
string s = "";
if (!DateTimeToolTip)
{
s = "(" + x.ToString("g4") + "," + y.ToString("g4") + ")";
}
else
{
DateTime dateTime = new DateTime((long)x);
s = dateTime.ToShortDateString() + " " + dateTime.ToLongTimeString() + Environment.NewLine + y.ToString("f4");
}
coordinates_.SetToolTip( this, s );
}
else
{
coordinates_.ShowAlways = false;
}
}
}
/// <summary>
/// MouseMove event handler.
/// </summary>
/// <param name="e">The event arguments.</param>
protected override void OnMouseMove(MouseEventArgs e)
{
DoMouseMove( e, this );
base.OnMouseMove( e );
}
/// <summary>
/// MouseLeave event handler. It has to invalidate the control to get rid of
/// any remnant of vertical and horizontal guides.
/// </summary>
/// <param name="e">The event arguments.</param>
protected override void OnMouseLeave(EventArgs e)
{
DoMouseLeave( e, this );
base.OnMouseLeave(e);
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
/// <param name="ctr"></param>
public void DoMouseLeave(EventArgs e, System.Windows.Forms.Control ctr)
{
bool dirty = false;
foreach (Interactions.Interaction i in interactions_)
{
dirty = i.DoMouseLeave(e, this) || dirty;
}
if (dirty)
Refresh();
}
/// <summary>
/// When true, tool tip will display x value as a DateTime. Quick hack - this will probably be
/// changed at some point.
/// </summary>
[
Bindable(true),
Browsable(true),
Category("PlotSurface2D"),
Description("When true, tool tip will display x value as a DateTime. Quick hack - this will probably be changed at some point.")
]
public bool DateTimeToolTip
{
get
{
return dateTimeToolTip_;
}
set
{
dateTimeToolTip_ = value;
}
}
private bool dateTimeToolTip_ = false;
/// <summary>
/// All functionality of the OnMouseUp function is contained here.
/// This allows use of the all encompasing PlotSurface.
/// </summary>
/// <param name="e">The mouse event args from the window we are drawing to.</param>
/// <param name="ctr">The control that the mouse event happened in.</param>
public void DoMouseUp( MouseEventArgs e, System.Windows.Forms.Control ctr )
{
bool dirty = false;
ArrayList local_interactions = (ArrayList)interactions_.Clone();
foreach (Interactions.Interaction i in local_interactions)
{
dirty |= i.DoMouseUp(e,ctr);
}
if (dirty)
{
Refresh();
}
if (e.Button == MouseButtons.Right)
{
Point here = new Point(e.X, e.Y);
selectedObjects_ = ps_.HitTest(here);
if (rightMenu_ != null)
rightMenu_.Menu.Show(ctr, here);
}
}
/// <summary>
/// mouse up event handler.
/// </summary>
/// <param name="e">The event arguments.</param>
protected override void OnMouseUp( MouseEventArgs e )
{
DoMouseUp(e, this);
base.OnMouseUp(e);
}
/// <summary>
/// sets axes to be those saved in the cache.
/// </summary>
public void OriginalDimensions()
{
if ( xAxis1ZoomCache_ != null )
{
this.XAxis1 = xAxis1ZoomCache_;
this.XAxis2 = xAxis2ZoomCache_;
this.YAxis1 = yAxis1ZoomCache_;
this.YAxis2 = yAxis2ZoomCache_;
xAxis1ZoomCache_ = null;
xAxis2ZoomCache_ = null;
yAxis1ZoomCache_ = null;
yAxis2ZoomCache_ = null;
}
this.Refresh();
}
private void DrawHorizontalSelection(Point start, Point end, System.Windows.Forms.UserControl ctr)
{
// the clipping rectangle in screen coordinates
Rectangle clip = ctr.RectangleToScreen(
new Rectangle(
(int)ps_.PlotAreaBoundingBoxCache.X,
(int)ps_.PlotAreaBoundingBoxCache.Y,
(int)ps_.PlotAreaBoundingBoxCache.Width,
(int)ps_.PlotAreaBoundingBoxCache.Height));
start = ctr.PointToScreen(start);
end = ctr.PointToScreen(end);
ControlPaint.FillReversibleRectangle(
new Rectangle((int)Math.Min(start.X,end.X), (int)clip.Y, (int)Math.Abs(end.X-start.X), (int)clip.Height),
Color.White );
}
/// <summary>
/// Add an axis constraint to the plot surface. Axis constraints can
/// specify relative world-pixel scalings, absolute axis positions etc.
/// </summary>
/// <param name="c">The axis constraint to add.</param>
public void AddAxesConstraint( AxesConstraint c )
{
ps_.AddAxesConstraint( c );
}
/// <summary>
/// Print the chart as currently shown by the control
/// </summary>
/// <param name="preview">If true, show print preview window.</param>
public void Print( bool preview )
{
PrintDocument printDocument = new PrintDocument();
printDocument.PrintPage += new PrintPageEventHandler(NPlot_PrintPage);
printDocument.DefaultPageSettings.Landscape = true;
DialogResult result;
if (!preview)
{
PrintDialog dlg = new PrintDialog();
dlg.Document = printDocument;
result = dlg.ShowDialog();
}
else
{
PrintPreviewDialog dlg = new PrintPreviewDialog();
dlg.Document = printDocument;
result = dlg.ShowDialog();
}
if (result == DialogResult.OK)
{
try
{
printDocument.Print();
}
catch
{
Console.WriteLine( "caught\n" );
}
}
}
private void NPlot_PrintPage(object sender, PrintPageEventArgs ev)
{
Rectangle r = ev.MarginBounds;
this.Draw( ev.Graphics, r );
ev.HasMorePages = false;
}
/// <summary>
/// Coppies the chart currently shown in the control to the clipboard as an image.
/// </summary>
public void CopyToClipboard()
{
System.Drawing.Bitmap b = new System.Drawing.Bitmap( this.Width, this.Height );
System.Drawing.Graphics g = Graphics.FromImage( b );
g.Clear(Color.White);
this.Draw( g, new Rectangle( 0, 0, b.Width-1, b.Height-1 ) );
Clipboard.SetDataObject( b, true );
}
/// <summary>
/// Coppies data in the current plot surface view window to the clipboard
/// as text.
/// </summary>
public void CopyDataToClipboard()
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
for (int i=0; i<ps_.Drawables.Count; ++i)
{
IPlot plot = ps_.Drawables[i] as IPlot;
if (plot != null)
{
Axis xAxis = ps_.WhichXAxis( plot );
Axis yAxis = ps_.WhichYAxis( plot );
RectangleD region = new RectangleD(
xAxis.WorldMin,
yAxis.WorldMin,
xAxis.WorldMax - xAxis.WorldMin,
yAxis.WorldMax - yAxis.WorldMin );
plot.WriteData( sb, region, true );
}
}
Clipboard.SetDataObject( sb.ToString(), true );
}
/// <summary>
/// Remove a drawable object from the plot surface.
/// </summary>
/// <param name="p">the drawable to remove</param>
/// <param name="updateAxes">whether or not to update the axes after removing the idrawable.</param>
public void Remove(IDrawable p, bool updateAxes)
{
ps_.Remove(p, updateAxes);
}
/// <summary>
/// Gets an array list containing all drawables currently added to the PlotSurface2D.
/// </summary>
[
Browsable(false),
Bindable(false)
]
public ArrayList Drawables
{
get
{
return ps_.Drawables;
}
}
/// <summary>
/// Sets the right context menu. Custom menus can be designed by overriding
/// NPlot.Windows.PlotSurface2D.ContextMenu.
/// </summary>
[
Browsable(false),
Bindable(false)
]
public NPlot.Windows.PlotSurface2D.PlotContextMenu RightMenu
{
get
{
return rightMenu_;
}
set
{
rightMenu_ = value;
if (rightMenu_ != null)
{
rightMenu_.PlotSurface2D = this;
}
}
}
private NPlot.Windows.PlotSurface2D.PlotContextMenu rightMenu_ = null;
/// <summary>
/// Gets an instance of a NPlot.Windows.PlotSurface2D.ContextMenu that
/// is useful in typical situations.
/// </summary>
public static PlotContextMenu DefaultContextMenu
{
get
{
return new NPlot.Windows.PlotSurface2D.PlotContextMenu();
}
}
/// <summary>
/// Allows access to the PlotSurface2D.
/// </summary>
[
Browsable(false),
Bindable(false)
]
public NPlot.PlotSurface2D Inner
{
get
{
return ps_;
}
}
/// <summary>
/// Remembers the current axes - useful in interactions.
/// </summary>
public void CacheAxes()
{
if (xAxis1ZoomCache_ == null && xAxis2ZoomCache_ == null &&
yAxis1ZoomCache_ == null && yAxis2ZoomCache_ == null)
{
if (this.XAxis1 != null)
{
xAxis1ZoomCache_ = (Axis)this.XAxis1.Clone();
}
if (this.XAxis2 != null)
{
xAxis2ZoomCache_ = (Axis)this.XAxis2.Clone();
}
if (this.YAxis1 != null)
{
yAxis1ZoomCache_ = (Axis)this.YAxis1.Clone();
}
if (this.YAxis2 != null)
{
yAxis2ZoomCache_ = (Axis)this.YAxis2.Clone();
}
}
}
/// <summary>
/// Encapsulates a number of separate "Interactions". An interaction is basically
/// a set of handlers for mouse and keyboard events that work together in a
/// specific way.
/// </summary>
public abstract class Interactions
{
/// <summary>
/// Base class for an interaction. All methods are virtual. Not abstract as not all interactions
/// need to use all methods. Default functionality for each method is to do nothing.
/// </summary>
public class Interaction
{
/// <summary>
/// Handler for this interaction if a mouse down event is received.
/// </summary>
/// <param name="e">event args</param>
/// <param name="ctr">reference to the control</param>
/// <returns>true if plot surface needs refreshing.</returns>
public virtual bool DoMouseDown(MouseEventArgs e, System.Windows.Forms.Control ctr) { return false; }
/// <summary>
/// Handler for this interaction if a mouse up event is received.
/// </summary>
/// <param name="e">event args</param>
/// <param name="ctr">reference to the control</param>
/// <returns>true if plot surface needs refreshing.</returns>
public virtual bool DoMouseUp(MouseEventArgs e, System.Windows.Forms.Control ctr) { return false; }
/// <summary>
/// Handler for this interaction if a mouse move event is received.
/// </summary>
/// <param name="e">event args</param>
/// <param name="ctr">reference to the control</param>
/// <param name="lastKeyEventArgs"></param>
/// <returns>true if plot surface needs refreshing.</returns>
public virtual bool DoMouseMove(MouseEventArgs e, System.Windows.Forms.Control ctr, KeyEventArgs lastKeyEventArgs) { return false; }
/// <summary>
/// Handler for this interaction if a mouse move event is received.
/// </summary>
/// <param name="e">event args</param>
/// <param name="ctr">reference to the control</param>
/// <returns>true if plot surface needs refreshing.</returns>
public virtual bool DoMouseWheel(MouseEventArgs e, System.Windows.Forms.Control ctr) { return false; }
/// <summary>
/// Handler for this interaction if a mouse Leave event is received.
/// </summary>
/// <param name="e">event args</param>
/// <param name="ctr">reference to the control</param>
/// <returns>true if the plot surface needs refreshing.</returns>
public virtual bool DoMouseLeave(EventArgs e, System.Windows.Forms.Control ctr) { return false; }
/// <summary>
/// Handler for this interaction if a paint event is received.
/// </summary>
/// <param name="pe">paint event args</param>
/// <param name="width"></param>
/// <param name="height"></param>
public virtual void DoPaint(PaintEventArgs pe, int width, int height) { }
}
#region RubberBandSelection
/// <summary>
///
/// </summary>
public class RubberBandSelection : Interaction
{
private bool selectionInitiated_ = false;
/// <summary>
///
/// </summary>
/// <param name="e"></param>
/// <param name="ctr"></param>
public override bool DoMouseDown(MouseEventArgs e, Control ctr)
{
// keep track of the start point and flag that select initiated.
selectionInitiated_ = true;
startPoint_.X = e.X;
startPoint_.Y = e.Y;
// invalidate the end point
endPoint_ = unset_;
return false;
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
/// <param name="ctr"></param>
/// <param name="lastKeyEventArgs"></param>
public override bool DoMouseMove(MouseEventArgs e, Control ctr, KeyEventArgs lastKeyEventArgs)
{
if ((e.Button == MouseButtons.Left) && selectionInitiated_)
{
// we are here
Point here = new Point(e.X, e.Y);
// delete the previous box
if (endPoint_ != unset_)
{
this.DrawRubberBand(startPoint_, endPoint_, ctr);
}
endPoint_ = here;
// and redraw the last one
this.DrawRubberBand(startPoint_, endPoint_, ctr);
}
return false;
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
/// <param name="ctr"></param>
public override bool DoMouseUp(MouseEventArgs e, Control ctr)
{
NPlot.PlotSurface2D ps = ((Windows.PlotSurface2D)ctr).Inner;
// handle left button (selecting region).
if ((e.Button == MouseButtons.Left) && selectionInitiated_)
{
endPoint_.X = e.X;
endPoint_.Y = e.Y;
// flag stopped selecting.
selectionInitiated_ = false;
if (endPoint_ != unset_)
{
this.DrawRubberBand(startPoint_, endPoint_, ctr);
}
Point minPoint = new Point(0, 0);
minPoint.X = Math.Min(startPoint_.X, endPoint_.X);
minPoint.Y = Math.Min(startPoint_.Y, endPoint_.Y);
Point maxPoint = new Point(0, 0);
maxPoint.X = Math.Max(startPoint_.X, endPoint_.X);
maxPoint.Y = Math.Max(startPoint_.Y, endPoint_.Y);
Rectangle r = ps.PlotAreaBoundingBoxCache;
if (minPoint != maxPoint && (r.Contains(minPoint) || r.Contains(maxPoint)))
{
((Windows.PlotSurface2D)ctr).CacheAxes();
((Windows.PlotSurface2D)ctr).PhysicalXAxis1Cache.SetWorldLimitsFromPhysical(minPoint, maxPoint);
((Windows.PlotSurface2D)ctr).PhysicalXAxis2Cache.SetWorldLimitsFromPhysical(minPoint, maxPoint);
((Windows.PlotSurface2D)ctr).PhysicalYAxis1Cache.SetWorldLimitsFromPhysical(maxPoint, minPoint);
((Windows.PlotSurface2D)ctr).PhysicalYAxis2Cache.SetWorldLimitsFromPhysical(maxPoint, minPoint);
// reset the start/end points
startPoint_ = unset_;
endPoint_ = unset_;
((Windows.PlotSurface2D)ctr).InteractionOccured(this);
return true;
}
}
return false;
}
/// <summary>
/// Draws a rectangle representing selection area.
/// </summary>
/// <param name="start">a corner of the rectangle.</param>
/// <param name="end">a corner of the rectangle diagonally opposite the first.</param>
/// <param name="ctr">The control to draw to - this may not be us, if we have
/// been contained by a PlotSurface.</param>
private void DrawRubberBand(Point start, Point end, System.Windows.Forms.Control ctr)
{
NPlot.PlotSurface2D ps = ((Windows.PlotSurface2D)ctr).Inner;
Rectangle rect = new Rectangle();
// the clipping rectangle in screen coordinates
Rectangle clip = ctr.RectangleToScreen(
new Rectangle(
(int)ps.PlotAreaBoundingBoxCache.X,
(int)ps.PlotAreaBoundingBoxCache.Y,
(int)ps.PlotAreaBoundingBoxCache.Width,
(int)ps.PlotAreaBoundingBoxCache.Height));
// convert to screen coords
start = ctr.PointToScreen(start);
end = ctr.PointToScreen(end);
// now, "normalize" the rectangle
if (start.X < end.X)
{
rect.X = start.X;
rect.Width = end.X - start.X;
}
else
{
rect.X = end.X;
rect.Width = start.X - end.X;
}
if (start.Y < end.Y)
{
rect.Y = start.Y;
rect.Height = end.Y - start.Y;
}
else
{
rect.Y = end.Y;
rect.Height = start.Y - end.Y;
}
rect = Rectangle.Intersect(rect, clip);
ControlPaint.DrawReversibleFrame(
new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height),
Color.White, FrameStyle.Dashed);
}
private Point startPoint_ = new Point(-1, -1);
private Point endPoint_ = new Point(-1, -1);
// this is the condition for an unset point
private Point unset_ = new Point(-1, -1);
}
#endregion
#region HorizontalGuideline
/// <summary>
/// Horizontal line interaction
/// </summary>
public class HorizontalGuideline : Interaction
{
private int barPos_;
private Color color_;
/// <summary>
/// Constructor
/// </summary>
public HorizontalGuideline()
{
color_ = Color.Black;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="lineColor"></param>
public HorizontalGuideline(Color lineColor)
{
color_ = lineColor;
}
/// <summary>
///
/// </summary>
/// <param name="pe"></param>
/// <param name="width"></param>
/// <param name="height"></param>
public override void DoPaint(PaintEventArgs pe, int width, int height)
{
barPos_ = -1;
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
/// <param name="ctr"></param>
/// <param name="lastKeyEventArgs"></param>
public override bool DoMouseMove(MouseEventArgs e, System.Windows.Forms.Control ctr, KeyEventArgs lastKeyEventArgs)
{
NPlot.PlotSurface2D ps = ((Windows.PlotSurface2D)ctr).Inner;
// if mouse isn't in plot region, then don't draw horizontal line
if (e.X > ps.PlotAreaBoundingBoxCache.Left && e.X < ps.PlotAreaBoundingBoxCache.Right &&
e.Y > ps.PlotAreaBoundingBoxCache.Top && e.Y < (ps.PlotAreaBoundingBoxCache.Bottom-1))
{
if (ps.PhysicalXAxis1Cache != null)
{
// the clipping rectangle in screen coordinates
Rectangle clip = ctr.RectangleToScreen(
new Rectangle(
(int)ps.PlotAreaBoundingBoxCache.X,
(int)ps.PlotAreaBoundingBoxCache.Y,
(int)ps.PlotAreaBoundingBoxCache.Width,
(int)ps.PlotAreaBoundingBoxCache.Height));
Point p = ctr.PointToScreen(new Point(e.X, e.Y));
if (barPos_ != -1)
{
ControlPaint.DrawReversibleLine(
new Point(clip.Left, barPos_),
new Point(clip.Right, barPos_), color_);
}
if (p.Y < clip.Bottom && p.Y > clip.Top)
{
ControlPaint.DrawReversibleLine(
new Point(clip.Left, p.Y),
new Point(clip.Right, p.Y), color_);
barPos_ = p.Y;
}
else
{
barPos_ = -1;
}
}
}
else
{
if (barPos_ != -1)
{
Rectangle clip = ctr.RectangleToScreen(
new Rectangle(
(int)ps.PlotAreaBoundingBoxCache.X,
(int)ps.PlotAreaBoundingBoxCache.Y,
(int)ps.PlotAreaBoundingBoxCache.Width,
(int)ps.PlotAreaBoundingBoxCache.Height) );
ControlPaint.DrawReversibleLine(
new Point(clip.Left, barPos_),
new Point(clip.Right, barPos_), color_);
barPos_ = -1;
}
}
return false;
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
/// <param name="ctr"></param>
/// <returns></returns>
public override bool DoMouseLeave(EventArgs e, System.Windows.Forms.Control ctr)
{
if (barPos_ != -1)
{
NPlot.PlotSurface2D ps = ((Windows.PlotSurface2D)ctr).Inner;
Rectangle clip = ctr.RectangleToScreen(
new Rectangle(
(int)ps.PlotAreaBoundingBoxCache.X,
(int)ps.PlotAreaBoundingBoxCache.Y,
(int)ps.PlotAreaBoundingBoxCache.Width,
(int)ps.PlotAreaBoundingBoxCache.Height));
ControlPaint.DrawReversibleLine(
new Point(clip.Left, barPos_),
new Point(clip.Right, barPos_), color_);
barPos_ = -1;
}
return false;
}
}
#endregion
#region VerticalGuideline
/// <summary>
///
/// </summary>
public class VerticalGuideline : Interaction
{
private int barPos_;
private Color color_;
/// <summary>
///
/// </summary>
public VerticalGuideline()
{
color_ = Color.Black;
}
/// <summary>
///
/// </summary>
/// <param name="lineColor"></param>
public VerticalGuideline(Color lineColor)
{
color_ = lineColor;
}
/// <summary>
///
/// </summary>
/// <param name="pe"></param>
/// <param name="width"></param>
/// <param name="height"></param>
public override void DoPaint(PaintEventArgs pe, int width, int height)
{
barPos_ = -1;
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
/// <param name="ctr"></param>
/// <param name="lastKeyEventArgs"></param>
public override bool DoMouseMove(MouseEventArgs e, System.Windows.Forms.Control ctr, KeyEventArgs lastKeyEventArgs)
{
NPlot.PlotSurface2D ps = ((Windows.PlotSurface2D)ctr).Inner;
// if mouse isn't in plot region, then don't draw horizontal line
if (e.X > ps.PlotAreaBoundingBoxCache.Left && e.X < (ps.PlotAreaBoundingBoxCache.Right-1) &&
e.Y > ps.PlotAreaBoundingBoxCache.Top && e.Y < ps.PlotAreaBoundingBoxCache.Bottom)
{
if (ps.PhysicalXAxis1Cache != null)
{
// the clipping rectangle in screen coordinates
Rectangle clip = ctr.RectangleToScreen(
new Rectangle(
(int)ps.PlotAreaBoundingBoxCache.X,
(int)ps.PlotAreaBoundingBoxCache.Y,
(int)ps.PlotAreaBoundingBoxCache.Width,
(int)ps.PlotAreaBoundingBoxCache.Height));
Point p = ctr.PointToScreen(new Point(e.X, e.Y));
if (barPos_ != -1)
{
ControlPaint.DrawReversibleLine(
new Point(barPos_, clip.Top),
new Point(barPos_, clip.Bottom), color_);
}
if (p.X < clip.Right && p.X > clip.Left)
{
ControlPaint.DrawReversibleLine(
new Point(p.X, clip.Top),
new Point(p.X, clip.Bottom), color_);
barPos_ = p.X;
}
else
{
barPos_ = -1;
}
}
}
else
{
if (barPos_ != -1)
{
Rectangle clip = ctr.RectangleToScreen(
new Rectangle(
(int)ps.PlotAreaBoundingBoxCache.X,
(int)ps.PlotAreaBoundingBoxCache.Y,
(int)ps.PlotAreaBoundingBoxCache.Width,
(int)ps.PlotAreaBoundingBoxCache.Height)
);
ControlPaint.DrawReversibleLine(
new Point(barPos_, clip.Top),
new Point(barPos_, clip.Bottom), color_);
barPos_ = -1;
}
}
return false;
}
/// <summary>
/// Handler for mouse leave event
/// </summary>
/// <param name="e">event args</param>
/// <param name="ctr"></param>
/// <returns></returns>
public override bool DoMouseLeave(EventArgs e, System.Windows.Forms.Control ctr)
{
if (barPos_ != -1)
{
NPlot.PlotSurface2D ps = ((Windows.PlotSurface2D)ctr).Inner;
Rectangle clip = ctr.RectangleToScreen(
new Rectangle(
(int)ps.PlotAreaBoundingBoxCache.X,
(int)ps.PlotAreaBoundingBoxCache.Y,
(int)ps.PlotAreaBoundingBoxCache.Width,
(int)ps.PlotAreaBoundingBoxCache.Height));
ControlPaint.DrawReversibleLine(
new Point(barPos_, clip.Top),
new Point(barPos_, clip.Bottom), color_);
barPos_ = -1;
}
return false;
}
}
#endregion
#region HorizontalDrag
/// <summary>
///
/// </summary>
public class HorizontalDrag : Interaction
{
/// <summary>
///
/// </summary>
/// <param name="e"></param>
/// <param name="ctr"></param>
public override bool DoMouseDown(MouseEventArgs e, Control ctr)
{
NPlot.PlotSurface2D ps = ((Windows.PlotSurface2D)ctr).Inner;
if (e.X > ps.PlotAreaBoundingBoxCache.Left && e.X < (ps.PlotAreaBoundingBoxCache.Right) &&
e.Y > ps.PlotAreaBoundingBoxCache.Top && e.Y < ps.PlotAreaBoundingBoxCache.Bottom)
{
dragInitiated_ = true;
lastPoint_.X = e.X;
lastPoint_.Y = e.Y;
}
return false;
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
/// <param name="ctr"></param>
/// <param name="lastKeyEventArgs"></param>
public override bool DoMouseMove(MouseEventArgs e, Control ctr, KeyEventArgs lastKeyEventArgs)
{
NPlot.PlotSurface2D ps = ((Windows.PlotSurface2D)ctr).Inner;
if ((e.Button == MouseButtons.Left) && dragInitiated_)
{
int diffX = e.X - lastPoint_.X;
((Windows.PlotSurface2D)ctr).CacheAxes();
// original code was using PixelWorldLength of the physical axis
// but it was not working for non-linear axes - the code below works
// in all cases
if (ps.XAxis1 != null)
{
Axis axis = ps.XAxis1;
PointF pMin = ps.PhysicalXAxis1Cache.PhysicalMin;
PointF pMax = ps.PhysicalXAxis1Cache.PhysicalMax;
PointF physicalWorldMin = pMin;
PointF physicalWorldMax = pMax;
physicalWorldMin.X -= diffX;
physicalWorldMax.X -= diffX;
double newWorldMin = axis.PhysicalToWorld(physicalWorldMin, pMin, pMax, false);
double newWorldMax = axis.PhysicalToWorld(physicalWorldMax, pMin, pMax, false);
axis.WorldMin = newWorldMin;
axis.WorldMax = newWorldMax;
}
if (ps.XAxis2 != null)
{
Axis axis = ps.XAxis2;
PointF pMin = ps.PhysicalXAxis2Cache.PhysicalMin;
PointF pMax = ps.PhysicalXAxis2Cache.PhysicalMax;
PointF physicalWorldMin = pMin;
PointF physicalWorldMax = pMax;
physicalWorldMin.X -= diffX;
physicalWorldMax.X -= diffX;
double newWorldMin = axis.PhysicalToWorld(physicalWorldMin, pMin, pMax, false);
double newWorldMax = axis.PhysicalToWorld(physicalWorldMax, pMin, pMax, false);
axis.WorldMin = newWorldMin;
axis.WorldMax = newWorldMax;
}
lastPoint_ = new Point(e.X, e.Y);
((Windows.PlotSurface2D)ctr).InteractionOccured(this);
return true;
}
return false;
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
/// <param name="ctr"></param>
public override bool DoMouseUp(MouseEventArgs e, Control ctr)
{
if ((e.Button == MouseButtons.Left) && dragInitiated_)
{
lastPoint_ = unset_;
dragInitiated_ = false;
}
return false;
}
private bool dragInitiated_ = false;
private Point lastPoint_ = new Point(-1, -1);
// this is the condition for an unset point
private Point unset_ = new Point(-1, -1);
}
#endregion
#region VerticalDrag
/// <summary>
///
/// </summary>
public class VerticalDrag : Interaction
{
/// <summary>
///
/// </summary>
/// <param name="e"></param>
/// <param name="ctr"></param>
public override bool DoMouseDown(MouseEventArgs e, Control ctr)
{
NPlot.PlotSurface2D ps = ((Windows.PlotSurface2D)ctr).Inner;
if (e.X > ps.PlotAreaBoundingBoxCache.Left && e.X < (ps.PlotAreaBoundingBoxCache.Right) &&
e.Y > ps.PlotAreaBoundingBoxCache.Top && e.Y < ps.PlotAreaBoundingBoxCache.Bottom)
{
dragInitiated_ = true;
lastPoint_.X = e.X;
lastPoint_.Y = e.Y;
}
return false;
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
/// <param name="ctr"></param>
/// <param name="lastKeyEventArgs"></param>
public override bool DoMouseMove(MouseEventArgs e, Control ctr, KeyEventArgs lastKeyEventArgs)
{
NPlot.PlotSurface2D ps = ((Windows.PlotSurface2D)ctr).Inner;
if ((e.Button == MouseButtons.Left) && dragInitiated_)
{
int diffY = e.Y - lastPoint_.Y;
((Windows.PlotSurface2D)ctr).CacheAxes();
if (ps.YAxis1 != null)
{
Axis axis = ps.YAxis1;
PointF pMin = ps.PhysicalYAxis1Cache.PhysicalMin;
PointF pMax = ps.PhysicalYAxis1Cache.PhysicalMax;
PointF physicalWorldMin = pMin;
PointF physicalWorldMax = pMax;
physicalWorldMin.Y -= diffY;
physicalWorldMax.Y -= diffY;
double newWorldMin = axis.PhysicalToWorld(physicalWorldMin, pMin, pMax, false);
double newWorldMax = axis.PhysicalToWorld(physicalWorldMax, pMin, pMax, false);
axis.WorldMin = newWorldMin;
axis.WorldMax = newWorldMax;
}
if (ps.YAxis2 != null)
{
Axis axis = ps.YAxis2;
PointF pMin = ps.PhysicalYAxis2Cache.PhysicalMin;
PointF pMax = ps.PhysicalYAxis2Cache.PhysicalMax;
PointF physicalWorldMin = pMin;
PointF physicalWorldMax = pMax;
physicalWorldMin.Y -= diffY;
physicalWorldMax.Y -= diffY;
double newWorldMin = axis.PhysicalToWorld(physicalWorldMin, pMin, pMax, false);
double newWorldMax = axis.PhysicalToWorld(physicalWorldMax, pMin, pMax, false);
axis.WorldMin = newWorldMin;
axis.WorldMax = newWorldMax;
}
lastPoint_ = new Point(e.X, e.Y);
((Windows.PlotSurface2D)ctr).InteractionOccured(this);
return true;
}
return false;
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
/// <param name="ctr"></param>
public override bool DoMouseUp(MouseEventArgs e, Control ctr)
{
if ((e.Button == MouseButtons.Left) && dragInitiated_)
{
lastPoint_ = unset_;
dragInitiated_ = false;
}
return false;
}
private bool dragInitiated_ = false;
private Point lastPoint_ = new Point(-1, -1);
// this is the condition for an unset point
private Point unset_ = new Point(-1, -1);
}
#endregion
#region HorizontalRangeSelection
/// <summary>
/// This plot intraction allows the user to select horizontal regions.
/// </summary>
public class HorizontalRangeSelection : Interaction
{
private bool selectionInitiated_ = false;
private Point startPoint_ = new Point(-1, -1);
private Point endPoint_ = new Point(-1, -1);
private Point previousPoint_ = new Point(-1, -1);
private Point unset_ = new Point(-1, -1);
private int minimumPixelDistanceForSelect_ = 5;
private double smallestAllowedRange_ = double.Epsilon * 100.0;
/// <summary>
/// Default constructor
/// </summary>
public HorizontalRangeSelection()
{
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="smallestAllowedRange">the smallest distance between the selected xmin and xmax for the selection to be performed.</param>
public HorizontalRangeSelection( double smallestAllowedRange )
{
this.smallestAllowedRange_ = smallestAllowedRange;
}
/// <summary>
/// The minimum width of the selected region (in pixels) for the interaction to zoom.
/// </summary>
public int MinimumPixelDistanceForSelect
{
get
{
return minimumPixelDistanceForSelect_;
}
set
{
minimumPixelDistanceForSelect_ = value;
}
}
/// <summary>
/// The smallest range (distance between world min and world max) selectable.
/// If a smaller region is selected, the selection will do nothing.
/// </summary>
public double SmallestAllowedRange
{
get
{
return smallestAllowedRange_;
}
set
{
smallestAllowedRange_ = value;
}
}
/// <summary>
/// Handler for mouse down event for this interaction
/// </summary>
/// <param name="e">the mouse event args</param>
/// <param name="ctr">the plot surface this event applies to</param>
public override bool DoMouseDown(MouseEventArgs e, Control ctr )
{
NPlot.PlotSurface2D ps = ((Windows.PlotSurface2D)ctr).Inner;
if (e.X > ps.PlotAreaBoundingBoxCache.Left && e.X < ps.PlotAreaBoundingBoxCache.Right &&
e.Y > ps.PlotAreaBoundingBoxCache.Top && e.Y < ps.PlotAreaBoundingBoxCache.Bottom)
{
// keep track of the start point and flag that select initiated.
selectionInitiated_ = true;
startPoint_.X = e.X;
startPoint_.Y = e.Y;
previousPoint_.X = e.X;
previousPoint_.Y = e.Y;
// invalidate the end point
endPoint_ = unset_;
return false;
}
selectionInitiated_ = false;
endPoint_ = unset_;
startPoint_ = unset_;
return false;
}
/// <summary>
/// Handler for mouse move event for this interaction
/// </summary>
/// <param name="e">the mouse event args</param>
/// <param name="ctr">the plot surface this event applies to</param>
/// <param name="lastKeyEventArgs"></param>
public override bool DoMouseMove(MouseEventArgs e, Control ctr, KeyEventArgs lastKeyEventArgs)
{
NPlot.PlotSurface2D ps = ((Windows.PlotSurface2D)ctr).Inner;
// if dragging on axis to zoom.
if ((e.Button == MouseButtons.Left) && selectionInitiated_)
{
Point endPoint_ = previousPoint_;
if (e.X > ps.PlotAreaBoundingBoxCache.Left && e.X < ps.PlotAreaBoundingBoxCache.Right &&
e.Y > ps.PlotAreaBoundingBoxCache.Top && e.Y < ps.PlotAreaBoundingBoxCache.Bottom)
{
endPoint_ = new Point(e.X, e.Y);
this.DrawHorizontalSelection(previousPoint_, endPoint_, ctr);
previousPoint_ = endPoint_;
}
else
{
endPoint_ = new Point(e.X, e.Y);
if (e.X < ps.PlotAreaBoundingBoxCache.Left) endPoint_.X = ps.PlotAreaBoundingBoxCache.Left + 1;
if (e.X > ps.PlotAreaBoundingBoxCache.Right) endPoint_.X = ps.PlotAreaBoundingBoxCache.Right - 1;
this.DrawHorizontalSelection(previousPoint_, endPoint_, ctr);
previousPoint_ = endPoint_;
}
}
return false;
}
/// <summary>
/// Handler for mouse up event for this interaction
/// </summary>
/// <param name="e">the mouse event args</param>
/// <param name="ctr">the plot surface this event applies to</param>
public override bool DoMouseUp(MouseEventArgs e, Control ctr)
{
NPlot.PlotSurface2D ps = ((Windows.PlotSurface2D)ctr).Inner;
if ((e.Button == MouseButtons.Left) && selectionInitiated_)
{
endPoint_.X = e.X;
endPoint_.Y = e.Y;
if (e.X < ps.PlotAreaBoundingBoxCache.Left) endPoint_.X = ps.PlotAreaBoundingBoxCache.Left + 1;
if (e.X > ps.PlotAreaBoundingBoxCache.Right) endPoint_.X = ps.PlotAreaBoundingBoxCache.Right - 1;
// flag stopped selecting.
selectionInitiated_ = false;
if (endPoint_ != unset_)
{
this.DrawHorizontalSelection(startPoint_, endPoint_, ctr);
}
// ignore very small selections
if (Math.Abs(endPoint_.X - startPoint_.X) < minimumPixelDistanceForSelect_)
{
return false;
}
((Windows.PlotSurface2D)ctr).CacheAxes();
// determine the new x axis 1 world limits (and check to see if they are far enough appart).
double xAxis1Min = double.NaN;
double xAxis1Max = double.NaN;
if (ps.XAxis1 != null)
{
int x1 = (int)Math.Min(endPoint_.X, startPoint_.X);
int x2 = (int)Math.Max(endPoint_.X, startPoint_.X);
int y = ps.PhysicalXAxis1Cache.PhysicalMax.Y;
xAxis1Min = ps.PhysicalXAxis1Cache.PhysicalToWorld(new Point(x1, y), true);
xAxis1Max = ps.PhysicalXAxis1Cache.PhysicalToWorld(new Point(x2, y), true);
if (xAxis1Max - xAxis1Min < this.smallestAllowedRange_)
{
return false;
}
}
// determine the new x axis 2 world limits (and check to see if they are far enough appart).
double xAxis2Min = double.NaN;
double xAxis2Max = double.NaN;
if (ps.XAxis2 != null)
{
int x1 = (int)Math.Min(endPoint_.X, startPoint_.X);
int x2 = (int)Math.Max(endPoint_.X, startPoint_.X);
int y = ps.PhysicalXAxis2Cache.PhysicalMax.Y;
xAxis2Min = ps.PhysicalXAxis2Cache.PhysicalToWorld(new Point(x1, y), true);
xAxis2Max = ps.PhysicalXAxis2Cache.PhysicalToWorld(new Point(x2, y), true);
if (xAxis2Max - xAxis2Min < smallestAllowedRange_)
{
return false;
}
}
// now actually update the world limits.
if (ps.XAxis1 != null)
{
ps.XAxis1.WorldMax = xAxis1Max;
ps.XAxis1.WorldMin = xAxis1Min;
}
if (ps.XAxis2 != null)
{
ps.XAxis2.WorldMax = xAxis2Max;
ps.XAxis2.WorldMin = xAxis2Min;
}
((Windows.PlotSurface2D)ctr).InteractionOccured(this);
return true;
}
return false;
}
private void DrawHorizontalSelection(Point start, Point end, System.Windows.Forms.Control ctr)
{
NPlot.PlotSurface2D ps = ((Windows.PlotSurface2D)ctr).Inner;
// the clipping rectangle in screen coordinates
Rectangle clip = ctr.RectangleToScreen(
new Rectangle(
(int)ps.PlotAreaBoundingBoxCache.X,
(int)ps.PlotAreaBoundingBoxCache.Y,
(int)ps.PlotAreaBoundingBoxCache.Width,
(int)ps.PlotAreaBoundingBoxCache.Height));
start = ctr.PointToScreen(start);
end = ctr.PointToScreen(end);
ControlPaint.FillReversibleRectangle(
new Rectangle((int)Math.Min(start.X, end.X), (int)clip.Y, (int)Math.Abs(end.X - start.X), (int)clip.Height),
Color.White);
}
}
#endregion
#region AxisDrag
/// <summary>
///
/// </summary>
public class AxisDrag : Interaction
{
/// <summary>
///
/// </summary>
/// <param name="enableDragWithCtr"></param>
public AxisDrag(bool enableDragWithCtr)
{
enableDragWithCtr_ = enableDragWithCtr;
}
private bool enableDragWithCtr_ = false;
private Axis axis_ = null;
private bool doing_ = false;
private Point lastPoint_ = new Point();
private PhysicalAxis physicalAxis_ = null;
private Point startPoint_ = new Point();
/// <summary>
///
/// </summary>
/// <param name="e"></param>
/// <param name="ctr"></param>
public override bool DoMouseDown(MouseEventArgs e, Control ctr)
{
// if the mouse is inside the plot area [the tick marks are here and part of the
// axis], then don't invoke drag.
NPlot.PlotSurface2D ps = ((Windows.PlotSurface2D)ctr).Inner;
if (e.X > ps.PlotAreaBoundingBoxCache.Left && e.X < ps.PlotAreaBoundingBoxCache.Right &&
e.Y > ps.PlotAreaBoundingBoxCache.Top && e.Y < ps.PlotAreaBoundingBoxCache.Bottom)
{
return false;
}
if ((e.Button == MouseButtons.Left))
{
// see if hit with axis.
ArrayList objects = ps.HitTest(new Point(e.X, e.Y));
foreach (object o in objects)
{
if (o is NPlot.Axis)
{
doing_ = true;
axis_ = (Axis)o;
PhysicalAxis[] physicalAxisList = new PhysicalAxis[] { ps.PhysicalXAxis1Cache, ps.PhysicalXAxis2Cache, ps.PhysicalYAxis1Cache, ps.PhysicalYAxis2Cache };
if (ps.PhysicalXAxis1Cache.Axis == axis_)
physicalAxis_ = ps.PhysicalXAxis1Cache;
else if (ps.PhysicalXAxis2Cache.Axis == axis_)
physicalAxis_ = ps.PhysicalXAxis2Cache;
else if (ps.PhysicalYAxis1Cache.Axis == axis_)
physicalAxis_ = ps.PhysicalYAxis1Cache;
else if (ps.PhysicalYAxis2Cache.Axis == axis_)
physicalAxis_ = ps.PhysicalYAxis2Cache;
lastPoint_ = startPoint_ = new Point(e.X, e.Y);
return false;
}
}
}
return false;
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
/// <param name="ctr"></param>
/// <param name="lastKeyEventArgs"></param>
public override bool DoMouseMove(MouseEventArgs e, Control ctr, KeyEventArgs lastKeyEventArgs)
{
NPlot.PlotSurface2D ps = ((Windows.PlotSurface2D)ctr).Inner;
// if dragging on axis to zoom.
if ((e.Button == MouseButtons.Left) && doing_ && physicalAxis_ != null)
{
if (enableDragWithCtr_ && lastKeyEventArgs != null && lastKeyEventArgs.Control)
{
}
else
{
float dist =
(e.X - lastPoint_.X) +
(-e.Y + lastPoint_.Y);
lastPoint_ = new Point(e.X, e.Y);
if (dist > sensitivity_ / 3.0f)
{
dist = sensitivity_ / 3.0f;
}
PointF pMin = physicalAxis_.PhysicalMin;
PointF pMax = physicalAxis_.PhysicalMax;
double physicalWorldLength = Math.Sqrt((pMax.X - pMin.X) * (pMax.X - pMin.X) + (pMax.Y - pMin.Y) * (pMax.Y - pMin.Y));
float prop = (float)(physicalWorldLength * dist / sensitivity_);
prop *= 2;
((Windows.PlotSurface2D)ctr).CacheAxes();
float relativePosX = (startPoint_.X - pMin.X) / (pMax.X - pMin.X);
float relativePosY = (startPoint_.Y - pMin.Y) / (pMax.Y - pMin.Y);
if (float.IsInfinity(relativePosX) || float.IsNaN(relativePosX)) relativePosX = 0.0f;
if (float.IsInfinity(relativePosY) || float.IsNaN(relativePosY)) relativePosY = 0.0f;
PointF physicalWorldMin = pMin;
PointF physicalWorldMax = pMax;
physicalWorldMin.X += relativePosX * prop;
physicalWorldMax.X -= (1 - relativePosX) * prop;
physicalWorldMin.Y -= relativePosY * prop;
physicalWorldMax.Y += (1 - relativePosY) * prop;
double newWorldMin = axis_.PhysicalToWorld(physicalWorldMin, pMin, pMax, false);
double newWorldMax = axis_.PhysicalToWorld(physicalWorldMax, pMin, pMax, false);
axis_.WorldMin = newWorldMin;
axis_.WorldMax = newWorldMax;
((Windows.PlotSurface2D)ctr).InteractionOccured(this);
return true;
}
}
return false;
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
/// <param name="ctr"></param>
public override bool DoMouseUp(MouseEventArgs e, Control ctr)
{
if (doing_)
{
doing_ = false;
axis_ = null;
physicalAxis_ = null;
lastPoint_ = new Point();
}
return false;
}
private float sensitivity_ = 200.0f;
/// <summary>
///
/// </summary>
/// <value></value>
public float Sensitivity
{
get
{
return sensitivity_;
}
set
{
sensitivity_ = value;
}
}
}
#endregion
#region MouseWheelZoom
/// <summary>
///
/// </summary>
public class MouseWheelZoom : Interaction
{
private Point point_ = new Point(-1, -1);
//private bool mouseDown_ = false;
/// <summary>
///
/// </summary>
/// <param name="e"></param>
/// <param name="ctr"></param>
public override bool DoMouseUp(MouseEventArgs e, Control ctr)
{
//mouseDown_ = false;
return false;
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
/// <param name="ctr"></param>
public override bool DoMouseDown(MouseEventArgs e, Control ctr)
{
//NPlot.PlotSurface2D ps = ((Windows.PlotSurface2D)ctr).Inner;
//if (e.X > ps.PlotAreaBoundingBoxCache.Left && e.X < ps.PlotAreaBoundingBoxCache.Right &&
// e.Y > ps.PlotAreaBoundingBoxCache.Top && e.Y < ps.PlotAreaBoundingBoxCache.Bottom)
//{
// point_.X = e.X;
// point_.Y = e.Y;
// mouseDown_ = true;
//}
return false;
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
/// <param name="ctr"></param>
public override bool DoMouseWheel(MouseEventArgs e, Control ctr)
{
NPlot.PlotSurface2D ps = ((Windows.PlotSurface2D)ctr).Inner;
((Windows.PlotSurface2D)ctr).CacheAxes();
float delta = (float)e.Delta / (float)e.Delta;
delta *= sensitivity_;
Axis axis = null;
PointF pMin = PointF.Empty;
PointF pMax = PointF.Empty;
KeyEventArgs keyArgs = ((Windows.PlotSurface2D)ctr).lastKeyEventArgs_;
bool zoom = (keyArgs != null && keyArgs.Control);
if (keyArgs != null && keyArgs.Shift)
{
axis = ps.YAxis1;
pMin = ps.PhysicalYAxis1Cache.PhysicalMin;
pMax = ps.PhysicalYAxis1Cache.PhysicalMax;
}
else
{
axis = ps.XAxis1;
pMin = ps.PhysicalXAxis1Cache.PhysicalMin;
pMax = ps.PhysicalXAxis1Cache.PhysicalMax;
}
if (axis == null) return false;
PointF physicalWorldMin = pMin;
PointF physicalWorldMax = pMax;
physicalWorldMin.X -= delta;
physicalWorldMax.X -= (zoom) ? -delta : delta;
physicalWorldMin.Y += delta;
physicalWorldMax.Y += (zoom) ? -delta : delta;
double newWorldMin = axis.PhysicalToWorld(physicalWorldMin, pMin, pMax, false);
double newWorldMax = axis.PhysicalToWorld(physicalWorldMax, pMin, pMax, false);
axis.WorldMin = newWorldMin;
axis.WorldMax = newWorldMax;
((Windows.PlotSurface2D)ctr).InteractionOccured(this);
return true;
}
/// <summary>
/// Number of screen pixels equivalent to one wheel step.
/// </summary>
public float Sensitivity
{
get
{
return sensitivity_;
}
set
{
sensitivity_ = value;
}
}
private float sensitivity_ = 60.0f;
}
#endregion
}
private ArrayList interactions_ = new ArrayList();
/// <summary>
/// Adds and interaction to the plotsurface that adds functionality that responds
/// to a set of mouse / keyboard events.
/// </summary>
/// <param name="i">the interaction to add.</param>
public void AddInteraction(Interactions.Interaction i)
{
interactions_.Add(i);
}
/// <summary>
/// Remove a previously added interaction
/// </summary>
/// <param name="i">interaction to remove</param>
public void RemoveInteraction(Interactions.Interaction i)
{
interactions_.Remove(i);
}
/// <summary>
/// This is the signature of the function used for InteractionOccurred events.
///
/// TODO: expand this to include information about the event.
/// </summary>
/// <param name="sender"></param>
public delegate void InteractionHandler(object sender);
/// <summary>
/// Event is fired when an interaction happens with the plot that causes it to be modified.
/// </summary>
public event InteractionHandler InteractionOccured;
/// <summary>
/// Default function called when plotsurface modifying interaction occured.
///
/// Override this, or add method to InteractionOccured event.
/// </summary>
/// <param name="sender"></param>
protected void OnInteractionOccured(object sender)
{
// do nothing.
}
/// <summary>
/// This is the signature of the function used for PreRefresh events.
/// </summary>
/// <param name="sender"></param>
public delegate void PreRefreshHandler(object sender);
/// <summary>
/// Event fired when we are about to paint.
/// </summary>
public event PreRefreshHandler PreRefresh;
/// <summary>
/// Default function called just before a refresh happens.
/// </summary>
/// <param name="sender"></param>
protected void OnPreRefresh(object sender)
{
// do nothing.
}
#region class PlotContextMenu
/// <summary>
/// Summary description for ContextMenu.
/// </summary>
public class PlotContextMenu
{
#region IPlotMenuItem
/// <summary>
/// elements of the MenuItems array list must implement this interface.
/// </summary>
public interface IPlotMenuItem
{
/// <summary>
/// Gets the Windows.Forms.MenuItem associated with the PlotMenuItem
/// </summary>
System.Windows.Forms.MenuItem MenuItem { get; }
/// <summary>
/// This method is called for each menu item before the menu is
/// displayed. It is useful for implementing check marks, disabling
/// etc.
/// </summary>
/// <param name="plotContextMenu"></param>
void OnPopup( PlotContextMenu plotContextMenu );
}
#endregion
#region PlotMenuSeparator
/// <summary>
/// A plot menu item for separators.
/// </summary>
public class PlotMenuSeparator : IPlotMenuItem
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="index"></param>
public PlotMenuSeparator( int index )
{
menuItem_ = new System.Windows.Forms.MenuItem();
index_ = index;
menuItem_.Index = index_;
menuItem_.Text = "-";
}
private int index_;
/// <summary>
/// Index of this menu item in the menu.
/// </summary>
public int Index
{
get
{
return index_;
}
}
private System.Windows.Forms.MenuItem menuItem_;
/// <summary>
/// The Windows.Forms.MenuItem associated with this IPlotMenuItem
/// </summary>
public System.Windows.Forms.MenuItem MenuItem
{
get
{
return menuItem_;
}
}
/// <summary>
///
/// </summary>
/// <param name="plotContextMenu"></param>
public void OnPopup( PlotContextMenu plotContextMenu )
{
// do nothing.
}
}
#endregion
#region PlotMenuItem
/// <summary>
/// A Plot menu item suitable for specifying basic menu items
/// </summary>
public class PlotMenuItem : IPlotMenuItem
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="text">Menu item text</param>
/// <param name="index">Index in the manu</param>
/// <param name="callback">EventHandler to call if menu selected.</param>
public PlotMenuItem( string text, int index, EventHandler callback )
{
text_ = text;
index_ = index;
callback_ = callback;
menuItem_ = new System.Windows.Forms.MenuItem();
menuItem_.Index = index;
menuItem_.Text = text;
menuItem_.Click += new System.EventHandler(callback);
}
private string text_;
/// <summary>
/// The text to put in the menu for this menu item.
/// </summary>
public string Text
{
get
{
return text_;
}
}
private int index_;
/// <summary>
/// Index of this menu item in the menu.
/// </summary>
public int Index
{
get
{
return index_;
}
}
private EventHandler callback_;
/// <summary>
/// EventHandler to call if menu selected.
/// </summary>
public EventHandler Callback
{
get
{
return callback_;
}
}
private System.Windows.Forms.MenuItem menuItem_;
/// <summary>
/// The Windows.Forms.MenuItem associated with this IPlotMenuItem
/// </summary>
public System.Windows.Forms.MenuItem MenuItem
{
get
{
return menuItem_;
}
}
/// <summary>
/// Called before menu drawn.
/// </summary>
/// <param name="plotContextMenu">The plot menu this item is a member of.</param>
public virtual void OnPopup( PlotContextMenu plotContextMenu )
{
// do nothing.
}
}
#endregion
#region PlotZoomBackMenuItem
/// <summary>
/// A Plot Menu Item that provides necessary functionality for the
/// zoom back menu item (graying out if zoomed right out in addition
/// to basic functionality).
/// </summary>
public class PlotZoomBackMenuItem : PlotMenuItem
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="text">Text associated with this item in the menu.</param>
/// <param name="index">Index of this item in the menu.</param>
/// <param name="callback">EventHandler to call when menu item is selected.</param>
public PlotZoomBackMenuItem( string text, int index, EventHandler callback )
: base( text, index, callback )
{
}
/// <summary>
/// Called before menu drawn.
/// </summary>
/// <param name="plotContextMenu">The plot menu this item is a member of.</param>
public override void OnPopup( PlotContextMenu plotContextMenu )
{
this.MenuItem.Enabled = plotContextMenu.plotSurface2D_.xAxis1ZoomCache_ != null;
}
}
#endregion
#region PlotShowCoordinatesMenuItem
/// <summary>
/// A Plot Menu Item that provides necessary functionality for the
/// show coordinates menu item (tick mark toggle in addition to basic
/// functionality).
/// </summary>
public class PlotShowCoordinatesMenuItem : PlotMenuItem
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="text">Text associated with this item in the menu.</param>
/// <param name="index">Index of this item in the menu.</param>
/// <param name="callback">EventHandler to call when menu item is selected.</param>
public PlotShowCoordinatesMenuItem( string text, int index, EventHandler callback )
: base( text, index, callback )
{
}
/// <summary>
/// Called before menu drawn.
/// </summary>
/// <param name="plotContextMenu">The plot menu this item is a member of.</param>
public override void OnPopup( PlotContextMenu plotContextMenu )
{
this.MenuItem.Checked = plotContextMenu.plotSurface2D_.ShowCoordinates;
}
}
#endregion
private System.Windows.Forms.ContextMenu rightMenu_ = null;
private ArrayList menuItems_ = null;
/// <summary>
/// Gets an arraylist of all PlotMenuItems that comprise the
/// menu. If this list is changed, this class must be told to
/// update using the Update method.
/// </summary>
public ArrayList MenuItems
{
get
{
return menuItems_;
}
}
/// <summary>
/// The PlotSurface2D associated with the context menu. Generally, the user
/// should not set this. It is used internally by PlotSurface2D.
/// </summary>
public Windows.PlotSurface2D PlotSurface2D
{
set
{
this.plotSurface2D_ = value;
}
}
/// <summary>
/// The PlotSurface2D associated with the context menu. Classes inherited
/// from PlotContextMenu will likely use this to implement their functionality.
/// </summary>
protected Windows.PlotSurface2D plotSurface2D_;
/// <summary>
/// Sets the context menu according to the IPlotMenuItem's in the provided
/// ArrayList. The current menu items can be obtained using the MenuItems
/// property and extended if desired.
/// </summary>
/// <param name="menuItems"></param>
public void SetMenuItems(ArrayList menuItems)
{
this.menuItems_ = menuItems;
this.rightMenu_ = new System.Windows.Forms.ContextMenu();
foreach (IPlotMenuItem item in menuItems_)
{
this.rightMenu_.MenuItems.Add( item.MenuItem );
}
this.rightMenu_.Popup += new System.EventHandler(this.rightMenu__Popup);
}
/// <summary>
/// Constructor creates
/// </summary>
public PlotContextMenu()
{
ArrayList menuItems = new ArrayList();
menuItems = new ArrayList();
menuItems.Add( new PlotZoomBackMenuItem( "Original Dimensions", 0, new EventHandler(this.mnuOriginalDimensions_Click) ) );
menuItems.Add( new PlotShowCoordinatesMenuItem( "Show World Coordinates", 1, new EventHandler(this.mnuDisplayCoordinates_Click) ) );
menuItems.Add( new PlotMenuSeparator(2) );
menuItems.Add( new PlotMenuItem( "Print", 3, new EventHandler(this.mnuPrint_Click )) );
menuItems.Add( new PlotMenuItem( "Print Preview", 4, new EventHandler(this.mnuPrintPreview_Click) ) );
menuItems.Add( new PlotMenuItem( "Copy To Clipboard", 5, new EventHandler(this.mnuCopyToClipboard_Click) ) );
menuItems.Add( new PlotMenuItem( "Copy Data To Clipboard", 6, new EventHandler(this.mnuCopyDataToClipboard_Click) ) );
this.SetMenuItems( menuItems );
}
private void mnuOriginalDimensions_Click(object sender, System.EventArgs e)
{
plotSurface2D_.OriginalDimensions();
}
private void mnuCopyToClipboard_Click(object sender, System.EventArgs e)
{
plotSurface2D_.CopyToClipboard();
}
private void mnuCopyDataToClipboard_Click(object sender, System.EventArgs e)
{
plotSurface2D_.CopyDataToClipboard();
}
private void mnuPrint_Click(object sender, System.EventArgs e)
{
plotSurface2D_.Print( false );
}
private void mnuPrintPreview_Click(object sender, System.EventArgs e)
{
plotSurface2D_.Print( true );
}
private void mnuDisplayCoordinates_Click(object sender, System.EventArgs e)
{
plotSurface2D_.ShowCoordinates = !plotSurface2D_.ShowCoordinates;
}
private void rightMenu__Popup(object sender, System.EventArgs e)
{
foreach (IPlotMenuItem item in menuItems_)
{
item.OnPopup( this );
}
}
/// <summary>
/// Gets the Windows.Forms context menu managed by this object.
/// </summary>
public System.Windows.Forms.ContextMenu Menu
{
get
{
return rightMenu_;
}
}
}
#endregion
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if( components != null )
components.Dispose();
}
base.Dispose( disposing );
}
private System.ComponentModel.IContainer components;
}
}