//============================================================================
//ZedGraph Class Library - A Flexible Line Graph/Bar Graph Library in C#
//Copyright � 2004 John Champion
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//=============================================================================
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Drawing.Imaging;
using System.Drawing.Printing;
using System.Data;
using System.Globalization;
using System.IO;
using System.Resources;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace ZedGraph
{
/*
/// <summary>
///
/// </summary>
public struct DrawingThreadData
{
/// <summary>
///
/// </summary>
public Graphics _g;
/// <summary>
///
/// </summary>
public MasterPane _masterPane;
// public DrawingThread( Graphics g, MasterPane masterPane )
// {
// _g = g;
// _masterPane = masterPane;
// }
}
*/
/// <summary>
/// The ZedGraphControl class provides a UserControl interface to the
/// <see cref="ZedGraph"/> class library. This allows ZedGraph to be installed
/// as a control in the Visual Studio toolbox. You can use the control by simply
/// dragging it onto a form in the Visual Studio form editor. All graph
/// attributes are accessible via the <see cref="ZedGraphControl.GraphPane"/>
/// property.
/// </summary>
/// <author> John Champion revised by Jerry Vos </author>
/// <version> $Revision: 3.80 $ $Date: 2007/02/18 05:51:54 $ </version>
public class ZedGraphControl : System.Windows.Forms.UserControl
{
private System.ComponentModel.IContainer components;
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.hScrollBar1 = new System.Windows.Forms.HScrollBar();
this.vScrollBar1 = new System.Windows.Forms.VScrollBar();
this.contextMenu = new System.Windows.Forms.ContextMenu();
this.pointToolTip = new System.Windows.Forms.ToolTip(this.components);
this.SuspendLayout();
//
// hScrollBar1
//
this.hScrollBar1.Location = new System.Drawing.Point(0, 128);
this.hScrollBar1.Name = "hScrollBar1";
this.hScrollBar1.Size = new System.Drawing.Size(128, 17);
this.hScrollBar1.TabIndex = 0;
this.hScrollBar1.Scroll += new System.Windows.Forms.ScrollEventHandler(this.hScrollBar1_Scroll);
//
// vScrollBar1
//
this.vScrollBar1.Location = new System.Drawing.Point(128, 0);
this.vScrollBar1.Name = "vScrollBar1";
this.vScrollBar1.Size = new System.Drawing.Size(17, 128);
this.vScrollBar1.TabIndex = 1;
this.vScrollBar1.Scroll += new System.Windows.Forms.ScrollEventHandler(this.vScrollBar1_Scroll);
//
// contextMenu
//
this.contextMenu.Popup += new System.EventHandler(this.ContextMenu_Popup);
//
// pointToolTip
//
this.pointToolTip.AutoPopDelay = 5000;
this.pointToolTip.InitialDelay = 100;
this.pointToolTip.ReshowDelay = 0;
//
// ZedGraphControl
//
this.ContextMenu = this.contextMenu;
this.Controls.Add(this.vScrollBar1);
this.Controls.Add(this.hScrollBar1);
this.Name = "ZedGraphControl";
this.MouseWheel += new System.Windows.Forms.MouseEventHandler( this.ZedGraphControl_MouseWheel );
this.Resize += new System.EventHandler(this.ZedGraphControl_ReSize);
this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.ZedGraphControl_KeyUp);
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ZedGraphControl_KeyDown);
this.ResumeLayout(false);
}
#endregion
#region Private Fields
/// <summary>
/// This private field contains the instance for the MasterPane object of this control.
/// You can access the MasterPane object through the public property
/// <see cref="ZedGraphControl.MasterPane"/>. This is nulled when this Control is
/// disposed.
/// </summary>
private MasterPane _masterPane;
/// <summary>
/// private field that determines if anti-aliased drawing will be forced on. Use the
/// public property <see cref="ZedGraphControl.IsAntiAlias"/> to access this value.
/// </summary>
private bool _isAntiAlias = false;
/// <summary>
/// private field that determines whether or not tooltips will be displayed
/// when the mouse hovers over data values. Use the public property
/// <see cref="IsShowPointValues"/> to access this value.
/// </summary>
private bool _isShowPointValues = false;
/// <summary>
/// private field that determines whether or not tooltips will be displayed
/// showing the scale values while the mouse is located within the ChartRect.
/// Use the public property <see cref="IsShowCursorValues"/> to access this value.
/// </summary>
private bool _isShowCursorValues = false;
/// <summary>
/// private field that determines the format for displaying tooltip values.
/// This format is passed to <see cref="PointPairBase.ToString(string)"/>.
/// Use the public property <see cref="PointValueFormat"/> to access this
/// value.
/// </summary>
private string _pointValueFormat = PointPair.DefaultFormat;
/// <summary>
/// private field that determines whether or not the context menu will be available. Use the
/// public property <see cref="IsShowContextMenu"/> to access this value.
/// </summary>
private bool _isShowContextMenu = true;
/// <summary>
/// private field that determines whether or not a message box will be shown in response to
/// a context menu "Copy" command. Use the
/// public property <see cref="IsShowCopyMessage"/> to access this value.
/// </summary>
/// <remarks>
/// Note that, if this value is set to false, the user will receive no indicative feedback
/// in response to a Copy action.
/// </remarks>
private bool _isShowCopyMessage = true;
private SaveFileDialog _saveFileDialog = new SaveFileDialog();
/// <summary>
/// private field that determines whether the settings of
/// <see cref="ZedGraph.PaneBase.IsFontsScaled" /> and <see cref="PaneBase.IsPenWidthScaled" />
/// will be overridden to true during printing operations.
/// </summary>
/// <remarks>
/// Printing involves pixel maps that are typically of a dramatically different dimension
/// than on-screen pixel maps. Therefore, it becomes more important to scale the fonts and
/// lines to give a printed image that looks like what is shown on-screen. The default
/// setting for <see cref="ZedGraph.PaneBase.IsFontsScaled" /> is true, but the default
/// setting for <see cref="PaneBase.IsPenWidthScaled" /> is false.
/// </remarks>
/// <value>
/// A value of true will cause both <see cref="ZedGraph.PaneBase.IsFontsScaled" /> and
/// <see cref="PaneBase.IsPenWidthScaled" /> to be temporarily set to true during
/// printing operations.
/// </value>
private bool _isPrintScaleAll = true;
/// <summary>
/// private field that determines whether or not the visible aspect ratio of the
/// <see cref="MasterPane" /> <see cref="PaneBase.Rect" /> will be preserved
/// when printing this <see cref="ZedGraphControl" />.
/// </summary>
private bool _isPrintKeepAspectRatio = true;
/// <summary>
/// private field that determines whether or not the <see cref="MasterPane" />
/// <see cref="PaneBase.Rect" /> dimensions will be expanded to fill the
/// available space when printing this <see cref="ZedGraphControl" />.
/// </summary>
/// <remarks>
/// If <see cref="IsPrintKeepAspectRatio" /> is also true, then the <see cref="MasterPane" />
/// <see cref="PaneBase.Rect" /> dimensions will be expanded to fit as large
/// a space as possible while still honoring the visible aspect ratio.
/// </remarks>
private bool _isPrintFillPage = true;
/// <summary>
/// private field that determines the format for displaying tooltip date values.
/// This format is passed to <see cref="XDate.ToString(string)"/>.
/// Use the public property <see cref="PointDateFormat"/> to access this
/// value.
/// </summary>
private string _pointDateFormat = XDate.DefaultFormatStr;
/// <summary>
/// private value that determines whether or not zooming is enabled for the control in the
/// vertical direction. Use the public property <see cref="IsEnableVZoom"/> to access this
/// value.
/// </summary>
private bool _isEnableVZoom = true;
/// <summary>
/// private value that determines whether or not zooming is enabled for the control in the
/// horizontal direction. Use the public property <see cref="IsEnableHZoom"/> to access this
/// value.
/// </summary>
private bool _isEnableHZoom = true;
/// <summary>
/// private value that determines whether or not point editing is enabled in the
/// vertical direction. Use the public property <see cref="IsEnableVEdit"/> to access this
/// value.
/// </summary>
private bool _isEnableVEdit = false;
/// <summary>
/// private value that determines whether or not point editing is enabled in the
/// horizontal direction. Use the public property <see cref="IsEnableHEdit"/> to access this
/// value.
/// </summary>
private bool _isEnableHEdit = false;
/// <summary>
/// private value that determines whether or not panning is allowed for the control in the
/// horizontal direction. Use the
/// public property <see cref="IsEnableHPan"/> to access this value.
/// </summary>
private bool _isEnableHPan = true;
/// <summary>
/// private value that determines whether or not panning is allowed for the control in the
/// vertical direction. Use the
/// public property <see cref="IsEnableVPan"/> to access this value.
/// </summary>
private bool _isEnableVPan = true;
// Revision: JCarpenter 10/06
/// <summary>
/// Internal variable that indicates if the control can manage selections.
/// </summary>
private bool _isEnableSelection = false;
private double _zoomStepFraction = 0.1;
private ScrollRange _xScrollRange;
private ScrollRangeList _yScrollRangeList;
private ScrollRangeList _y2ScrollRangeList;
private bool _isShowHScrollBar = false;
private bool _isShowVScrollBar = false;
//private bool isScrollY2 = false;
private bool _isAutoScrollRange = false;
private double _scrollGrace = 0.00; //0.05;
private bool _isSynchronizeXAxes = false;
private bool _isSynchronizeYAxes = false;
//private System.Windows.Forms.HScrollBar hScrollBar1;
//private System.Windows.Forms.VScrollBar vScrollBar1;
// The range of values to use the scroll control bars
private const int _ScrollControlSpan = int.MaxValue;
// The ratio of the largeChange to the smallChange for the scroll bars
private const int _ScrollSmallRatio = 10;
private bool _isZoomOnMouseCenter = false;
private ResourceManager _resourceManager;
/// <summary>
/// private field that stores a <see cref="PrintDocument" /> instance, which maintains
/// a persistent selection of printer options.
/// </summary>
/// <remarks>
/// This is needed so that a "Print" action utilizes the settings from a prior
/// "Page Setup" action.</remarks>
private PrintDocument _pdSave = null;
//private PrinterSettings printSave = null;
//private PageSettings pageSave = null;
/// <summary>
/// This private field contains a list of selected CurveItems.
/// </summary>
//private List<CurveItem> _selection = new List<CurveItem>();
private Selection _selection = new Selection();
#endregion
#region Fields: Buttons & Keys Properties
/// <summary>
/// Gets or sets a value that determines which Mouse button will be used to click on
/// linkable objects
/// </summary>
/// <seealso cref="LinkModifierKeys" />
private MouseButtons _linkButtons = MouseButtons.Left;
/// <summary>
/// Gets or sets a value that determines which modifier keys will be used to click
/// on linkable objects
/// </summary>
/// <seealso cref="LinkButtons" />
private Keys _linkModifierKeys = Keys.Alt;
/// <summary>
/// Gets or sets a value that determines which Mouse button will be used to edit point
/// data values
/// </summary>
/// <remarks>
/// This setting only applies if <see cref="IsEnableHEdit" /> and/or
/// <see cref="IsEnableVEdit" /> are true.
/// </remarks>
/// <seealso cref="EditModifierKeys" />
private MouseButtons _editButtons = MouseButtons.Right;
/// <summary>
/// Gets or sets a value that determines which modifier keys will be used to edit point
/// data values
/// </summary>
/// <remarks>
/// This setting only applies if <see cref="IsEnableHEdit" /> and/or
/// <see cref="IsEnableVEdit" /> are true.
/// </remarks>
/// <seealso cref="EditButtons" />
private Keys _editModifierKeys = Keys.Alt;
/// <summary>
/// Gets or sets a value that determines which mouse button will be used to select
/// <see cref="CurveItem" />'s.
/// </summary>
/// <remarks>
/// This setting only applies if <see cref="IsEnableSelection" /> is true.
/// </remarks>
/// <seealso cref="SelectModifierKeys" />
private MouseButtons _selectButtons = MouseButtons.Left;
/// <summary>
/// Gets or sets a value that determines which modifier keys will be used to select
/// <see cref="CurveItem" />'s.
/// </summary>
/// <remarks>
/// This setting only applies if <see cref="IsEnableSelection" /> is true.
/// </remarks>
/// <seealso cref="SelectButtons" />
private Keys _selectModifierKeys = Keys.Shift;
private Keys _selectAppendModifierKeys = Keys.Shift | Keys.Control;
/// <summary>
/// Gets or sets a value that determines which Mouse button will be used to perform
/// zoom operations
/// </summary>
/// <remarks>
/// This setting only applies if <see cref="IsEnableHZoom" /> and/or
/// <see cref="IsEnableVZoom" /> are true.
/// </remarks>
/// <seealso cref="ZoomModifierKeys" />
/// <seealso cref="ZoomButtons2" />
/// <seealso cref="ZoomModifierKeys2" />
private MouseButtons _zoomButtons = MouseButtons.Left;
/// <summary>
/// Gets or sets a value that determines which modifier keys will be used to perform
/// zoom operations
/// </summary>
/// <remarks>
/// This setting only applies if <see cref="IsEnableHZoom" /> and/or
/// <see cref="IsEnableVZoom" /> are true.
/// </remarks>
/// <seealso cref="ZoomButtons" />
/// <seealso cref="ZoomButtons2" />
/// <seealso cref="ZoomModifierKeys2" />
private Keys _zoomModifierKeys = Keys.None;
/// <summary>
/// Gets or sets a value that determines which Mouse button will be used as a
/// secondary option to perform zoom operations
/// </summary>
/// <remarks>
/// This setting only applies if <see cref="IsEnableHZoom" /> and/or
/// <see cref="IsEnableVZoom" /> are true.
/// </remarks>
/// <seealso cref="ZoomModifierKeys2" />
/// <seealso cref="ZoomButtons" />
/// <seealso cref="ZoomModifierKeys" />
private MouseButtons _zoomButtons2 = MouseButtons.None;
/// <summary>
/// Gets or sets a value that determines which modifier keys will be used as a
/// secondary option to perform zoom operations
/// </summary>
/// <remarks>
/// This setting only applies if <see cref="IsEnableHZoom" /> and/or
/// <see cref="IsEnableVZoom" /> are true.
/// </remarks>
/// <seealso cref="ZoomButtons" />
/// <seealso cref="ZoomButtons2" />
/// <seealso cref="ZoomModifierKeys2" />
private Keys _zoomModifierKeys2 = Keys.None;
/// <summary>
/// Gets or sets a value that determines which Mouse button will be used to perform
/// panning operations
/// </summary>
/// <remarks>
/// This setting only applies if <see cref="IsEnableHPan" /> and/or
/// <see cref="IsEnableVPan" /> are true. A Pan operation (dragging the graph with
/// the mouse) should not be confused with a scroll operation (using a scroll bar to
/// move the graph).
/// </remarks>
/// <seealso cref="PanModifierKeys" />
/// <seealso cref="PanButtons2" />
/// <seealso cref="PanModifierKeys2" />
private MouseButtons _panButtons = MouseButtons.Left;
// Setting this field to Keys.Shift here
// causes an apparent bug to crop up in VS 2003, by which it will have the value:
// "System.Windows.Forms.Keys.Shift+None", which won't compile
/// <summary>
/// Gets or sets a value that determines which modifier keys will be used to perform
/// panning operations
/// </summary>
/// <remarks>
/// This setting only applies if <see cref="IsEnableHPan" /> and/or
/// <see cref="IsEnableVPan" /> are true. A Pan operation (dragging the graph with
/// the mouse) should not be confused with a scroll operation (using a scroll bar to
/// move the graph).
/// </remarks>
/// <seealso cref="PanButtons" />
/// <seealso cref="PanButtons2" />
/// <seealso cref="PanModifierKeys2" />
private Keys _panModifierKeys = Keys.Control;
/// <summary>
/// Gets or sets a value that determines which Mouse button will be used as a
/// secondary option to perform panning operations
/// </summary>
/// <remarks>
/// This setting only applies if <see cref="IsEnableHPan" /> and/or
/// <see cref="IsEnableVPan" /> are true. A Pan operation (dragging the graph with
/// the mouse) should not be confused with a scroll operation (using a scroll bar to
/// move the graph).
/// </remarks>
/// <seealso cref="PanModifierKeys2" />
/// <seealso cref="PanButtons" />
/// <seealso cref="PanModifierKeys" />
private MouseButtons _panButtons2 = MouseButtons.Middle;
// Setting this field to Keys.Shift here
// causes an apparent bug to crop up in VS 2003, by which it will have the value:
// "System.Windows.Forms.Keys.Shift+None", which won't compile
/// <summary>
/// Gets or sets a value that determines which modifier keys will be used as a
/// secondary option to perform panning operations
/// </summary>
/// <remarks>
/// This setting only applies if <see cref="IsEnableHPan" /> and/or
/// <see cref="IsEnableVPan" /> are true. A Pan operation (dragging the graph with
/// the mouse) should not be confused with a scroll operation (using a scroll bar to
/// move the graph).
/// </remarks>
/// <seealso cref="PanButtons2" />
/// <seealso cref="PanButtons" />
/// <seealso cref="PanModifierKeys" />
private Keys _panModifierKeys2 = Keys.None;
#endregion
#region Button and Key Properties
/// <summary>
/// Gets or sets a value that determines which mouse button will be used as a primary option
/// to trigger a zoom event.
/// </summary>
/// <remarks>
/// This value is combined with <see cref="ZoomModifierKeys"/> to determine the actual zoom combination.
/// A secondary zoom button/key combination option is available via <see cref="ZoomButtons2"/> and
/// <see cref="ZoomModifierKeys2"/>. To not use this button/key combination, set the value
/// of <see cref="ZoomButtons"/> to <see cref="MouseButtons.None"/>.
/// </remarks>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue(MouseButtons.Left),
Description( "Determines which mouse button is used as the primary for zooming" )]
public MouseButtons ZoomButtons
{
get { return _zoomButtons; }
set { _zoomButtons = value; }
}
/// <summary>
/// Gets or sets a value that determines which mouse button will be used as the secondary option
/// to trigger a zoom event.
/// </summary>
/// <remarks>
/// This value is combined with <see cref="ZoomModifierKeys2"/> to determine the actual zoom combination.
/// The primary zoom button/key combination option is available via <see cref="ZoomButtons"/> and
/// <see cref="ZoomModifierKeys"/>. To not use this button/key combination, set the value
/// of <see cref="ZoomButtons2"/> to <see cref="MouseButtons.None"/>.
/// </remarks>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue(MouseButtons.None),
Description( "Determines which mouse button is used as the secondary for zooming" )]
public MouseButtons ZoomButtons2
{
get { return _zoomButtons2; }
set { _zoomButtons2 = value; }
}
/// <summary>
/// Gets or sets a value that determines which modifier keys will be used as a primary option
/// to trigger a zoom event.
/// </summary>
/// <remarks>
/// This value is combined with <see cref="ZoomButtons"/> to determine the actual zoom combination.
/// A secondary zoom button/key combination option is available via <see cref="ZoomButtons2"/> and
/// <see cref="ZoomModifierKeys2"/>. To not use this button/key combination, set the value
/// of <see cref="ZoomButtons"/> to <see cref="MouseButtons.None"/>.
/// </remarks>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( Keys.None ),
Description( "Determines which modifier key used as the primary for zooming" )]
public Keys ZoomModifierKeys
{
get { return _zoomModifierKeys; }
set { _zoomModifierKeys = value; }
}
/// <summary>
/// Gets or sets a value that determines which modifier keys will be used as a secondary option
/// to trigger a zoom event.
/// </summary>
/// <remarks>
/// This value is combined with <see cref="ZoomButtons2"/> to determine the actual zoom combination.
/// A primary zoom button/key combination option is available via <see cref="ZoomButtons"/> and
/// <see cref="ZoomModifierKeys"/>. To not use this button/key combination, set the value
/// of <see cref="ZoomButtons2"/> to <see cref="MouseButtons.None"/>.
/// </remarks>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( Keys.None ),
Description( "Determines which modifier key used as the secondary for zooming" )]
public Keys ZoomModifierKeys2
{
get { return _zoomModifierKeys2; }
set { _zoomModifierKeys2 = value; }
}
/// <summary>
/// Gets or sets a value that determines which mouse button will be used as a primary option
/// to trigger a pan event.
/// </summary>
/// <remarks>
/// This value is combined with <see cref="PanModifierKeys"/> to determine the actual pan combination.
/// A secondary pan button/key combination option is available via <see cref="PanButtons2"/> and
/// <see cref="PanModifierKeys2"/>. To not use this button/key combination, set the value
/// of <see cref="PanButtons"/> to <see cref="MouseButtons.None"/>.
/// </remarks>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( MouseButtons.Left ),
Description( "Determines which mouse button is used as the primary for panning" )]
public MouseButtons PanButtons
{
get { return _panButtons; }
set { _panButtons = value; }
}
/// <summary>
/// Gets or sets a value that determines which mouse button will be used as the secondary option
/// to trigger a pan event.
/// </summary>
/// <remarks>
/// This value is combined with <see cref="PanModifierKeys2"/> to determine the actual pan combination.
/// The primary pan button/key combination option is available via <see cref="PanButtons"/> and
/// <see cref="PanModifierKeys"/>. To not use this button/key combination, set the value
/// of <see cref="PanButtons2"/> to <see cref="MouseButtons.None"/>.
/// </remarks>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( MouseButtons.Middle ),
Description( "Determines which mouse button is used as the secondary for panning" )]
public MouseButtons PanButtons2
{
get { return _panButtons2; }
set { _panButtons2 = value; }
}
// NOTE: The default value of PanModifierKeys is Keys.Shift. Because of an apparent bug in
// VS 2003, the initial value set in InitializeComponent by the code wizard is "Keys.Shift+None"
// which will not compile. As a temporary workaround, I've hidden the value so that it won't
// have compile errors. This problem does not exist in VS 2005.
/// <summary>
/// Gets or sets a value that determines which modifier keys will be used as a primary option
/// to trigger a pan event.
/// </summary>
/// <remarks>
/// This value is combined with <see cref="PanButtons"/> to determine the actual pan combination.
/// A secondary pan button/key combination option is available via <see cref="PanButtons2"/> and
/// <see cref="PanModifierKeys2"/>. To not use this button/key combination, set the value
/// of <see cref="PanButtons"/> to <see cref="MouseButtons.None"/>.
/// </remarks>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( Keys.Control ),
Description( "Determines which modifier key is used as the primary for panning" )]
public Keys PanModifierKeys
{
get { return _panModifierKeys; }
set { _panModifierKeys = value; }
}
/// <summary>
/// Gets or sets a value that determines which modifier keys will be used as a secondary option
/// to trigger a pan event.
/// </summary>
/// <remarks>
/// This value is combined with <see cref="PanButtons2"/> to determine the actual pan combination.
/// A primary pan button/key combination option is available via <see cref="PanButtons"/> and
/// <see cref="PanModifierKeys"/>. To not use this button/key combination, set the value
/// of <see cref="PanButtons2"/> to <see cref="MouseButtons.None"/>.
/// </remarks>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( Keys.None ),
Description( "Determines which modifier key is used as the secondary for panning" )]
public Keys PanModifierKeys2
{
get { return _panModifierKeys2; }
set { _panModifierKeys2 = value; }
}
/// <summary>
/// Gets or sets a value that determines which Mouse button will be used to edit point
/// data values
/// </summary>
/// <remarks>
/// This setting only applies if <see cref="IsEnableHEdit" /> and/or
/// <see cref="IsEnableVEdit" /> are true.
/// </remarks>
/// <seealso cref="EditModifierKeys" />
[Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( MouseButtons.Right ),
Description( "Specify mouse button for point editing" )]
public MouseButtons EditButtons
{
get { return _editButtons; }
set { _editButtons = value; }
}
/// <summary>
/// Gets or sets a value that determines which modifier keys will be used to edit point
/// data values
/// </summary>
/// <remarks>
/// This setting only applies if <see cref="IsEnableHEdit" /> and/or
/// <see cref="IsEnableVEdit" /> are true.
/// </remarks>
/// <seealso cref="EditButtons" />
[Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( Keys.Alt ),
Description( "Specify modifier key for point editing" )]
public Keys EditModifierKeys
{
get { return _editModifierKeys; }
set { _editModifierKeys = value; }
}
/// <summary>
/// Gets or sets a value that determines which Mouse button will be used to
/// select <see cref="CurveItem" />'s.
/// </summary>
/// <remarks>
/// This setting only applies if <see cref="IsEnableSelection" /> is true.
/// </remarks>
/// <seealso cref="SelectModifierKeys" />
[Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( MouseButtons.Left ),
Description( "Specify mouse button for curve selection" )]
public MouseButtons SelectButtons
{
get { return _selectButtons; }
set { _selectButtons = value; }
}
/// <summary>
/// Gets or sets a value that determines which Modifier keys will be used to
/// select <see cref="CurveItem" />'s.
/// </summary>
/// <remarks>
/// This setting only applies if <see cref="IsEnableSelection" /> is true.
/// </remarks>
/// <seealso cref="SelectButtons" />
[Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( Keys.Shift ),
Description( "Specify modifier key for curve selection" )]
public Keys SelectModifierKeys
{
get { return _selectModifierKeys; }
set { _selectModifierKeys = value; }
}
/// <summary>
/// Gets or sets a value that determines which Modifier keys will be used to
/// append a <see cref="CurveItem" /> to the selection list.
/// </summary>
[Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( Keys.Shift | Keys.Alt ),
Description( "Specify modifier key for append curve selection" )]
public Keys SelectAppendModifierKeys
{
get { return _selectAppendModifierKeys; }
}
/// <summary>
/// Gets or sets a value that determines which Mouse button will be used to click
/// on linkable objects
/// </summary>
/// <seealso cref="LinkModifierKeys" />
/// <seealso cref="LinkEvent"/>
// /// <seealso cref="ZedGraph.Web.IsImageMap"/>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( MouseButtons.Left ),
Description( "Specify mouse button for clicking on linkable objects" )]
public MouseButtons LinkButtons
{
get { return _linkButtons; }
set { _linkButtons = value; }
}
/// <summary>
/// Gets or sets a value that determines which modifier keys will be used to click
/// on linkable objects
/// </summary>
/// <seealso cref="LinkButtons" />
/// <seealso cref="LinkEvent"/>
// /// <seealso cref="ZedGraph.Web.IsImageMap"/>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( Keys.Alt ),
Description( "Specify modifier key for clicking on linkable objects" )]
public Keys LinkModifierKeys
{
get { return _linkModifierKeys; }
set { _linkModifierKeys = value; }
}
#endregion
#region Fields: Temporary state variables
/// <summary>
/// Internal variable that indicates the control is currently being zoomed.
/// </summary>
private bool _isZooming = false;
/// <summary>
/// Internal variable that indicates the control is currently being panned.
/// </summary>
private bool _isPanning = false;
/// <summary>
/// Internal variable that indicates a point value is currently being edited.
/// </summary>
private bool _isEditing = false;
// Revision: JCarpenter 10/06
/// <summary>
/// Internal variable that indicates the control is currently using selection.
/// </summary>
private bool _isSelecting = false;
/// <summary>
/// Internal variable that stores the <see cref="GraphPane"/> reference for the Pane that is
/// currently being zoomed or panned.
/// </summary>
private GraphPane _dragPane = null;
/// <summary>
/// Internal variable that stores a rectangle which is either the zoom rectangle, or the incremental
/// pan amount since the last mousemove event.
/// </summary>
private Point _dragStartPt;
private Point _dragEndPt;
private int _dragIndex;
private CurveItem _dragCurve;
private PointPair _dragStartPair;
/// <summary>
/// private field that stores the state of the scale ranges prior to starting a panning action.
/// </summary>
private ZoomState _zoomState;
private ZoomStateStack _zoomStateStack;
private System.Windows.Forms.HScrollBar hScrollBar1;
private System.Windows.Forms.VScrollBar vScrollBar1;
private System.Windows.Forms.ToolTip pointToolTip;
private System.Windows.Forms.ContextMenu contextMenu;
//temporarily save the location of a context menu click so we can use it for reference
// Note that Control.MousePosition ends up returning the position after the mouse has
// moved to the menu item within the context menu. Therefore, this point is saved so
// that we have the point at which the context menu was first right-clicked
internal Point _menuClickPt;
#endregion
#region Events
/// <summary>
/// A delegate that allows subscribing methods to append or modify the context menu.
/// </summary>
/// <param name="sender">The source <see cref="ZedGraphControl"/> object</param>
/// <param name="menu">A reference to the <see cref="ContextMenu"/> object
/// that contains the context menu.
/// </param>
/// <param name="mousePt">The point at which the mouse was clicked</param>
/// <param name="objState">The current context menu state</param>
/// <seealso cref="ContextMenuBuilder" />
public delegate void ContextMenuBuilderEventHandler( ZedGraphControl sender,
ContextMenu menu, Point mousePt, ContextMenuObjectState objState );
/// <summary>
/// Subscribe to this event to be able to modify the ZedGraph context menu.
/// </summary>
/// <remarks>
/// The context menu is built on the fly after a right mouse click. You can add menu items
/// to this menu by simply modifying the <see paramref="menu"/> parameter.
/// </remarks>
[ Bindable( true ), Category( "Events" ),
Description( "Subscribe to this event to be able to modify the ZedGraph context menu" )]
public event ContextMenuBuilderEventHandler ContextMenuBuilder;
/// <summary>
/// A delegate that allows notification of zoom and pan events.
/// </summary>
/// <param name="sender">The source <see cref="ZedGraphControl"/> object</param>
/// <param name="oldState">A <see cref="ZoomState"/> object that corresponds to the state of the
/// <see cref="GraphPane"/> before the zoom or pan event.</param>
/// <param name="newState">A <see cref="ZoomState"/> object that corresponds to the state of the
/// <see cref="GraphPane"/> after the zoom or pan event</param>
/// <seealso cref="ZoomEvent" />
public delegate void ZoomEventHandler( ZedGraphControl sender, ZoomState oldState,
ZoomState newState );
/// <summary>
/// Subscribe to this event to be notified when the <see cref="GraphPane"/> is zoomed or panned by the user,
/// either via a mouse drag operation or by the context menu commands.
/// </summary>
[ Bindable( true ), Category( "Events" ),
Description( "Subscribe to this event to be notified when the graph is zoomed or panned" )]
public event ZoomEventHandler ZoomEvent;
/// <summary>
/// A delegate that allows notification of scroll events.
/// </summary>
/// <param name="sender">The source <see cref="ZedGraphControl"/> object</param>
/// <param name="scrollBar">The source <see cref="ScrollBar"/> object</param>
/// <param name="oldState">A <see cref="ZoomState"/> object that corresponds to the state of the
/// <see cref="GraphPane"/> before the scroll event.</param>
/// <param name="newState">A <see cref="ZoomState"/> object that corresponds to the state of the
/// <see cref="GraphPane"/> after the scroll event</param>
/// <seealso cref="ZoomEvent" />
public delegate void ScrollDoneHandler( ZedGraphControl sender, ScrollBar scrollBar,
ZoomState oldState, ZoomState newState );
// This event is not supported for .Net 1.1 since the Scroll Capture event cannot be captured.
// /// <summary>
// /// Subscribe to this event to be notified when the <see cref="GraphPane"/> is scrolled by the user
// /// using the scrollbars.
// /// </summary>
// [ Bindable( true ), Category( "Events" ),
// Description( "Subscribe this event to be notified when a scroll operation using the scrollbars is completed" )]
// public event ScrollDoneHandler ScrollDoneEvent;
/// <summary>
/// A delegate that allows notification of scroll events.
/// </summary>
/// <param name="sender">The source <see cref="ZedGraphControl"/> object</param>
/// <param name="scrollBar">The source <see cref="ScrollBar"/> object</param>
/// <param name="oldState">A <see cref="ZoomState"/> object that corresponds to the state of the
/// <see cref="GraphPane"/> before the scroll event.</param>
/// <param name="newState">A <see cref="ZoomState"/> object that corresponds to the state of the
/// <see cref="GraphPane"/> after the scroll event</param>
/// <seealso cref="ZoomEvent" />
public delegate void ScrollProgressHandler( ZedGraphControl sender, ScrollBar scrollBar,
ZoomState oldState, ZoomState newState );
/// <summary>
/// Subscribe to this event to be notified when the <see cref="GraphPane"/> is scrolled by the user
/// using the scrollbars.
/// </summary>
[ Bindable( true ), Category( "Events" ),
Description( "Subscribe this event to be notified continuously as a scroll operation is taking place" )]
public event ScrollProgressHandler ScrollProgressEvent;
/// <summary>
/// A delegate that receives notification after a point-edit operation is completed.
/// </summary>
/// <param name="sender">The source <see cref="ZedGraphControl"/> object</param>
/// <param name="pane">The <see cref="GraphPane"/> object that contains the
/// point that has been edited</param>
/// <param name="curve">The <see cref="CurveItem"/> object that contains the point
/// that has been edited</param>
/// <param name="iPt">The integer index of the edited <see cref="PointPair"/> within the
/// <see cref="IPointList"/> of the selected <see cref="CurveItem"/>
/// </param>
/// <seealso cref="PointValueEvent" />
public delegate string PointEditHandler( ZedGraphControl sender, GraphPane pane,
CurveItem curve, int iPt );
/// <summary>
/// Subscribe to this event to receive notifcation and/or respond after a data
/// point has been edited via <see cref="IsEnableHEdit" /> and <see cref="IsEnableVEdit" />.
/// </summary>
/// <example>
/// <para>To subscribe to this event, use the following in your Form_Load method:</para>
/// <code>zedGraphControl1.PointEditEvent +=
/// new ZedGraphControl.PointEditHandler( MyPointEditHandler );</code>
/// <para>Add this method to your Form1.cs:</para>
/// <code>
/// private string MyPointEditHandler( object sender, GraphPane pane, CurveItem curve, int iPt )
/// {
/// PointPair pt = curve[iPt];
/// return "This value is " + pt.Y.ToString("f2") + " gallons";
/// }</code>
/// </example>
[ Bindable( true ), Category( "Events" ),
Description( "Subscribe to this event to respond to data point edit actions" )]
public event PointEditHandler PointEditEvent;
/// <summary>
/// A delegate that allows custom formatting of the point value tooltips
/// </summary>
/// <param name="sender">The source <see cref="ZedGraphControl"/> object</param>
/// <param name="pane">The <see cref="GraphPane"/> object that contains the point value of interest</param>
/// <param name="curve">The <see cref="CurveItem"/> object that contains the point value of interest</param>
/// <param name="iPt">The integer index of the selected <see cref="PointPair"/> within the
/// <see cref="IPointList"/> of the selected <see cref="CurveItem"/></param>
/// <seealso cref="PointValueEvent" />
public delegate string PointValueHandler( ZedGraphControl sender, GraphPane pane,
CurveItem curve, int iPt );
/// <summary>
/// Subscribe to this event to provide custom formatting for the tooltips
/// </summary>
/// <example>
/// <para>To subscribe to this event, use the following in your FormLoad method:</para>
/// <code>zedGraphControl1.PointValueEvent +=
/// new ZedGraphControl.PointValueHandler( MyPointValueHandler );</code>
/// <para>Add this method to your Form1.cs:</para>
/// <code>
/// private string MyPointValueHandler( object sender, GraphPane pane, CurveItem curve, int iPt )
/// {
/// #region
/// PointPair pt = curve[iPt];
/// return "This value is " + pt.Y.ToString("f2") + " gallons";
/// #endregion
/// }</code>
/// </example>
[ Bindable( true ), Category( "Events" ),
Description( "Subscribe to this event to provide custom-formatting for data point tooltips" )]
public event PointValueHandler PointValueEvent;
/// <summary>
/// A delegate that allows notification of mouse events on Graph objects.
/// </summary>
/// <param name="sender">The source <see cref="ZedGraphControl"/> object</param>
/// <param name="e">A <see cref="MouseEventArgs" /> corresponding to this event</param>
/// <seealso cref="MouseDownEvent" />
/// <returns>
/// Return true if you have handled the mouse event entirely, and you do not
/// want the <see cref="ZedGraphControl"/> to do any further action (e.g., starting
/// a zoom operation). Return false if ZedGraph should go ahead and process the
/// mouse event.
/// </returns>
public delegate bool ZedMouseEventHandler( ZedGraphControl sender, MouseEventArgs e );
/// <summary>
/// Subscribe to this event to provide notification of MouseDown clicks on graph
/// objects
/// </summary>
/// <remarks>
/// This event provides for a notification when the mouse is clicked on an object
/// within any <see cref="GraphPane"/> of the <see cref="MasterPane"/> associated
/// with this <see cref="ZedGraphControl" />. This event will use the
/// <see cref="ZedGraph.MasterPane.FindNearestPaneObject"/> method to determine which object
/// was clicked. The boolean value that you return from this handler determines whether
/// or not the <see cref="ZedGraphControl"/> will do any further handling of the
/// MouseDown event (see <see cref="ZedMouseEventHandler" />). Return true if you have
/// handled the MouseDown event entirely, and you do not
/// want the <see cref="ZedGraphControl"/> to do any further action (e.g., starting
/// a zoom operation). Return false if ZedGraph should go ahead and process the
/// MouseDown event.
/// </remarks>
[ Bindable( true ), Category( "Events" ),
Description( "Subscribe to be notified when the left mouse button is clicked down" )]
public event ZedMouseEventHandler MouseDownEvent;
/// <summary>
/// Hide the standard control MouseDown event so that the ZedGraphControl.MouseDownEvent
/// can be used. This is so that the user must return true/false in order to indicate
/// whether or not we should respond to the event.
/// </summary>
[Bindable( false ), Browsable( false )]
public new event MouseEventHandler MouseDown;
/// <summary>
/// Hide the standard control MouseUp event so that the ZedGraphControl.MouseUpEvent
/// can be used. This is so that the user must return true/false in order to indicate
/// whether or not we should respond to the event.
/// </summary>
[Bindable( false ), Browsable( false )]
public new event MouseEventHandler MouseUp;
/// <summary>
/// Hide the standard control MouseMove event so that the ZedGraphControl.MouseMoveEvent
/// can be used. This is so that the user must return true/false in order to indicate
/// whether or not we should respond to the event.
/// </summary>
[Bindable( false ), Browsable( false )]
private new event MouseEventHandler MouseMove;
/// <summary>
/// Subscribe to this event to provide notification of MouseUp clicks on graph
/// objects
/// </summary>
/// <remarks>
/// This event provides for a notification when the mouse is clicked on an object
/// within any <see cref="GraphPane"/> of the <see cref="MasterPane"/> associated
/// with this <see cref="ZedGraphControl" />. This event will use the
/// <see cref="ZedGraph.MasterPane.FindNearestPaneObject"/> method to determine which object
/// was clicked. The boolean value that you return from this handler determines whether
/// or not the <see cref="ZedGraphControl"/> will do any further handling of the
/// MouseUp event (see <see cref="ZedMouseEventHandler" />). Return true if you have
/// handled the MouseUp event entirely, and you do not
/// want the <see cref="ZedGraphControl"/> to do any further action (e.g., starting
/// a zoom operation). Return false if ZedGraph should go ahead and process the
/// MouseUp event.
/// </remarks>
[ Bindable( true ), Category( "Events" ),
Description( "Subscribe to be notified when the left mouse button is released" )]
public event ZedMouseEventHandler MouseUpEvent;
/// <summary>
/// Subscribe to this event to provide notification of MouseMove events over graph
/// objects
/// </summary>
/// <remarks>
/// This event provides for a notification when the mouse is moving over on the control.
/// The boolean value that you return from this handler determines whether
/// or not the <see cref="ZedGraphControl"/> will do any further handling of the
/// MouseMove event (see <see cref="ZedMouseEventHandler" />). Return true if you
/// have handled the MouseMove event entirely, and you do not
/// want the <see cref="ZedGraphControl"/> to do any further action.
/// Return false if ZedGraph should go ahead and process the MouseMove event.
/// </remarks>
[ Bindable( true ), Category( "Events" ),
Description( "Subscribe to be notified when the mouse is moved inside the control" )]
public event ZedMouseEventHandler MouseMoveEvent;
/// <summary>
/// Subscribe to this event to provide notification of Double Clicks on graph
/// objects
/// </summary>
/// <remarks>
/// This event provides for a notification when the mouse is double-clicked on an object
/// within any <see cref="GraphPane"/> of the <see cref="MasterPane"/> associated
/// with this <see cref="ZedGraphControl" />. This event will use the
/// <see cref="ZedGraph.MasterPane.FindNearestPaneObject"/> method to determine which object
/// was clicked. The boolean value that you return from this handler determines whether
/// or not the <see cref="ZedGraphControl"/> will do any further handling of the
/// DoubleClick event (see <see cref="ZedMouseEventHandler" />). Return true if you have
/// handled the DoubleClick event entirely, and you do not
/// want the <see cref="ZedGraphControl"/> to do any further action.
/// Return false if ZedGraph should go ahead and process the
/// DoubleClick event.
/// </remarks>
[ Bindable( true ), Category( "Events" ),
Description( "Subscribe to be notified when the left mouse button is double-clicked" )]
public event ZedMouseEventHandler DoubleClickEvent;
/// <summary>
/// A delegate that allows notification of clicks on ZedGraph objects that have
/// active links enabled
/// </summary>
/// <param name="sender">The source <see cref="ZedGraphControl"/> object</param>
/// <param name="pane">The source <see cref="GraphPane" /> in which the click
/// occurred.
/// </param>
/// <param name="source">The source object which was clicked. This is typically
/// a type of <see cref="CurveItem" /> if a curve point was clicked, or
/// a type of <see cref="GraphObj" /> if a graph object was clicked.
/// </param>
/// <param name="link">The <see cref="Link" /> object, belonging to
/// <paramref name="source" />, that contains the link information
/// </param>
/// <param name="index">An index value, typically used if a <see cref="CurveItem" />
/// was clicked, indicating the ordinal value of the actual point that was clicked.
/// </param>
/// <returns>
/// Return true if you have handled the LinkEvent entirely, and you do not
/// want the <see cref="ZedGraphControl"/> to do any further action.
/// Return false if ZedGraph should go ahead and process the LinkEvent.
/// </returns>
public delegate bool LinkEventHandler( ZedGraphControl sender, GraphPane pane,
object source, Link link, int index );
/// <summary>
/// Subscribe to this event to be able to respond to mouse clicks within linked
/// objects.
/// </summary>
/// <remarks>
/// Linked objects are typically either <see cref="GraphObj" /> type objects or
/// <see cref="CurveItem" /> type objects. These object types can include
/// hyperlink information allowing for "drill-down" type operation.
/// </remarks>
/// <seealso cref="LinkEventHandler"/>
/// <seealso cref="Link" />
/// <seealso cref="CurveItem.Link">CurveItem.Link</seealso>
/// <seealso cref="GraphObj.Link">GraphObj.Link</seealso>
// /// <seealso cref="ZedGraph.Web.IsImageMap" />
[ Bindable( true ), Category( "Events" ),
Description( "Subscribe to be notified when a link-enabled item is clicked" )]
public event LinkEventHandler LinkEvent;
#endregion
#region Constructors
/// <summary>
/// Default Constructor
/// </summary>
public ZedGraphControl()
{
InitializeComponent();
// These commands do nothing, but they get rid of the compiler warnings for
// unused events
bool b = MouseDown == null || MouseUp == null || MouseMove == null;
// Link in these events from the base class, since we disable them from this class.
base.MouseDown += new System.Windows.Forms.MouseEventHandler( this.ZedGraphControl_MouseDown );
base.MouseUp += new System.Windows.Forms.MouseEventHandler( this.ZedGraphControl_MouseUp );
base.MouseMove += new System.Windows.Forms.MouseEventHandler( this.ZedGraphControl_MouseMove );
//this.MouseWheel += new System.Windows.Forms.MouseEventHandler( this.ZedGraphControl_MouseWheel );
// Use double-buffering for flicker-free updating:
SetStyle( ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint
| ControlStyles.DoubleBuffer | ControlStyles.ResizeRedraw, true );
//isTransparentBackground = false;
//SetStyle( ControlStyles.Opaque, false );
SetStyle( ControlStyles.SupportsTransparentBackColor, true );
//this.BackColor = Color.Transparent;
_resourceManager = new ResourceManager( "ZedGraph.ZedGraph_v5.ZedGraphLocale",
Assembly.GetExecutingAssembly() );
Rectangle rect = new Rectangle( 0, 0, this.Size.Width, this.Size.Height );
_masterPane = new MasterPane( "", rect );
_masterPane.Margin.All = 0;
_masterPane.Title.IsVisible = false;
string titleStr = _resourceManager.GetString( "title_def" );
string xStr = _resourceManager.GetString( "x_title_def" );
string yStr = _resourceManager.GetString( "y_title_def" );
//GraphPane graphPane = new GraphPane( rect, "Title", "X Axis", "Y Axis" );
GraphPane graphPane = new GraphPane( rect, titleStr, xStr, yStr );
using ( Graphics g = this.CreateGraphics() )
{
graphPane.AxisChange( g );
//g.Dispose();
}
_masterPane.Add( graphPane );
this.hScrollBar1.Minimum = 0;
this.hScrollBar1.Maximum = 100;
this.hScrollBar1.Value = 0;
this.vScrollBar1.Minimum = 0;
this.vScrollBar1.Maximum = 100;
this.vScrollBar1.Value = 0;
_xScrollRange = new ScrollRange( true );
_yScrollRangeList = new ScrollRangeList();
_y2ScrollRangeList = new ScrollRangeList();
_yScrollRangeList.Add( new ScrollRange( true ) );
_y2ScrollRangeList.Add( new ScrollRange( false ) );
_zoomState = null;
_zoomStateStack = new ZoomStateStack();
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if the components should be
/// disposed, false otherwise</param>
protected override void Dispose( bool disposing )
{
lock ( this )
{
if ( disposing )
{
if ( components != null )
components.Dispose();
}
base.Dispose( disposing );
_masterPane = null;
}
}
#endregion
#region Properties
/// <summary>
/// Gets or sets the <see cref="ZedGraph.MasterPane"/> property for the control
/// </summary>
[ Bindable( false ), Browsable( false ),
DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )]
public MasterPane MasterPane
{
get { lock ( this ) return _masterPane; }
set { lock ( this ) _masterPane = value; }
}
// Testing for Designer attribute
/*
Class1 _class1 = null;
[ Bindable( true ), Browsable( true ), Category( "Data" ), NotifyParentProperty( true ),
DesignerSerializationVisibility( DesignerSerializationVisibility.Content ),
Description( "My Class1 Test" )]
public Class1 Class1
{
get { if ( _class1 == null ) _class1 = new Class1(); return _class1; }
set { _class1 = value; }
}
*/
/// <summary>
/// Gets or sets the <see cref="ZedGraph.GraphPane"/> property for the control
/// </summary>
/// <remarks>
/// <see cref="ZedGraphControl"/> actually uses a <see cref="MasterPane"/> object
/// to hold a list of <see cref="GraphPane"/> objects. This property really only
/// accesses the first <see cref="GraphPane"/> in the list. If there is more
/// than one <see cref="GraphPane"/>, use the <see cref="MasterPane"/>
/// indexer property to access any of the <see cref="GraphPane"/> objects.</remarks>
[
Bindable( false ), Browsable( false ),
DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )
]
//[
// Bindable( true ), Browsable( true ), Category( "Data" ), NotifyParentProperty( true ),
// AttributeProvider( typeof( GraphPane ) ),
// Description("Access to the primary GraphPane object associated with this control")
//]
public GraphPane GraphPane
{
get
{
// Just return the first GraphPane in the list
lock ( this )
{
if ( _masterPane != null && _masterPane.PaneList.Count > 0 )
return _masterPane[0];
else
return null;
}
}
set
{
lock ( this )
{
//Clear the list, and replace it with the specified Graphpane
if ( _masterPane != null )
{
_masterPane.PaneList.Clear();
_masterPane.Add( value );
}
}
}
}
/// <summary>
/// Gets or sets a value that determines if all drawing operations for this control
/// will be forced to operate in Anti-alias mode. Note that if this value is set to
/// "true", it overrides the setting for sub-objects. Otherwise, the sub-object settings
/// (such as <see cref="FontSpec.IsAntiAlias"/>)
/// will be honored.
/// </summary>
[Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( false ),
Description( "true to force all objects to be draw in anti-alias mode" )]
public bool IsAntiAlias
{
get { return _isAntiAlias; }
set { _isAntiAlias = value; }
}
/// <summary>
/// Gets or sets a value that determines whether or not tooltips will be displayed
/// when the mouse hovers over data values.
/// </summary>
/// <remarks>The displayed values are taken from <see cref="PointPair.Tag"/>
/// if it is a <see cref="System.String"/> type, or <see cref="PointPairBase.ToString()"/>
/// otherwise (using the <see cref="PointValueFormat" /> as a format string).
/// Additionally, the user can custom format the values using the
/// <see cref="PointValueEvent" /> event. Note that <see cref="IsShowPointValues" />
/// may be overridden by <see cref="IsShowCursorValues" />.
/// </remarks>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( false ),
Description( "true to display tooltips when the mouse hovers over data points" )]
public bool IsShowPointValues
{
get { return _isShowPointValues; }
set { _isShowPointValues = value; }
}
/// <summary>
/// Gets or sets a value that determines whether or not tooltips will be displayed
/// showing the current scale values when the mouse is within the
/// <see cref="Chart.Rect" />.
/// </summary>
/// <remarks>The displayed values are taken from the current mouse position, and formatted
/// according to <see cref="PointValueFormat" /> and/or <see cref="PointDateFormat" />. If this
/// value is set to true, it overrides the <see cref="IsShowPointValues" /> setting.
/// </remarks>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( false ),
Description( "true to display tooltips showing the current mouse position within the Chart area" )]
public bool IsShowCursorValues
{
get { return _isShowCursorValues; }
set { _isShowCursorValues = value; }
}
/// <summary>
/// Gets or sets a value that determines whether or not editing of point data is allowed in
/// the horizontal direction.
/// </summary>
/// <remarks>
/// Editing is done by holding down the Alt key, and left-clicking on an individual point of
/// a given <see cref="CurveItem" /> to drag it to a new location. The Mouse and Key
/// combination for this mode are modifiable using <see cref="EditButtons" /> and
/// <see cref="EditModifierKeys" />.
/// </remarks>
/// <seealso cref="EditButtons" />
/// <seealso cref="EditModifierKeys" />
/// <seealso cref="IsEnableVEdit" />
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( false ),
Description( "true to allow horizontal editing by alt-left-click-drag" )]
public bool IsEnableHEdit
{
get { return _isEnableHEdit; }
set { _isEnableHEdit = value; }
}
/// <summary>
/// Gets or sets a value that determines whether or not editing of point data is allowed in
/// the vertical direction.
/// </summary>
/// <remarks>
/// Editing is done by holding down the Alt key, and left-clicking on an individual point of
/// a given <see cref="CurveItem" /> to drag it to a new location. The Mouse and Key
/// combination for this mode are modifiable using <see cref="EditButtons" /> and
/// <see cref="EditModifierKeys" />.
/// </remarks>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( false ),
Description( "true to allow vertical editing by alt-left-click-drag" )]
public bool IsEnableVEdit
{
get { return _isEnableVEdit; }
set { _isEnableVEdit = value; }
}
/// <summary>
/// Gets or sets a value that determines whether or not zooming is allowed for the control.
/// </summary>
/// <remarks>
/// Zooming is done by left-clicking inside the <see cref="Chart.Rect"/> to drag
/// out a rectangle, indicating the new scale ranges that will be part of the graph.
/// </remarks>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( true ),
Description( "true to allow horizontal and vertical zooming by left-click-drag" )]
public bool IsEnableZoom
{
set { _isEnableHZoom = value; _isEnableVZoom = value; }
}
/// <summary>
/// Gets or sets a value that determines whether or not zooming is allowed for the control in
/// the horizontal direction.
/// </summary>
/// <remarks>
/// Zooming is done by left-clicking inside the <see cref="Chart.Rect"/> to drag
/// out a rectangle, indicating the new scale ranges that will be part of the graph.
/// </remarks>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( true ),
Description( "true to allow horizontal zooming by left-click-drag" )]
public bool IsEnableHZoom
{
get { return _isEnableHZoom; }
set { _isEnableHZoom = value; }
}
/// <summary>
/// Gets or sets a value that determines whether or not zooming is allowed for the control in
/// the vertical direction.
/// </summary>
/// <remarks>
/// Zooming is done by left-clicking inside the <see cref="Chart.Rect"/> to drag
/// out a rectangle, indicating the new scale ranges that will be part of the graph.
/// </remarks>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( true ),
Description( "true to allow vertical zooming by left-click-drag" )]
public bool IsEnableVZoom
{
get { return _isEnableVZoom; }
set { _isEnableVZoom = value; }
}
/// <summary>
/// Gets or sets a value that determines whether or not panning is allowed for the control in
/// the horizontal direction.
/// </summary>
/// <remarks>
/// Panning is done by clicking the middle mouse button (or holding down the shift key
/// while clicking the left mouse button) inside the <see cref="Chart.Rect"/> and
/// dragging the mouse around to shift the scale ranges as desired.
/// </remarks>
/// <seealso cref="IsEnableVPan"/>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( true ),
Description( "true to allow horizontal panning by middle-mouse-drag or shift-left-drag" )]
public bool IsEnableHPan
{
get { return _isEnableHPan; }
set { _isEnableHPan = value; }
}
/// <summary>
/// Gets or sets a value that determines whether or not panning is allowed for the control in
/// the vertical direction.
/// </summary>
/// <remarks>
/// Panning is done by clicking the middle mouse button (or holding down the shift key
/// while clicking the left mouse button) inside the <see cref="Chart.Rect"/> and
/// dragging the mouse around to shift the scale ranges as desired.
/// </remarks>
/// <seealso cref="IsEnableHPan"/>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( true ),
Description( "true to allow vertical panning by middle-mouse-drag or shift-left-drag" )]
public bool IsEnableVPan
{
get { return _isEnableVPan; }
set { _isEnableVPan = value; }
}
/// <summary>
/// Gets or sets a value that determines whether or not the context menu will be available.
/// </summary>
/// <remarks>The context menu is a menu that appears when you right-click on the
/// <see cref="ZedGraphControl"/>. It provides options for Zoom, Pan, AutoScale, Clipboard
/// Copy, and toggle <see cref="IsShowPointValues"/>.
/// </remarks>
/// <value>true to allow the context menu, false to disable it</value>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( true ),
Description( "true to enable the right mouse button context menu" )]
public bool IsShowContextMenu
{
get { return _isShowContextMenu; }
set { _isShowContextMenu = value; }
}
/// <summary>
/// Gets or sets a value that determines whether or not a message box will be shown
/// in response to a context menu "Copy" command.
/// </summary>
/// <remarks>
/// Note that, if this property is set to false, the user will receive no
/// indicative feedback in response to a Copy action.
/// </remarks>
[Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( true ),
Description( "true to show a message box after a 'Copy' context menu action completes" )]
public bool IsShowCopyMessage
{
get { return _isShowCopyMessage; }
set { _isShowCopyMessage = value; }
}
/// <summary>
/// Gets or sets the <see cref="SaveFileDialog" /> instance that will be used
/// by the "Save As..." context menu item.
/// </summary>
/// <remarks>
/// This provides the opportunity to modify the dialog, such as setting the
/// <see cref="FileDialog.InitialDirectory" /> property.
/// </remarks>
[Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( true ),
Description( "Provides access to the SaveFileDialog for the 'Save As' menu item" )]
public SaveFileDialog SaveFileDialog
{
get { return _saveFileDialog; }
set { _saveFileDialog = value; }
}
/// <summary>
/// Gets or sets a value that determines whether or not the visible aspect ratio of the
/// <see cref="MasterPane" /> <see cref="PaneBase.Rect" /> will be preserved
/// when printing this <see cref="ZedGraphControl" />.
/// </summary>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( true ),
Description( "true to preserve the displayed aspect ratio when printing" )]
public bool IsPrintKeepAspectRatio
{
get { return _isPrintKeepAspectRatio; }
set { _isPrintKeepAspectRatio = value; }
}
/// <summary>
/// Gets or sets a value that determines whether or not the <see cref="MasterPane" />
/// <see cref="PaneBase.Rect" /> dimensions will be expanded to fill the
/// available space when printing this <see cref="ZedGraphControl" />.
/// </summary>
/// <remarks>
/// If <see cref="IsPrintKeepAspectRatio" /> is also true, then the <see cref="MasterPane" />
/// <see cref="PaneBase.Rect" /> dimensions will be expanded to fit as large
/// a space as possible while still honoring the visible aspect ratio.
/// </remarks>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( true ),
Description( "true to resize to fill the page when printing" )]
public bool IsPrintFillPage
{
get { return _isPrintFillPage; }
set { _isPrintFillPage = value; }
}
/// <summary>
/// Gets or sets a value that determines whether the settings of
/// <see cref="ZedGraph.PaneBase.IsFontsScaled" /> and <see cref="PaneBase.IsPenWidthScaled" />
/// will be overridden to true during printing operations.
/// </summary>
/// <remarks>
/// Printing involves pixel maps that are typically of a dramatically different dimension
/// than on-screen pixel maps. Therefore, it becomes more important to scale the fonts and
/// lines to give a printed image that looks like what is shown on-screen. The default
/// setting for <see cref="ZedGraph.PaneBase.IsFontsScaled" /> is true, but the default
/// setting for <see cref="PaneBase.IsPenWidthScaled" /> is false.
/// </remarks>
/// <value>
/// A value of true will cause both <see cref="ZedGraph.PaneBase.IsFontsScaled" /> and
/// <see cref="PaneBase.IsPenWidthScaled" /> to be temporarily set to true during
/// printing operations.
/// </value>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( true ),
Description( "true to force font and pen width scaling when printing" )]
public bool IsPrintScaleAll
{
get { return _isPrintScaleAll; }
set { _isPrintScaleAll = value; }
}
/// <summary>
/// Gets or sets a value that controls whether or not the axis value range for the scroll
/// bars will be set automatically.
/// </summary>
/// <remarks>
/// If this value is set to true, then the range of the scroll bars will be set automatically
/// to the actual range of the data as returned by <see cref="CurveList.GetRange" /> at the
/// time that <see cref="AxisChange" /> was last called. Note that a value of true
/// can override any setting of <see cref="ScrollMinX" />, <see cref="ScrollMaxX" />,
/// <see cref="ScrollMinY" />, <see cref="ScrollMaxY" />,
/// <see cref="ScrollMinY2" />, and <see cref="ScrollMaxY2" />. Note also that you must
/// call <see cref="AxisChange" /> from the <see cref="ZedGraphControl" /> for this to
/// work properly (e.g., don't call it directly from the <see cref="GraphPane" />.
/// Alternatively, you can call <see cref="SetScrollRangeFromData" /> at anytime to set
/// the scroll bar range.<br />
/// <b>In most cases, you will probably want to disable
/// <see cref="ZedGraph.GraphPane.IsBoundedRanges" /> before activating this option.</b>
/// </remarks>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( false ),
Description( "true to automatically set the scroll bar range to the actual data range" )]
public bool IsAutoScrollRange
{
get { return _isAutoScrollRange; }
set { _isAutoScrollRange = value; }
}
/// <summary>
/// Set a "grace" value that leaves a buffer area around the data when
/// <see cref="IsAutoScrollRange" /> is true.
/// </summary>
/// <remarks>
/// This value represents a fraction of the total range around each axis. For example, if the
/// axis ranges from 0 to 100, then a 0.05 value for ScrollGrace would set the scroll range
/// to -5 to 105.
/// </remarks>
public double ScrollGrace
{
get { return _scrollGrace; }
set { _scrollGrace = value; }
}
/// <summary>
/// Gets or sets a value that determines if the horizontal scroll bar will be visible.
/// </summary>
/// <remarks>This scroll bar allows the display to be scrolled in the horizontal direction.
/// Another option is display panning, in which the user can move the display around by
/// clicking directly on it and dragging (see <see cref="IsEnableHPan"/> and <see cref="IsEnableVPan"/>).
/// You can control the available range of scrolling with the <see cref="ScrollMinX"/> and
/// <see cref="ScrollMaxX"/> properties. Note that the scroll range can be set automatically by
/// <see cref="IsAutoScrollRange" />.<br />
/// <b>In most cases, you will probably want to disable
/// <see cref="ZedGraph.GraphPane.IsBoundedRanges" /> before activating this option.</b>
/// </remarks>
/// <value>A boolean value. true to display a horizontal scrollbar, false otherwise.</value>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( false ),
Description( "true to display the horizontal scroll bar" )]
public bool IsShowHScrollBar
{
get { return _isShowHScrollBar; }
set { _isShowHScrollBar = value; ZedGraphControl_ReSize( this, new EventArgs() ); }
}
/// <summary>
/// Gets or sets a value that determines if the vertical scroll bar will be visible.
/// </summary>
/// <remarks>This scroll bar allows the display to be scrolled in the vertical direction.
/// Another option is display panning, in which the user can move the display around by
/// clicking directly on it and dragging (see <see cref="IsEnableHPan"/> and <see cref="IsEnableVPan"/>).
/// You can control the available range of scrolling with the <see cref="ScrollMinY"/> and
/// <see cref="ScrollMaxY"/> properties.
/// Note that the vertical scroll bar only affects the <see cref="YAxis"/>; it has no impact on
/// the <see cref="Y2Axis"/>. The panning options affect both the <see cref="YAxis"/> and
/// <see cref="Y2Axis"/>. Note also that the scroll range can be set automatically by
/// <see cref="IsAutoScrollRange" />.<br />
/// <b>In most cases, you will probably want to disable
/// <see cref="ZedGraph.GraphPane.IsBoundedRanges" /> before activating this option.</b>
/// </remarks>
/// <value>A boolean value. true to display a vertical scrollbar, false otherwise.</value>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( false ),
Description( "true to display the vertical scroll bar" )]
public bool IsShowVScrollBar
{
get { return _isShowVScrollBar; }
set { _isShowVScrollBar = value; ZedGraphControl_ReSize( this, new EventArgs() ); }
}
/// <summary>
/// Gets or sets a value that determines if the <see cref="XAxis" /> <see cref="Scale" />
/// ranges for all <see cref="GraphPane" /> objects in the <see cref="MasterPane" /> will
/// be forced to match.
/// </summary>
/// <remarks>
/// If set to true (default is false), then all of the <see cref="GraphPane" /> objects
/// in the <see cref="MasterPane" /> associated with this <see cref="ZedGraphControl" />
/// will be forced to have matching scale ranges for the x axis. That is, zoom, pan,
/// and scroll operations will result in zoom/pan/scroll for all graphpanes simultaneously.
/// </remarks>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( false ),
Description( "true to force the X axis ranges for all GraphPanes to match" )]
public bool IsSynchronizeXAxes
{
get { return _isSynchronizeXAxes; }
set
{
if ( _isSynchronizeXAxes != value )
ZoomStatePurge();
_isSynchronizeXAxes = value;
}
}
/// <summary>
/// Gets or sets a value that determines if the <see cref="YAxis" /> <see cref="Scale" />
/// ranges for all <see cref="GraphPane" /> objects in the <see cref="MasterPane" /> will
/// be forced to match.
/// </summary>
/// <remarks>
/// If set to true (default is false), then all of the <see cref="GraphPane" /> objects
/// in the <see cref="MasterPane" /> associated with this <see cref="ZedGraphControl" />
/// will be forced to have matching scale ranges for the y axis. That is, zoom, pan,
/// and scroll operations will result in zoom/pan/scroll for all graphpanes simultaneously.
/// </remarks>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( false ),
Description( "true to force the Y axis ranges for all GraphPanes to match" )]
public bool IsSynchronizeYAxes
{
get { return _isSynchronizeYAxes; }
set
{
if ( _isSynchronizeYAxes != value )
ZoomStatePurge();
_isSynchronizeYAxes = value;
}
}
/// <summary>
/// Gets or sets a value that determines if the vertical scroll bar will affect the Y2 axis.
/// </summary>
/// <remarks>
/// The vertical scroll bar is automatically associated with the Y axis. With this value, you
/// can choose to include or exclude the Y2 axis with the scrolling. Note that the Y2 axis
/// scrolling is handled as a secondary. The vertical scroll bar position always reflects
/// the status of the Y axis. This can cause the Y2 axis to "jump" when first scrolled if
/// the <see cref="ScrollMinY2" /> and <see cref="ScrollMaxY2" /> values are not set to the
/// same proportions as <see cref="ScrollMinY" /> and <see cref="ScrollMaxY" /> with respect
/// to the actual <see cref="Scale.Min"/> and <see cref="Scale.Max" />. Also note that
/// this property is actually just an alias to the <see cref="ScrollRange.IsScrollable" />
/// property of the first element of <see cref="YScrollRangeList" />.
/// </remarks>
/// <seealso cref="IsShowVScrollBar"/>
/// <seealso cref="ScrollMinY2"/>
/// <seealso cref="ScrollMaxY2"/>
/// <seealso cref="YScrollRangeList" />
/// <seealso cref="Y2ScrollRangeList" />
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( false ),
Description( "true to scroll the Y2 axis along with the Y axis" )]
public bool IsScrollY2
{
get
{
if ( _y2ScrollRangeList != null && _y2ScrollRangeList.Count > 0 )
return _y2ScrollRangeList[0].IsScrollable;
else
return false;
}
set
{
if ( _y2ScrollRangeList != null && _y2ScrollRangeList.Count > 0 )
{
ScrollRange tmp = _y2ScrollRangeList[0];
tmp.IsScrollable = value;
_y2ScrollRangeList[0] = tmp;
}
}
}
/// <summary>
/// Access the <see cref="ScrollRangeList" /> for the Y axes.
/// </summary>
/// <remarks>
/// This list maintains the user scale ranges for the scroll bars for each axis
/// in the <see cref="ZedGraph.GraphPane.YAxisList" />. Each ordinal location in
/// <see cref="YScrollRangeList" /> corresponds to an equivalent ordinal location
/// in <see cref="ZedGraph.GraphPane.YAxisList" />.
/// </remarks>
/// <seealso cref="ScrollMinY" />
/// <seealso cref="ScrollMaxY" />
[Bindable( true ), Category( "Display" ), NotifyParentProperty( true )]
[Description( "Sets the manual scroll bar ranges for the collection of Y axes" )]
public ScrollRangeList YScrollRangeList
{
get { return _yScrollRangeList; }
}
/// <summary>
/// Access the <see cref="ScrollRangeList" /> for the Y2 axes.
/// </summary>
/// <remarks>
/// This list maintains the user scale ranges for the scroll bars for each axis
/// in the <see cref="ZedGraph.GraphPane.Y2AxisList" />. Each ordinal location in
/// <see cref="Y2ScrollRangeList" /> corresponds to an equivalent ordinal location
/// in <see cref="ZedGraph.GraphPane.Y2AxisList" />.
/// </remarks>
/// <seealso cref="ScrollMinY2" />
/// <seealso cref="ScrollMaxY2" />
[Bindable( true ), Category( "Display" ), NotifyParentProperty( true )]
[Description( "Sets the manual scroll bar ranges for the collection of Y2 axes" )]
public ScrollRangeList Y2ScrollRangeList
{
get { return _y2ScrollRangeList; }
}
/// <summary>
/// The minimum value for the X axis scroll range.
/// </summary>
/// <remarks>
/// Effectively, the minimum endpoint of the scroll range will cause the
/// <see cref="Scale.Min"/> value to be set to <see cref="ScrollMinX"/>. Note that this
/// value applies only to the scroll bar settings. Axis panning (see <see cref="IsEnableHPan"/>)
/// is not affected by this value. Note that this value can be overridden by
/// <see cref="IsAutoScrollRange" /> and <see cref="SetScrollRangeFromData" />.
/// </remarks>
/// <value>A double value indicating the minimum axis value</value>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( 0 ),
Description( "Sets the manual scroll minimum value for the X axis" )]
public double ScrollMinX
{
get { return _xScrollRange.Min; }
set { _xScrollRange.Min = value; }
}
/// <summary>
/// The maximum value for the X axis scroll range.
/// </summary>
/// <remarks>
/// Effectively, the maximum endpoint of the scroll range will cause the
/// <see cref="Scale.Max"/> value to be set to <see cref="ScrollMaxX"/>. Note that this
/// value applies only to the scroll bar settings. Axis panning (see <see cref="IsEnableHPan"/>)
/// is not affected by this value. Note that this value can be overridden by
/// <see cref="IsAutoScrollRange" /> and <see cref="SetScrollRangeFromData" />.
/// </remarks>
/// <value>A double value indicating the maximum axis value</value>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( 0 ),
Description( "Sets the manual scroll maximum value for the X axis" )]
public double ScrollMaxX
{
get { return _xScrollRange.Max; }
set { _xScrollRange.Max = value; }
}
/// <summary>
/// The minimum value for the Y axis scroll range.
/// </summary>
/// <remarks>
/// Effectively, the minimum endpoint of the scroll range will cause the
/// <see cref="Scale.Min"/> value to be set to <see cref="ScrollMinY"/>. Note that this
/// value applies only to the scroll bar settings. Axis panning (see <see cref="IsEnableVPan"/>)
/// is not affected by this value. Note that this value can be overridden by
/// <see cref="IsAutoScrollRange" /> and <see cref="SetScrollRangeFromData" />. Also note that
/// this property is actually just an alias to the <see cref="ScrollRange.Min" />
/// property of the first element of <see cref="YScrollRangeList" />.
/// </remarks>
/// <value>A double value indicating the minimum axis value</value>
/// <seealso cref="YScrollRangeList" />
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( 0 ),
Description( "Sets the manual scroll minimum value for the Y axis" )]
public double ScrollMinY
{
get
{
if ( _yScrollRangeList != null && _yScrollRangeList.Count > 0 )
return _yScrollRangeList[0].Min;
else
return double.NaN;
}
set
{
if ( _yScrollRangeList != null && _yScrollRangeList.Count > 0 )
{
ScrollRange tmp = _yScrollRangeList[0];
tmp.Min = value;
_yScrollRangeList[0] = tmp;
}
}
}
/// <summary>
/// The maximum value for the Y axis scroll range.
/// </summary>
/// <remarks>
/// Effectively, the maximum endpoint of the scroll range will cause the
/// <see cref="Scale.Max"/> value to be set to <see cref="ScrollMaxY"/>. Note that this
/// value applies only to the scroll bar settings. Axis panning (see <see cref="IsEnableVPan"/>)
/// is not affected by this value. Note that this value can be overridden by
/// <see cref="IsAutoScrollRange" /> and <see cref="SetScrollRangeFromData" />. Also note that
/// this property is actually just an alias to the <see cref="ScrollRange.Max" />
/// property of the first element of <see cref="YScrollRangeList" />.
/// </remarks>
/// <value>A double value indicating the maximum axis value</value>
/// <seealso cref="YScrollRangeList" />
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( 0 ),
Description( "Sets the manual scroll maximum value for the Y axis" )]
public double ScrollMaxY
{
get
{
if ( _yScrollRangeList != null && _yScrollRangeList.Count > 0 )
return _yScrollRangeList[0].Max;
else
return double.NaN;
}
set
{
if ( _yScrollRangeList != null && _yScrollRangeList.Count > 0 )
{
ScrollRange tmp = _yScrollRangeList[0];
tmp.Max = value;
_yScrollRangeList[0] = tmp;
}
}
}
/// <summary>
/// The minimum value for the Y2 axis scroll range.
/// </summary>
/// <remarks>
/// Effectively, the minimum endpoint of the scroll range will cause the
/// <see cref="Scale.Min"/> value to be set to <see cref="ScrollMinY2"/>. Note that this
/// value applies only to the scroll bar settings. Axis panning (see <see cref="IsEnableVPan"/>)
/// is not affected by this value. Note that this value can be overridden by
/// <see cref="IsAutoScrollRange" /> and <see cref="SetScrollRangeFromData" />. Also note that
/// this property is actually just an alias to the <see cref="ScrollRange.Min" />
/// property of the first element of <see cref="Y2ScrollRangeList" />.
/// </remarks>
/// <value>A double value indicating the minimum axis value</value>
/// <seealso cref="Y2ScrollRangeList" />
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( 0 ),
Description( "Sets the manual scroll minimum value for the Y2 axis" )]
public double ScrollMinY2
{
get
{
if ( _y2ScrollRangeList != null && _y2ScrollRangeList.Count > 0 )
return _y2ScrollRangeList[0].Min;
else
return double.NaN;
}
set
{
if ( _y2ScrollRangeList != null && _y2ScrollRangeList.Count > 0 )
{
ScrollRange tmp = _y2ScrollRangeList[0];
tmp.Min = value;
_y2ScrollRangeList[0] = tmp;
}
}
}
/// <summary>
/// The maximum value for the Y2 axis scroll range.
/// </summary>
/// <remarks>
/// Effectively, the maximum endpoint of the scroll range will cause the
/// <see cref="Scale.Max"/> value to be set to <see cref="ScrollMaxY2"/>. Note that this
/// value applies only to the scroll bar settings. Axis panning (see <see cref="IsEnableVPan"/>)
/// is not affected by this value. Note that this value can be overridden by
/// <see cref="IsAutoScrollRange" /> and <see cref="SetScrollRangeFromData" />. Also note that
/// this property is actually just an alias to the <see cref="ScrollRange.Max" />
/// property of the first element of <see cref="Y2ScrollRangeList" />.
/// </remarks>
/// <value>A double value indicating the maximum axis value</value>
/// <seealso cref="Y2ScrollRangeList" />
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( 0 ),
Description( "Sets the manual scroll maximum value for the Y2 axis" )]
public double ScrollMaxY2
{
get
{
if ( _y2ScrollRangeList != null && _y2ScrollRangeList.Count > 0 )
return _y2ScrollRangeList[0].Max;
else
return double.NaN;
}
set
{
if ( _y2ScrollRangeList != null && _y2ScrollRangeList.Count > 0 )
{
ScrollRange tmp = _y2ScrollRangeList[0];
tmp.Max = value;
_y2ScrollRangeList[0] = tmp;
}
}
}
/// <summary>
/// Returns true if the user is currently scrolling via the scrollbar, or
/// false if no scrolling is taking place.
/// </summary>
/// <remarks>
/// This method just tests ScrollBar.Capture to see if the
/// mouse has been captured by the scroll bar. If so, scrolling is active.
/// </remarks>
public Boolean IsScrolling
{
get
{
if ( hScrollBar1 != null && vScrollBar1 != null )
return hScrollBar1.Capture || vScrollBar1.Capture;
else
return false;
}
}
/// <summary>
/// Gets or sets the format for displaying tooltip values.
/// This format is passed to <see cref="PointPairBase.ToString(string)"/>.
/// </summary>
/// <remarks>
/// Use the <see cref="System.Globalization.NumberFormatInfo" /> type
/// to determine the format strings.
/// </remarks>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( PointPair.DefaultFormat ),
Description( "Sets the numeric display format string for the point value tooltips" )]
public string PointValueFormat
{
get { return _pointValueFormat; }
set { _pointValueFormat = value; }
}
/// <summary>
/// Gets or sets the format for displaying tooltip values.
/// This format is passed to <see cref="XDate.ToString(string)"/>.
/// </summary>
/// <remarks>
/// Use the <see cref="System.Globalization.DateTimeFormatInfo" /> type
/// to determine the format strings.
/// </remarks>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( XDate.DefaultFormatStr ),
Description( "Sets the date display format for the point value tooltips" )]
public string PointDateFormat
{
get { return _pointDateFormat; }
set { _pointDateFormat = value; }
}
/// <summary>
/// Gets or sets the step size fraction for zooming with the mouse wheel.
/// A value of 0.1 will result in a 10% zoom step for each mouse wheel movement.
/// </summary>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( 0.1 ),
Description( "Sets the step size fraction for zooming with the mouse wheel" )]
public double ZoomStepFraction
{
get { return _zoomStepFraction; }
set { _zoomStepFraction = value; }
}
/// <summary>
/// Gets or sets a boolean value that determines if zooming with the wheel mouse
/// is centered on the mouse location, or centered on the existing graph.
/// </summary>
[ Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( false ),
Description( "true to center the mouse wheel zoom at the current mouse location" )]
public bool IsZoomOnMouseCenter
{
get { return _isZoomOnMouseCenter; }
set { _isZoomOnMouseCenter = value; }
}
/// <summary>
/// Gets the graph pane's current image.
/// <seealso cref="Bitmap"/>
/// </summary>
/// <exception cref="ZedGraphException">
/// When the control has been disposed before this call.
/// </exception>
[ Bindable( false ), Browsable( false ),
DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )]
public Image GetImage()
{
lock ( this )
{
if ( BeenDisposed || _masterPane == null || _masterPane[0] == null )
throw new ZedGraphException( "The control has been disposed" );
return _masterPane.GetImage();
}
}
/// <summary>
/// This checks if the control has been disposed. This is synonymous with
/// the graph pane having been nulled or disposed. Therefore this is the
/// same as <c>ZedGraphControl.GraphPane == null</c>.
/// </summary>
[ Bindable( false ), Browsable( false ),
DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )]
public bool BeenDisposed
{
get
{
lock ( this ) return _masterPane == null;
}
}
// Revision: JCarpenter 10/06
/// <summary>
/// Readonly property that gets the list of selected CurveItems
/// </summary>
public Selection Selection
{
get { return _selection; }
}
/// <summary>
/// Gets or sets a value that determines whether or not selection is allowed for the control.
/// </summary>
[Bindable( true ), Category( "Display" ), NotifyParentProperty( true ),
DefaultValue( false ),
Description( "true to allow selecting Curves" )]
public bool IsEnableSelection
{
get { return _isEnableSelection; }
set
{
_isEnableSelection = value;
/*
if ( value )
{
this.Cursor = Cursors.Default;
this.IsEnableZoom = false;
}
else
{
this.Cursor = Cursors.Cross;
this.IsEnableZoom = true;
}
*/
}
}
#endregion
#region Methods
/// <summary>
/// Called by the system to update the control on-screen
/// </summary>
/// <param name="e">
/// A PaintEventArgs object containing the Graphics specifications
/// for this Paint event.
/// </param>
protected override void OnPaint( PaintEventArgs e )
{
lock ( this )
{
if ( BeenDisposed || _masterPane == null || this.GraphPane == null )
return;
if ( hScrollBar1 != null && this.GraphPane != null &&
vScrollBar1 != null && _yScrollRangeList != null )
{
SetScroll( hScrollBar1, this.GraphPane.XAxis, _xScrollRange.Min, _xScrollRange.Max );
SetScroll( vScrollBar1, this.GraphPane.YAxis, _yScrollRangeList[0].Min,
_yScrollRangeList[0].Max );
}
SmoothingMode sModeSave = e.Graphics.SmoothingMode;
TextRenderingHint sHintSave = e.Graphics.TextRenderingHint;
if ( _isAntiAlias )
{
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
e.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
}
base.OnPaint( e );
// Add a try/catch pair since the users of the control can't catch this one
try { _masterPane.Draw( e.Graphics ); }
catch { }
e.Graphics.SmoothingMode = sModeSave;
e.Graphics.TextRenderingHint = sHintSave;
}
/*
// first, see if an old thread is still running
if ( t != null && t.IsAlive )
{
t.Abort();
}
//dt = new DrawingThread( e.Graphics, _masterPane );
//g = e.Graphics;
// Fire off the new thread
t = new Thread( new ParameterizedThreadStart( DoDrawingThread ) );
//ct.ApartmentState = ApartmentState.STA;
//ct.SetApartmentState( ApartmentState.STA );
DrawingThreadData dtd;
dtd._g = e.Graphics;
dtd._masterPane = _masterPane;
t.Start( dtd );
//ct.Join();
*/
}
// Thread t = null;
//DrawingThread dt = null;
/*
/// <summary>
///
/// </summary>
/// <param name="dtdobj"></param>
public void DoDrawingThread( object dtdobj )
{
try
{
DrawingThreadData dtd = (DrawingThreadData) dtdobj;
if ( dtd._g != null && dtd._masterPane != null )
dtd._masterPane.Draw( dtd._g );
// else
// {
// using ( Graphics g2 = CreateGraphics() )
// _masterPane.Draw( g2 );
// }
}
catch
{
}
}
*/
/// <summary>
/// Called when the control has been resized.
/// </summary>
/// <param name="sender">
/// A reference to the control that has been resized.
/// </param>
/// <param name="e">
/// An EventArgs object.
/// </param>
protected void ZedGraphControl_ReSize( object sender, System.EventArgs e )
{
lock ( this )
{
if ( BeenDisposed || _masterPane == null )
return;
Size newSize = this.Size;
if ( _isShowHScrollBar )
{
hScrollBar1.Visible = true;
newSize.Height -= this.hScrollBar1.Size.Height;
hScrollBar1.Location = new Point( 0, newSize.Height );
hScrollBar1.Size = new Size( newSize.Width, hScrollBar1.Height );
}
else
hScrollBar1.Visible = false;
if ( _isShowVScrollBar )
{
vScrollBar1.Visible = true;
newSize.Width -= this.vScrollBar1.Size.Width;
vScrollBar1.Location = new Point( newSize.Width, 0 );
vScrollBar1.Size = new Size( vScrollBar1.Width, newSize.Height );
}
else
vScrollBar1.Visible = false;
using ( Graphics g = this.CreateGraphics() )
{
_masterPane.ReSize( g, new RectangleF( 0, 0, newSize.Width, newSize.Height ) );
//g.Dispose();
}
this.Invalidate();
}
}
/// <summary>This performs an axis change command on the graphPane.
/// </summary>
/// <remarks>
/// This is the same as
/// <c>ZedGraphControl.GraphPane.AxisChange( ZedGraphControl.CreateGraphics() )</c>, however,
/// this method also calls <see cref="SetScrollRangeFromData" /> if <see cref="IsAutoScrollRange" />
/// is true.
/// </remarks>
public virtual void AxisChange()
{
lock ( this )
{
if ( BeenDisposed || _masterPane == null )
return;
using ( Graphics g = this.CreateGraphics() )
{
_masterPane.AxisChange( g );
//g.Dispose();
}
if ( _isAutoScrollRange )
SetScrollRangeFromData();
}
}
#endregion
#region Mouse Events
/// <summary>
/// Handle a MouseDown event in the <see cref="ZedGraphControl" />
/// </summary>
/// <param name="sender">A reference to the <see cref="ZedGraphControl" /></param>
/// <param name="e">A <see cref="MouseEventArgs" /> instance</param>
protected void ZedGraphControl_MouseDown( object sender, MouseEventArgs e )
{
_isPanning = false;
_isZooming = false;
_isEditing = false;
_isSelecting = false;
_dragPane = null;
Point mousePt = new Point( e.X, e.Y );
// Callback for doubleclick events
if ( _masterPane != null && e.Clicks > 1 && this.DoubleClickEvent != null )
{
if ( this.DoubleClickEvent( this, e ) )
return;
}
// Provide Callback for MouseDown events
if ( _masterPane != null && this.MouseDownEvent != null )
{
if ( this.MouseDownEvent( this, e ) )
return;
}
if ( e.Clicks > 1 || _masterPane == null )
return;
// First, see if the click is within a Linkable object within any GraphPane
GraphPane pane = this.MasterPane.FindPane( mousePt );
if ( pane != null &&
e.Button == _linkButtons && Control.ModifierKeys == _linkModifierKeys )
{
object source;
Link link;
int index;
using ( Graphics g = this.CreateGraphics() )
{
float scaleFactor = pane.CalcScaleFactor();
if ( pane.FindLinkableObject( mousePt, g, scaleFactor, out source, out link, out index ) )
{
if ( LinkEvent != null && LinkEvent( this, pane, source, link, index ) )
return;
string url;
CurveItem curve = source as CurveItem;
if ( curve != null )
url = link.MakeCurveItemUrl( pane, curve, index );
else
url = link._url;
if ( url != string.Empty )
{
System.Diagnostics.Process.Start( url );
// linkable objects override any other actions with mouse
return;
}
}
//g.Dispose();
}
}
// Second, Check to see if it's within a Chart Rect
pane = this.MasterPane.FindChartRect( mousePt );
//Rectangle rect = new Rectangle( mousePt, new Size( 1, 1 ) );
if ( pane != null &&
( _isEnableHPan || _isEnableVPan ) &&
( ( e.Button == _panButtons && Control.ModifierKeys == _panModifierKeys ) ||
( e.Button == _panButtons2 && Control.ModifierKeys == _panModifierKeys2 ) ) )
{
_isPanning = true;
_dragStartPt = mousePt;
_dragPane = pane;
//_zoomState = new ZoomState( _dragPane, ZoomState.StateType.Pan );
ZoomStateSave( _dragPane, ZoomState.StateType.Pan );
}
else if ( pane != null && ( _isEnableHZoom || _isEnableVZoom ) &&
( ( e.Button == _zoomButtons && Control.ModifierKeys == _zoomModifierKeys ) ||
( e.Button == _zoomButtons2 && Control.ModifierKeys == _zoomModifierKeys2 ) ) )
{
_isZooming = true;
_dragStartPt = mousePt;
_dragEndPt = mousePt;
_dragEndPt.Offset( 1, 1 );
_dragPane = pane;
ZoomStateSave( _dragPane, ZoomState.StateType.Zoom );
}
//Revision: JCarpenter 10/06
else if ( pane != null && _isEnableSelection && e.Button == _selectButtons &&
( Control.ModifierKeys == _selectModifierKeys ||
Control.ModifierKeys == _selectAppendModifierKeys ))
{
_isSelecting = true;
_dragStartPt = mousePt;
_dragEndPt = mousePt;
_dragEndPt.Offset( 1, 1 );
_dragPane = pane;
}
else if ( pane != null && ( _isEnableHEdit || _isEnableVEdit ) &&
( e.Button == EditButtons && Control.ModifierKeys == EditModifierKeys ) )
{
// find the point that was clicked, and make sure the point list is editable
// and that it's a primary Y axis (the first Y or Y2 axis)
if ( pane.FindNearestPoint( mousePt, out _dragCurve, out _dragIndex ) &&
_dragCurve.Points is IPointListEdit )
{
_isEditing = true;
_dragPane = pane;
_dragStartPt = mousePt;
_dragStartPair = _dragCurve[_dragIndex];
}
}
}
/// <summary>
/// Set the cursor according to the current mouse location.
/// </summary>
protected void SetCursor()
{
SetCursor( this.PointToClient( Control.MousePosition ) );
}
/// <summary>
/// Set the cursor according to the current mouse location.
/// </summary>
protected void SetCursor( Point mousePt )
{
if ( _masterPane != null )
{
GraphPane pane = _masterPane.FindChartRect( mousePt );
if ( ( _isEnableHPan || _isEnableVPan ) && ( Control.ModifierKeys == Keys.Shift || _isPanning ) &&
( pane != null || _isPanning ) )
this.Cursor = Cursors.Hand;
else if ( ( _isEnableVZoom || _isEnableHZoom ) && ( pane != null || _isZooming ) )
this.Cursor = Cursors.Cross;
else if ( _isEnableSelection && ( pane != null || _isSelecting ) )
this.Cursor = Cursors.Cross;
else
this.Cursor = Cursors.Default;
// else if ( isZoomMode || isPanMode )
// this.Cursor = Cursors.No;
}
}
/// <summary>
/// Handle a KeyUp event
/// </summary>
/// <param name="sender">The <see cref="ZedGraphControl" /> in which the KeyUp occurred.</param>
/// <param name="e">A <see cref="KeyEventArgs" /> instance.</param>
protected void ZedGraphControl_KeyUp( object sender, KeyEventArgs e )
{
SetCursor();
}
/// <summary>
/// Handle the Key Events so ZedGraph can Escape out of a panning or zooming operation.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void ZedGraphControl_KeyDown( object sender, System.Windows.Forms.KeyEventArgs e )
{
SetCursor();
if ( e.KeyCode == Keys.Escape )
{
if ( _isPanning )
HandlePanCancel();
if ( _isZooming )
HandleZoomCancel();
if ( _isEditing )
HandleEditCancel();
//if ( _isSelecting )
// Esc always cancels the selection
HandleSelectionCancel();
_isZooming = false;
_isPanning = false;
_isEditing = false;
_isSelecting = false;
Refresh();
}
}
/// <summary>
/// Handle a MouseUp event in the <see cref="ZedGraphControl" />
/// </summary>
/// <param name="sender">A reference to the <see cref="ZedGraphControl" /></param>
/// <param name="e">A <see cref="MouseEventArgs" /> instance</param>
protected void ZedGraphControl_MouseUp( object sender, MouseEventArgs e )
{
// Provide Callback for MouseUp events
if ( _masterPane != null && this.MouseUpEvent != null )
{
if ( this.MouseUpEvent( this, e ) )
return;
}
if ( _masterPane != null && _dragPane != null )
{
// If the MouseUp event occurs, the user is done dragging.
if ( _isZooming )
HandleZoomFinish( sender, e );
else if ( _isPanning )
HandlePanFinish();
else if ( _isEditing )
HandleEditFinish();
//Revision: JCarpenter 10/06
else if ( _isSelecting )
HandleSelectionFinish( sender, e );
}
// Reset the rectangle.
//dragStartPt = new Rectangle( 0, 0, 0, 0 );
_dragPane = null;
_isZooming = false;
_isPanning = false;
_isEditing = false;
_isSelecting = false;
Cursor.Current = Cursors.Default;
}
/// <summary>
/// Make a string label that corresponds to a user scale value.
/// </summary>
/// <param name="axis">The axis from which to obtain the scale value. This determines
/// if it's a date value, linear, log, etc.</param>
/// <param name="val">The value to be made into a label</param>
/// <param name="iPt">The ordinal position of the value</param>
/// <param name="isOverrideOrdinal">true to override the ordinal settings of the axis,
/// and prefer the actual value instead.</param>
/// <returns>The string label.</returns>
protected string MakeValueLabel( Axis axis, double val, int iPt, bool isOverrideOrdinal )
{
if ( axis != null )
{
if ( axis.Scale.IsDate || axis.Scale.Type == AxisType.DateAsOrdinal )
{
return XDate.ToString( val, _pointDateFormat );
}
else if ( axis._scale.IsText && axis._scale._textLabels != null )
{
int i = iPt;
if ( isOverrideOrdinal )
i = (int)( val - 0.5 );
if ( i >= 0 && i < axis._scale._textLabels.Length )
return axis._scale._textLabels[i];
else
return ( i + 1 ).ToString();
}
else if ( axis.Scale.IsAnyOrdinal && axis.Scale.Type != AxisType.LinearAsOrdinal
&& !isOverrideOrdinal )
{
return iPt.ToString( _pointValueFormat );
}
else
return val.ToString( _pointValueFormat );
}
else
return "";
}
/// <summary>
/// protected method for handling MouseMove events to display tooltips over
/// individual datapoints.
/// </summary>
/// <param name="sender">
/// A reference to the control that has the MouseMove event.
/// </param>
/// <param name="e">
/// A MouseEventArgs object.
/// </param>
protected void ZedGraphControl_MouseMove( object sender, MouseEventArgs e )
{
if ( _masterPane != null )
{
// Provide Callback for MouseMove events
if ( this.MouseMoveEvent != null && this.MouseMoveEvent( this, e ) )
return;
Point mousePt = new Point( e.X, e.Y );
//Point tempPt = this.PointToClient( Control.MousePosition );
SetCursor( mousePt );
// If the mouse is being dragged,
// undraw and redraw the rectangle as the mouse moves.
if ( _isZooming )
HandleZoomDrag( mousePt );
else if ( _isPanning )
HandlePanDrag( mousePt );
else if ( _isEditing )
HandleEditDrag( mousePt );
else if ( _isShowCursorValues )
HandleCursorValues( mousePt );
else if ( _isShowPointValues )
HandlePointValues( mousePt );
//Revision: JCarpenter 10/06
else if ( _isSelecting )
HandleZoomDrag( mousePt );
}
}
private Point HandlePointValues( Point mousePt )
{
int iPt;
GraphPane pane;
object nearestObj;
using ( Graphics g = this.CreateGraphics() )
{
if ( _masterPane.FindNearestPaneObject( mousePt,
g, out pane, out nearestObj, out iPt ) )
{
if ( nearestObj is CurveItem && iPt >= 0 )
{
CurveItem curve = (CurveItem)nearestObj;
// Provide Callback for User to customize the tooltips
if ( this.PointValueEvent != null )
{
string label = this.PointValueEvent( this, pane, curve, iPt );
if ( label != null && label.Length > 0 )
{
this.pointToolTip.SetToolTip( this, label );
this.pointToolTip.Active = true;
}
else
this.pointToolTip.Active = false;
}
else
{
if ( curve is PieItem )
{
this.pointToolTip.SetToolTip( this,
( (PieItem)curve ).Value.ToString( _pointValueFormat ) );
}
// else if ( curve is OHLCBarItem || curve is JapaneseCandleStickItem )
// {
// StockPt spt = (StockPt)curve.Points[iPt];
// this.pointToolTip.SetToolTip( this, ( (XDate) spt.Date ).ToString( "MM/dd/yyyy" ) + "\nOpen: $" +
// spt.Open.ToString( "N2" ) +
// "\nHigh: $" +
// spt.High.ToString( "N2" ) + "\nLow: $" +
// spt.Low.ToString( "N2" ) + "\nClose: $" +
// spt.Close.ToString
// ( "N2" ) );
// }
else
{
PointPair pt = curve.Points[iPt];
if ( pt.Tag is string )
this.pointToolTip.SetToolTip( this, (string)pt.Tag );
else
{
double xVal, yVal, lowVal;
ValueHandler valueHandler = new ValueHandler( pane, false );
if ( ( curve is BarItem || curve is ErrorBarItem || curve is HiLowBarItem )
&& pane.BarSettings.Base != BarBase.X )
valueHandler.GetValues( curve, iPt, out yVal, out lowVal, out xVal );
else
valueHandler.GetValues( curve, iPt, out xVal, out lowVal, out yVal );
string xStr = MakeValueLabel( pane.XAxis, xVal, iPt,
curve.IsOverrideOrdinal );
string yStr = MakeValueLabel( curve.GetYAxis( pane ), yVal, iPt,
curve.IsOverrideOrdinal );
this.pointToolTip.SetToolTip( this, "( " + xStr + ", " + yStr + " )" );
//this.pointToolTip.SetToolTip( this,
// curve.Points[iPt].ToString( this.pointValueFormat ) );
}
}
this.pointToolTip.Active = true;
}
}
else
this.pointToolTip.Active = false;
}
else
this.pointToolTip.Active = false;
//g.Dispose();
}
return mousePt;
}
private Point HandleCursorValues( Point mousePt )
{
GraphPane pane = _masterPane.FindPane( mousePt );
if ( pane != null && pane.Chart._rect.Contains( mousePt ) )
{
double x, y, y2;
pane.ReverseTransform( mousePt, out x, out y, out y2 );
string xStr = MakeValueLabel( pane.XAxis, x, -1, true );
string yStr = MakeValueLabel( pane.YAxis, y, -1, true );
string y2Str = MakeValueLabel( pane.Y2Axis, y2, -1, true );
this.pointToolTip.SetToolTip( this, "( " + xStr + ", " + yStr + ", " + y2Str + " )" );
this.pointToolTip.Active = true;
}
else
this.pointToolTip.Active = false;
return mousePt;
}
#endregion
#region Mouse Wheel Zoom Events
/// <summary>
/// Handle a MouseWheel event in the <see cref="ZedGraphControl" />
/// </summary>
/// <param name="sender">A reference to the <see cref="ZedGraphControl" /></param>
/// <param name="e">A <see cref="MouseEventArgs" /> instance</param>
protected void ZedGraphControl_MouseWheel( object sender, MouseEventArgs e )
{
if ( ( _isEnableVZoom || _isEnableHZoom ) && _masterPane != null )
{
GraphPane pane = this.MasterPane.FindChartRect( new PointF( e.X, e.Y ) );
if ( pane != null && e.Delta != 0 )
{
ZoomState oldState = ZoomStateSave( pane, ZoomState.StateType.WheelZoom );
//ZoomState oldState = pane.ZoomStack.Push( pane, ZoomState.StateType.Zoom );
PointF centerPoint = new PointF( e.X, e.Y );
double zoomFraction = ( 1 + ( e.Delta < 0 ? 1.0 : -1.0 ) * ZoomStepFraction );
ZoomPane( pane, zoomFraction, centerPoint, _isZoomOnMouseCenter, false );
ApplyToAllPanes( pane );
using ( Graphics g = this.CreateGraphics() )
{
// always AxisChange() the dragPane
pane.AxisChange( g );
foreach ( GraphPane tempPane in _masterPane._paneList )
{
if ( tempPane != pane && ( _isSynchronizeXAxes || _isSynchronizeYAxes ) )
tempPane.AxisChange( g );
}
}
ZoomStatePush( pane );
// Provide Callback to notify the user of zoom events
if ( this.ZoomEvent != null )
this.ZoomEvent( this, oldState, new ZoomState( pane, ZoomState.StateType.WheelZoom ) );
this.Refresh();
}
}
}
/// <summary>
/// Zoom a specified pane in or out according to the specified zoom fraction.
/// </summary>
/// <remarks>
/// The zoom will occur on the <see cref="XAxis" />, <see cref="YAxis" />, and
/// <see cref="Y2Axis" /> only if the corresponding flag, <see cref="IsEnableHZoom" /> or
/// <see cref="IsEnableVZoom" />, is true. Note that if there are multiple Y or Y2 axes, all of
/// them will be zoomed.
/// </remarks>
/// <param name="pane">The <see cref="GraphPane" /> instance to be zoomed.</param>
/// <param name="zoomFraction">The fraction by which to zoom, less than 1 to zoom in, greater than
/// 1 to zoom out. For example, 0.9 will zoom in such that the scale is 90% of what it was
/// originally.</param>
/// <param name="centerPt">The screen position about which the zoom will be centered. This
/// value is only used if <see paramref="isZoomOnCenter" /> is true.
/// </param>
/// <param name="isZoomOnCenter">true to cause the zoom to be centered on the point
/// <see paramref="centerPt" />, false to center on the <see cref="Chart.Rect" />.
/// </param>
/// <param name="isRefresh">true to force a refresh of the control, false to leave it unrefreshed</param>
protected void ZoomPane( GraphPane pane, double zoomFraction, PointF centerPt,
bool isZoomOnCenter, bool isRefresh )
{
double x;
double[] y;
double[] y2;
pane.ReverseTransform( centerPt, out x, out y, out y2 );
if ( _isEnableHZoom )
ZoomScale( pane.XAxis, zoomFraction, x, isZoomOnCenter );
if ( _isEnableVZoom )
{
for ( int i = 0; i < pane.YAxisList.Count; i++ )
ZoomScale( pane.YAxisList[i], zoomFraction, y[i], isZoomOnCenter );
for ( int i = 0; i < pane.Y2AxisList.Count; i++ )
ZoomScale( pane.Y2AxisList[i], zoomFraction, y2[i], isZoomOnCenter );
}
using ( Graphics g = this.CreateGraphics() )
{
pane.AxisChange( g );
//g.Dispose();
}
this.SetScroll( this.hScrollBar1, pane.XAxis, _xScrollRange.Min, _xScrollRange.Max );
this.SetScroll( this.vScrollBar1, pane.YAxis, _yScrollRangeList[0].Min,
_yScrollRangeList[0].Max );
if ( isRefresh )
Refresh();
}
/// <summary>
/// Zoom a specified pane in or out according to the specified zoom fraction.
/// </summary>
/// <remarks>
/// The zoom will occur on the <see cref="XAxis" />, <see cref="YAxis" />, and
/// <see cref="Y2Axis" /> only if the corresponding flag, <see cref="IsEnableHZoom" /> or
/// <see cref="IsEnableVZoom" />, is true. Note that if there are multiple Y or Y2 axes, all of
/// them will be zoomed.
/// </remarks>
/// <param name="pane">The <see cref="GraphPane" /> instance to be zoomed.</param>
/// <param name="zoomFraction">The fraction by which to zoom, less than 1 to zoom in, greater than
/// 1 to zoom out. For example, 0.9 will zoom in such that the scale is 90% of what it was
/// originally.</param>
/// <param name="centerPt">The screen position about which the zoom will be centered. This
/// value is only used if <see paramref="isZoomOnCenter" /> is true.
/// </param>
/// <param name="isZoomOnCenter">true to cause the zoom to be centered on the point
/// <see paramref="centerPt" />, false to center on the <see cref="Chart.Rect" />.
/// </param>
public void ZoomPane( GraphPane pane, double zoomFraction, PointF centerPt, bool isZoomOnCenter )
{
ZoomPane( pane, zoomFraction, centerPt, isZoomOnCenter, true );
}
/// <summary>
/// Zoom the specified axis by the specified amount, with the center of the zoom at the
/// (optionally) specified point.
/// </summary>
/// <remarks>
/// This method is used for MouseWheel zoom operations</remarks>
/// <param name="axis">The <see cref="Axis" /> to be zoomed.</param>
/// <param name="zoomFraction">The zoom fraction, less than 1.0 to zoom in, greater than 1.0 to
/// zoom out. That is, a value of 0.9 will zoom in such that the scale length is 90% of what
/// it previously was.</param>
/// <param name="centerVal">The location for the center of the zoom. This is only used if
/// <see paramref="IsZoomOnMouseCenter" /> is true.</param>
/// <param name="isZoomOnCenter">true if the zoom is to be centered at the
/// <see paramref="centerVal" /> screen position, false for the zoom to be centered within
/// the <see cref="Chart.Rect" />.
/// </param>
protected void ZoomScale( Axis axis, double zoomFraction, double centerVal, bool isZoomOnCenter )
{
if ( axis != null && zoomFraction > 0.0001 && zoomFraction < 1000.0 )
{
Scale scale = axis._scale;
/*
if ( axis.Scale.IsLog )
{
double ratio = Math.Sqrt( axis._scale._max / axis._scale._min * zoomFraction );
if ( !isZoomOnCenter )
centerVal = Math.Sqrt( axis._scale._max * axis._scale._min );
axis._scale._min = centerVal / ratio;
axis._scale._max = centerVal * ratio;
}
else
{
*/
double minLin = axis._scale._minLinearized;
double maxLin = axis._scale._maxLinearized;
double range = ( maxLin - minLin ) * zoomFraction / 2.0;
if ( !isZoomOnCenter )
centerVal = ( maxLin + minLin ) / 2.0;
axis._scale._minLinearized = centerVal - range;
axis._scale._maxLinearized = centerVal + range;
// }
axis._scale._minAuto = false;
axis._scale._maxAuto = false;
}
}
#endregion
#region Pan Events
private Point HandlePanDrag( Point mousePt )
{
double x1, x2;
double[] y1, y2, yy1, yy2;
//PointF endPoint = mousePt;
//PointF startPoint = ( (Control)sender ).PointToClient( this.dragRect.Location );
_dragPane.ReverseTransform( _dragStartPt, out x1, out y1, out yy1 );
_dragPane.ReverseTransform( mousePt, out x2, out y2, out yy2 );
if ( _isEnableHPan )
{
PanScale( _dragPane.XAxis, x1, x2 );
this.SetScroll( this.hScrollBar1, _dragPane.XAxis, _xScrollRange.Min, _xScrollRange.Max );
}
if ( _isEnableVPan )
{
for ( int i = 0; i < y1.Length; i++ )
PanScale( _dragPane.YAxisList[i], y1[i], y2[i] );
for ( int i = 0; i < yy1.Length; i++ )
PanScale( _dragPane.Y2AxisList[i], yy1[i], yy2[i] );
this.SetScroll( this.vScrollBar1, _dragPane.YAxis, _yScrollRangeList[0].Min,
_yScrollRangeList[0].Max );
}
ApplyToAllPanes( _dragPane );
Refresh();
_dragStartPt = mousePt;
return mousePt;
}
private void HandlePanFinish()
{
// push the prior saved zoomstate, since the scale ranges have already been changed on
// the fly during the panning operation
if ( _zoomState != null && _zoomState.IsChanged( _dragPane ) )
{
//_dragPane.ZoomStack.Push( _zoomState );
ZoomStatePush( _dragPane );
// Provide Callback to notify the user of pan events
if ( this.ZoomEvent != null )
this.ZoomEvent( this, _zoomState,
new ZoomState( _dragPane, ZoomState.StateType.Pan ) );
_zoomState = null;
}
}
private void HandlePanCancel()
{
if ( _isPanning )
{
if ( _zoomState != null && _zoomState.IsChanged( _dragPane ) )
{
ZoomStateRestore( _dragPane );
//_zoomState.ApplyState( _dragPane );
//_zoomState = null;
}
_isPanning = false;
Refresh();
ZoomStateClear();
}
}
/// <summary>
/// Handle a panning operation for the specified <see cref="Axis" />.
/// </summary>
/// <param name="axis">The <see cref="Axis" /> to be panned</param>
/// <param name="startVal">The value where the pan started. The scale range
/// will be shifted by the difference between <see paramref="startVal" /> and
/// <see paramref="endVal" />.
/// </param>
/// <param name="endVal">The value where the pan ended. The scale range
/// will be shifted by the difference between <see paramref="startVal" /> and
/// <see paramref="endVal" />.
/// </param>
protected void PanScale( Axis axis, double startVal, double endVal )
{
if ( axis != null )
{
Scale scale = axis._scale;
double delta = scale.Linearize( startVal ) - scale.Linearize( endVal );
scale._minLinearized += delta;
scale._maxLinearized += delta;
scale._minAuto = false;
scale._maxAuto = false;
/*
if ( axis.Type == AxisType.Log )
{
axis._scale._min *= startVal / endVal;
axis._scale._max *= startVal / endVal;
}
else
{
axis._scale._min += startVal - endVal;
axis._scale._max += startVal - endVal;
}
*/
}
}
#endregion
#region Edit Point Events
private void HandleEditDrag( Point mousePt )
{
// get the scale values that correspond to the current point
double curX, curY;
_dragPane.ReverseTransform( mousePt, _dragCurve.IsY2Axis, _dragCurve.YAxisIndex,
out curX, out curY );
double startX, startY;
_dragPane.ReverseTransform( _dragStartPt, _dragCurve.IsY2Axis, _dragCurve.YAxisIndex,
out startX, out startY );
// calculate the new scale values for the point
PointPair newPt = new PointPair( _dragStartPair );
Scale xScale = _dragPane.XAxis._scale;
if ( _isEnableHEdit )
newPt.X = xScale.DeLinearize( xScale.Linearize( newPt.X ) +
xScale.Linearize( curX )- xScale.Linearize( startX ) );
Scale yScale = _dragCurve.GetYAxis( _dragPane )._scale;
if ( _isEnableVEdit )
newPt.Y = yScale.DeLinearize( yScale.Linearize( newPt.Y ) +
yScale.Linearize( curY ) - yScale.Linearize( startY ) );
// save the data back to the point list
IPointListEdit list = _dragCurve.Points as IPointListEdit;
if ( list != null )
list[_dragIndex] = newPt;
// force a redraw
Refresh();
}
private void HandleEditFinish()
{
if ( this.PointEditEvent != null )
this.PointEditEvent( this, _dragPane, _dragCurve, _dragIndex );
}
private void HandleEditCancel()
{
if ( _isEditing )
{
IPointListEdit list = _dragCurve.Points as IPointListEdit;
if ( list != null )
list[_dragIndex] = _dragStartPair;
_isEditing = false;
Refresh();
}
}
#endregion
#region Zoom Events
private void HandleZoomDrag( Point mousePt )
{
// Hide the previous rectangle by calling the
// DrawReversibleFrame method with the same parameters.
Rectangle rect = CalcScreenRect( _dragStartPt, _dragEndPt );
ControlPaint.DrawReversibleFrame( rect, this.BackColor, FrameStyle.Dashed );
// Bound the zoom to the ChartRect
_dragEndPt = Point.Round( BoundPointToRect( mousePt, _dragPane.Chart._rect ) );
rect = CalcScreenRect( _dragStartPt, _dragEndPt );
// Draw the new rectangle by calling DrawReversibleFrame again.
ControlPaint.DrawReversibleFrame( rect, this.BackColor, FrameStyle.Dashed );
}
private void HandleZoomFinish( object sender, MouseEventArgs e )
{
PointF mousePtF = BoundPointToRect( new Point( e.X, e.Y ), _dragPane.Chart._rect );
// Only accept a drag if it covers at least 5 pixels in each direction
//Point curPt = ( (Control)sender ).PointToScreen( Point.Round( mousePt ) );
if ( ( Math.Abs( mousePtF.X - _dragStartPt.X ) > 4 || !_isEnableHZoom ) &&
( Math.Abs( mousePtF.Y - _dragStartPt.Y ) > 4 || !_isEnableVZoom ) )
{
// Draw the rectangle to be evaluated. Set a dashed frame style
// using the FrameStyle enumeration.
//ControlPaint.DrawReversibleFrame( this.dragRect,
// this.BackColor, FrameStyle.Dashed );
double x1, x2;
double[] y1, y2, yy1, yy2;
//PointF startPoint = ( (Control)sender ).PointToClient( this.dragRect.Location );
_dragPane.ReverseTransform( _dragStartPt, out x1, out y1, out yy1 );
_dragPane.ReverseTransform( mousePtF, out x2, out y2, out yy2 );
ZoomStatePush( _dragPane );
//ZoomState oldState = _dragPane.ZoomStack.Push( _dragPane,
// ZoomState.StateType.Zoom );
if ( _isEnableHZoom )
{
_dragPane.XAxis._scale._min = Math.Min( x1, x2 );
_dragPane.XAxis._scale._minAuto = false;
_dragPane.XAxis._scale._max = Math.Max( x1, x2 );
_dragPane.XAxis._scale._maxAuto = false;
}
if ( _isEnableVZoom )
{
for ( int i = 0; i < y1.Length; i++ )
{
_dragPane.YAxisList[i]._scale._min = Math.Min( y1[i], y2[i] );
_dragPane.YAxisList[i]._scale._max = Math.Max( y1[i], y2[i] );
_dragPane.YAxisList[i]._scale._minAuto = false;
_dragPane.YAxisList[i]._scale._maxAuto = false;
}
for ( int i = 0; i < yy1.Length; i++ )
{
_dragPane.Y2AxisList[i]._scale._min = Math.Min( yy1[i], yy2[i] );
_dragPane.Y2AxisList[i]._scale._max = Math.Max( yy1[i], yy2[i] );
_dragPane.Y2AxisList[i]._scale._minAuto = false;
_dragPane.Y2AxisList[i]._scale._maxAuto = false;
}
}
this.SetScroll( this.hScrollBar1, _dragPane.XAxis, _xScrollRange.Min, _xScrollRange.Max );
this.SetScroll( this.vScrollBar1, _dragPane.YAxis, _yScrollRangeList[0].Min,
_yScrollRangeList[0].Max );
ApplyToAllPanes( _dragPane );
// Provide Callback to notify the user of zoom events
if ( this.ZoomEvent != null )
this.ZoomEvent( this, _zoomState, //oldState,
new ZoomState( _dragPane, ZoomState.StateType.Zoom ) );
using ( Graphics g = this.CreateGraphics() )
{
// always AxisChange() the dragPane
_dragPane.AxisChange( g );
foreach ( GraphPane pane in _masterPane._paneList )
{
if ( pane != _dragPane && ( _isSynchronizeXAxes || _isSynchronizeYAxes ) )
pane.AxisChange( g );
}
}
}
Refresh();
}
private void HandleZoomCancel()
{
if ( _isZooming )
{
_isZooming = false;
Refresh();
ZoomStateClear();
}
}
private PointF BoundPointToRect( Point mousePt, RectangleF rect )
{
PointF newPt = new PointF( mousePt.X, mousePt.Y );
if ( mousePt.X < rect.X ) newPt.X = rect.X;
if ( mousePt.X > rect.Right ) newPt.X = rect.Right;
if ( mousePt.Y < rect.Y ) newPt.Y = rect.Y;
if ( mousePt.Y > rect.Bottom ) newPt.Y = rect.Bottom;
return newPt;
}
private Rectangle CalcScreenRect( Point mousePt1, Point mousePt2 )
{
Point screenPt = PointToScreen( mousePt1 );
Size size = new Size( mousePt2.X - mousePt1.X, mousePt2.Y - mousePt1.Y );
Rectangle rect = new Rectangle( screenPt, size );
if ( _isZooming )
{
Rectangle chartRect = Rectangle.Round( _dragPane.Chart._rect );
Point chartPt = PointToScreen( chartRect.Location );
if ( !_isEnableVZoom )
{
rect.Y = chartPt.Y;
rect.Height = chartRect.Height + 1;
}
else if ( !_isEnableHZoom )
{
rect.X = chartPt.X;
rect.Width = chartRect.Width + 1;
}
}
return rect;
}
#endregion
#region Selection Events
// Revision: JCarpenter 10/06
/// <summary>
/// Perform selection on curves within the drag pane, or under the mouse click.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void HandleSelectionFinish( object sender, MouseEventArgs e )
{
if ( e.Button != _selectButtons )
{
Refresh();
return;
}
PointF mousePtF = BoundPointToRect( new Point( e.X, e.Y ), _dragPane.Chart._rect );
PointF mousePt = BoundPointToRect( new Point( e.X, e.Y ), _dragPane.Rect );
Point curPt = ( (Control)sender ).PointToScreen( Point.Round( mousePt ) );
// Only accept a drag if it covers at least 5 pixels in each direction
//Point curPt = ( (Control)sender ).PointToScreen( Point.Round( mousePt ) );
if ( ( Math.Abs( mousePtF.X - _dragStartPt.X ) > 4 ) &&
( Math.Abs( mousePtF.Y - _dragStartPt.Y ) > 4 ) )
{
#region New Code to Select on Rubber Band
double x1, x2;
double[] y1, y2, yy1, yy2;
PointF startPoint = ( (Control)sender ).PointToClient( new Point( Convert.ToInt32( this._dragPane.Rect.X ), Convert.ToInt32( this._dragPane.Rect.Y ) ) );
_dragPane.ReverseTransform( _dragStartPt, out x1, out y1, out yy1 );
_dragPane.ReverseTransform( mousePtF, out x2, out y2, out yy2 );
CurveList objects = new CurveList();
double left = Math.Min( x1, x2 );
double right = Math.Max( x1, x2 );
double top = 0;
double bottom = 0;
for ( int i = 0; i < y1.Length; i++ )
{
bottom = Math.Min( y1[i], y2[i] );
top = Math.Max( y1[i], y2[i] );
}
for ( int i = 0; i < yy1.Length; i++ )
{
bottom = Math.Min( bottom, yy2[i] );
bottom = Math.Min( yy1[i], bottom );
top = Math.Max( top, yy2[i] );
top = Math.Max( yy1[i], top );
}
double w = right - left;
double h = bottom - top;
RectangleF rF = new RectangleF( (float)left, (float)top, (float)w, (float)h );
_dragPane.FindContainedObjects( rF, this.CreateGraphics(), out objects );
if ( Control.ModifierKeys == _selectAppendModifierKeys )
_selection.AddToSelection( _masterPane, objects );
else
_selection.Select( _masterPane, objects );
// this.Select( objects );
//Graphics g = this.CreateGraphics();
//this._dragPane.AxisChange( g );
//g.Dispose();
#endregion
}
else // It's a single-select
{
#region New Code to Single Select
//Point mousePt = new Point( e.X, e.Y );
int iPt;
GraphPane pane;
object nearestObj;
using ( Graphics g = this.CreateGraphics() )
{
if ( this.MasterPane.FindNearestPaneObject( mousePt, g, out pane,
out nearestObj, out iPt ) )
{
if ( nearestObj is CurveItem && iPt >= 0 )
{
if ( Control.ModifierKeys == _selectAppendModifierKeys )
_selection.AddToSelection( _masterPane, nearestObj as CurveItem );
else
_selection.Select( _masterPane, nearestObj as CurveItem );
}
else
_selection.ClearSelection( _masterPane );
Refresh();
}
else
{
_selection.ClearSelection( _masterPane );
}
}
#endregion New Code to Single Select
}
using ( Graphics g = this.CreateGraphics() )
{
// always AxisChange() the dragPane
_dragPane.AxisChange( g );
foreach ( GraphPane pane in _masterPane._paneList )
{
if ( pane != _dragPane && ( _isSynchronizeXAxes || _isSynchronizeYAxes ) )
pane.AxisChange( g );
}
}
Refresh();
}
private void HandleSelectionCancel()
{
_isSelecting = false;
_selection.ClearSelection( _masterPane );
Refresh();
}
#endregion
#region ScrollBars
private void vScrollBar1_Scroll( object sender, ScrollEventArgs e )
{
if ( this.GraphPane != null )
{
/*
ScrollBar scrollBar = sender as ScrollBar;
bool clearZoomState = false;
//ZoomState curState = new ZoomState( this.GraphPane, ZoomState.StateType.Scroll );
if ( _zoomState == null ) //&& !scrollBar.Capture )
{
clearZoomState = true;
ZoomStateSave( this.GraphPane, ZoomState.StateType.Scroll );
}
*/
for ( int i = 0; i < this.GraphPane.YAxisList.Count; i++ )
{
ScrollRange scroll = _yScrollRangeList[i];
if ( scroll.IsScrollable )
{
Axis axis = this.GraphPane.YAxisList[i];
HandleScroll( axis, e.NewValue, scroll.Min, scroll.Max, vScrollBar1.LargeChange,
!axis.Scale.IsReverse );
}
}
for ( int i = 0; i < this.GraphPane.Y2AxisList.Count; i++ )
{
ScrollRange scroll = _y2ScrollRangeList[i];
if ( scroll.IsScrollable )
{
Axis axis = this.GraphPane.Y2AxisList[i];
HandleScroll( axis, e.NewValue, scroll.Min, scroll.Max, vScrollBar1.LargeChange,
!axis.Scale.IsReverse );
}
}
ApplyToAllPanes( this.GraphPane );
if ( _zoomState != null ) // && ! clearZoomState && scrollBar.Capture )
{
// Provide Callback to notify the user of scroll events
if ( this.ScrollProgressEvent != null )
this.ScrollProgressEvent( this, vScrollBar1, _zoomState,
new ZoomState( this.GraphPane, ZoomState.StateType.Scroll ) );
}
/* else if ( clearZoomState && _zoomState != null && // !scrollBar.Capture &&
_zoomState.IsChanged( this.GraphPane ) )
{
//this.GraphPane.ZoomStack.Push( _zoomState );
ZoomStatePush( this.GraphPane );
// Provide Callback to notify the user of pan events
if ( this.ScrollDoneEvent != null )
this.ScrollDoneEvent( this, scrollBar, _zoomState,
new ZoomState( this.GraphPane, ZoomState.StateType.Scroll ) );
}
if ( clearZoomState )
_zoomState = null;
*/
}
}
private void ApplyToAllPanes( GraphPane primaryPane )
{
foreach ( GraphPane pane in _masterPane._paneList )
{
if ( pane != primaryPane )
{
if ( _isSynchronizeXAxes )
Synchronize( primaryPane.XAxis, pane.XAxis );
if ( _isSynchronizeYAxes )
Synchronize( primaryPane.YAxis, pane.YAxis );
}
}
}
private void Synchronize( Axis source, Axis dest )
{
dest._scale._min = source._scale._min;
dest._scale._max = source._scale._max;
dest._scale._majorStep = source._scale._majorStep;
dest._scale._minorStep = source._scale._minorStep;
dest._scale._minAuto = source._scale._minAuto;
dest._scale._maxAuto = source._scale._maxAuto;
dest._scale._majorStepAuto = source._scale._majorStepAuto;
dest._scale._minorStepAuto = source._scale._minorStepAuto;
}
private void hScrollBar1_Scroll( object sender, ScrollEventArgs e )
{
if ( this.GraphPane != null )
{
HandleScroll( this.GraphPane.XAxis, e.NewValue, _xScrollRange.Min, _xScrollRange.Max,
hScrollBar1.LargeChange, this.GraphPane.XAxis.Scale.IsReverse );
}
ApplyToAllPanes( this.GraphPane );
if ( _zoomState != null && this.GraphPane != null )
{
// Provide Callback to notify the user of pan events
if ( this.ScrollProgressEvent != null )
this.ScrollProgressEvent( this, hScrollBar1, _zoomState,
new ZoomState( this.GraphPane, ZoomState.StateType.Scroll ) );
}
}
/*
/// <summary>
/// Use the MouseCaptureChanged as an indicator for the start and end of a scrolling operation
/// </summary>
private void ScrollBarMouseCaptureChanged( object sender, EventArgs e )
{
ScrollBar scrollBar = sender as ScrollBar;
if ( scrollBar != null )
{
// If this is the start of a new scroll, then Capture will be true
if ( scrollBar.Capture )
{
// save the original zoomstate
//_zoomState = new ZoomState( this.GraphPane, ZoomState.StateType.Scroll );
ZoomStateSave( this.GraphPane, ZoomState.StateType.Scroll );
}
else
{
// push the prior saved zoomstate, since the scale ranges have already been changed on
// the fly during the scrolling operation
if ( _zoomState != null && _zoomState.IsChanged( this.GraphPane ) )
{
//this.GraphPane.ZoomStack.Push( _zoomState );
ZoomStatePush( this.GraphPane );
// Provide Callback to notify the user of pan events
if ( this.ScrollDoneEvent != null )
this.ScrollDoneEvent( this, scrollBar, _zoomState,
new ZoomState( this.GraphPane, ZoomState.StateType.Scroll ) );
_zoomState = null;
}
}
}
}
*/
private void HandleScroll( Axis axis, int newValue, double scrollMin, double scrollMax,
int largeChange, bool reverse )
{
if ( axis != null )
{
if ( scrollMin > axis._scale._min )
scrollMin = axis._scale._min;
if ( scrollMax < axis._scale._max )
scrollMax = axis._scale._max;
int span = _ScrollControlSpan - largeChange;
if ( span <= 0 )
return;
if ( reverse )
newValue = span - newValue;
Scale scale = axis._scale;
double delta = scale._maxLinearized - scale._minLinearized;
double scrollMin2 = scale.Linearize( scrollMax ) - delta;
scrollMin = scale.Linearize( scrollMin );
//scrollMax = scale.Linearize( scrollMax );
double val = scrollMin + (double)newValue / (double)span *
( scrollMin2 - scrollMin );
scale._minLinearized = val;
scale._maxLinearized = val + delta;
/*
if ( axis.Scale.IsLog )
{
double ratio = axis._scale._max / axis._scale._min;
double scrollMin2 = scrollMax / ratio;
double val = scrollMin * Math.Exp( (double)newValue / (double)span *
( Math.Log( scrollMin2 ) - Math.Log( scrollMin ) ) );
axis._scale._min = val;
axis._scale._max = val * ratio;
}
else
{
double delta = axis._scale._max - axis._scale._min;
double scrollMin2 = scrollMax - delta;
double val = scrollMin + (double)newValue / (double)span *
( scrollMin2 - scrollMin );
axis._scale._min = val;
axis._scale._max = val + delta;
}
*/
this.Invalidate();
}
}
/// <summary>
/// Sets the value of the scroll range properties (see <see cref="ScrollMinX" />,
/// <see cref="ScrollMaxX" />, <see cref="YScrollRangeList" />, and
/// <see cref="Y2ScrollRangeList" /> based on the actual range of the data for
/// each corresponding <see cref="Axis" />.
/// </summary>
/// <remarks>
/// This method is called automatically by <see cref="AxisChange" /> if
/// <see cref="IsAutoScrollRange" />
/// is true. Note that this will not be called if you call AxisChange directly from the
/// <see cref="GraphPane" />. For example, zedGraphControl1.AxisChange() works properly, but
/// zedGraphControl1.GraphPane.AxisChange() does not.</remarks>
public void SetScrollRangeFromData()
{
if ( this.GraphPane != null )
{
double grace = CalcScrollGrace( this.GraphPane.XAxis.Scale._rangeMin,
this.GraphPane.XAxis.Scale._rangeMax );
_xScrollRange.Min = this.GraphPane.XAxis.Scale._rangeMin - grace;
_xScrollRange.Max = this.GraphPane.XAxis.Scale._rangeMax + grace;
_xScrollRange.IsScrollable = true;
for ( int i = 0; i < this.GraphPane.YAxisList.Count; i++ )
{
Axis axis = this.GraphPane.YAxisList[i];
grace = CalcScrollGrace( axis.Scale._rangeMin, axis.Scale._rangeMax );
ScrollRange range = new ScrollRange( axis.Scale._rangeMin - grace,
axis.Scale._rangeMax + grace, _yScrollRangeList[i].IsScrollable );
if ( i >= _yScrollRangeList.Count )
_yScrollRangeList.Add( range );
else
_yScrollRangeList[i] = range;
}
for ( int i = 0; i < this.GraphPane.Y2AxisList.Count; i++ )
{
Axis axis = this.GraphPane.Y2AxisList[i];
grace = CalcScrollGrace( axis.Scale._rangeMin, axis.Scale._rangeMax );
ScrollRange range = new ScrollRange( axis.Scale._rangeMin - grace,
axis.Scale._rangeMax + grace, _y2ScrollRangeList[i].IsScrollable );
if ( i >= _y2ScrollRangeList.Count )
_y2ScrollRangeList.Add( range );
else
_y2ScrollRangeList[i] = range;
}
//this.GraphPane.CurveList.GetRange( out scrollMinX, out scrollMaxX,
// out scrollMinY, out scrollMaxY, out scrollMinY2, out scrollMaxY2, false, false,
// this.GraphPane );
}
}
private double CalcScrollGrace( double min, double max )
{
if ( Math.Abs( max - min ) < 1e-30 )
{
if ( Math.Abs( max ) < 1e-30 )
return _scrollGrace;
else
return max * _scrollGrace;
}
else
return ( max - min ) * _scrollGrace;
}
private void SetScroll( ScrollBar scrollBar, Axis axis, double scrollMin, double scrollMax )
{
if ( scrollBar != null && axis != null )
{
scrollBar.Minimum = 0;
scrollBar.Maximum = _ScrollControlSpan - 1;
if ( scrollMin > axis._scale._min )
scrollMin = axis._scale._min;
if ( scrollMax < axis._scale._max )
scrollMax = axis._scale._max;
int val = 0;
Scale scale = axis._scale;
double minLinearized = scale._minLinearized;
double maxLinearized = scale._maxLinearized;
scrollMin = scale.Linearize( scrollMin );
scrollMax = scale.Linearize( scrollMax );
double scrollMin2 = scrollMax - ( maxLinearized - minLinearized );
/*
if ( axis.Scale.IsLog )
scrollMin2 = scrollMax / ( axis._scale._max / axis._scale._min );
else
scrollMin2 = scrollMax - ( axis._scale._max - axis._scale._min );
*/
if ( scrollMin >= scrollMin2 )
{
//scrollBar.Visible = false;
scrollBar.Enabled = false;
scrollBar.Value = 0;
}
else
{
double ratio = ( maxLinearized - minLinearized ) / ( scrollMax - scrollMin );
/*
if ( axis.Scale.IsLog )
ratio = ( Math.Log( axis._scale._max ) - Math.Log( axis._scale._min ) ) /
( Math.Log( scrollMax ) - Math.Log( scrollMin ) );
else
ratio = ( axis._scale._max - axis._scale._min ) / ( scrollMax - scrollMin );
*/
int largeChange = (int)( ratio * _ScrollControlSpan + 0.5 );
if ( largeChange < 1 )
largeChange = 1;
scrollBar.LargeChange = largeChange;
int smallChange = largeChange / _ScrollSmallRatio;
if ( smallChange < 1 )
smallChange = 1;
scrollBar.SmallChange = smallChange;
int span = _ScrollControlSpan - largeChange;
val = (int)( ( minLinearized - scrollMin ) / ( scrollMin2 - scrollMin ) *
span + 0.5 );
/*
if ( axis.Scale.IsLog )
val = (int)( ( Math.Log( axis._scale._min ) - Math.Log( scrollMin ) ) /
( Math.Log( scrollMin2 ) - Math.Log( scrollMin ) ) * span + 0.5 );
else
val = (int)( ( axis._scale._min - scrollMin ) / ( scrollMin2 - scrollMin ) *
span + 0.5 );
*/
if ( val < 0 )
val = 0;
else if ( val > span )
val = span;
//if ( ( axis is XAxis && axis.IsReverse ) || ( ( ! axis is XAxis ) && ! axis.IsReverse ) )
if ( ( axis is XAxis ) == axis.Scale.IsReverse )
val = span - val;
if ( val < scrollBar.Minimum )
val = scrollBar.Minimum;
if ( val > scrollBar.Maximum )
val = scrollBar.Maximum;
scrollBar.Value = val;
scrollBar.Enabled = true;
//scrollBar.Visible = true;
}
}
}
#endregion
#region ContextMenu
// Revision: JCarpenter 10/06
/// <summary>
/// Public enumeration that specifies the type of
/// object present at the Context Menu's mouse location
/// </summary>
public enum ContextMenuObjectState
{
/// <summary>
/// The object is an Inactive Curve Item at the Context Menu's mouse position
/// </summary>
InactiveSelection,
/// <summary>
/// The object is an active Curve Item at the Context Menu's mouse position
/// </summary>
ActiveSelection,
/// <summary>
/// There is no selectable object present at the Context Menu's mouse position
/// </summary>
Background
}
//Revision: JCarpenter 10/06
/// <summary>
/// Find the object currently under the mouse cursor, and return its state.
/// </summary>
private ContextMenuObjectState GetObjectState()
{
ContextMenuObjectState objState = ContextMenuObjectState.Background;
// Determine object state
Point mousePt = this.PointToClient( Control.MousePosition );
int iPt;
GraphPane pane;
object nearestObj;
using ( Graphics g = this.CreateGraphics() )
{
if ( this.MasterPane.FindNearestPaneObject( mousePt, g, out pane,
out nearestObj, out iPt ) )
{
CurveItem item = nearestObj as CurveItem;
if ( item != null && iPt >= 0 )
{
if ( item.IsSelected )
objState = ContextMenuObjectState.ActiveSelection;
else
objState = ContextMenuObjectState.InactiveSelection;
}
}
}
return objState;
}
/// <summary>
/// protected method to handle the popup context menu in the <see cref="ZedGraphControl"/>.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void ContextMenu_Popup( object sender, System.EventArgs e )
{
//Revision: JCarpenter 10/06
ContextMenuObjectState objState = GetObjectState();
if ( this.contextMenu != null && this._masterPane != null )
{
contextMenu.MenuItems.Clear();
this._isZooming = false;
this._isPanning = false;
Cursor.Current = Cursors.Default;
this._menuClickPt = this.PointToClient( Control.MousePosition );
GraphPane pane = this._masterPane.FindPane( this._menuClickPt );
if ( this._isShowContextMenu )
{
MenuItem menuItem;
int index = 0;
menuItem = new MenuItem();
menuItem.Index = index++;
//menuItem.Tag = "copy";
string menuStr = this._resourceManager.GetString( "copy" );
menuItem.Text = menuStr;
this.contextMenu.MenuItems.Add( menuItem );
menuItem.Click += new System.EventHandler( this.MenuClick_Copy );
menuItem = new MenuItem();
menuItem.Index = index++;
//menuItem.Tag = "save_as";
menuStr = _resourceManager.GetString( "save_as" );
menuItem.Text = menuStr;
this.contextMenu.MenuItems.Add( menuItem );
menuItem.Click += new System.EventHandler( this.MenuClick_SaveAs );
menuItem = new MenuItem();
menuItem.Index = index++;
//menuItem.Tag = "page_setup";
menuStr = _resourceManager.GetString( "page_setup" );
menuItem.Text = menuStr;
this.contextMenu.MenuItems.Add( menuItem );
menuItem.Click += new System.EventHandler( this.MenuClick_PageSetup );
menuItem = new MenuItem();
menuItem.Index = index++;
//menuItem.Tag = "print";
menuStr = _resourceManager.GetString( "print" );
menuItem.Text = menuStr;
this.contextMenu.MenuItems.Add( menuItem );
menuItem.Click += new System.EventHandler( this.MenuClick_Print );
menuItem = new MenuItem();
menuItem.Index = index++;
//menuItem.Tag = "show_val";
menuStr = _resourceManager.GetString( "show_val" );
menuItem.Text = menuStr;
menuItem.Checked = this.IsShowPointValues;
this.contextMenu.MenuItems.Add( menuItem );
menuItem.Click += new System.EventHandler( this.MenuClick_ShowValues );
menuItem = new MenuItem();
menuItem.Index = index++;
//menuItem.Tag = "unzoom";
if ( pane == null || pane.ZoomStack.IsEmpty )
menuStr = _resourceManager.GetString( "unzoom" );
else
{
switch ( pane.ZoomStack.Top.Type )
{
case ZoomState.StateType.Zoom:
case ZoomState.StateType.WheelZoom:
menuStr = _resourceManager.GetString( "unzoom" );
break;
case ZoomState.StateType.Pan:
menuStr = _resourceManager.GetString( "unpan" );
break;
case ZoomState.StateType.Scroll:
menuStr = _resourceManager.GetString( "unscroll" );
break;
}
}
//menuItem.Text = "Un-" + ( ( pane == null || pane.zoomStack.IsEmpty ) ?
// "Zoom" : pane.zoomStack.Top.TypeString );
menuItem.Text = menuStr;
this.contextMenu.MenuItems.Add( menuItem );
menuItem.Click += new EventHandler( this.MenuClick_ZoomOut );
if ( pane == null || pane.ZoomStack.IsEmpty )
menuItem.Enabled = false;
menuItem = new MenuItem();
menuItem.Index = index++;
//menuItem.Tag = "undo_all";
menuStr = _resourceManager.GetString( "undo_all" );
menuItem.Text = menuStr;
this.contextMenu.MenuItems.Add( menuItem );
menuItem.Click += new EventHandler( this.MenuClick_ZoomOutAll );
if ( pane == null || pane.ZoomStack.IsEmpty )
menuItem.Enabled = false;
menuItem = new MenuItem();
menuItem.Index = index++;
//menuItem.Tag = "set_default";
menuStr = _resourceManager.GetString( "set_default" );
menuItem.Text = menuStr;
this.contextMenu.MenuItems.Add( menuItem );
menuItem.Click += new EventHandler( this.MenuClick_RestoreScale );
if ( pane == null )
menuItem.Enabled = false;
// Provide Callback for User to edit the context menu
//Revision: JCarpenter 10/06 - add ContextMenuObjectState objState
if ( this.ContextMenuBuilder != null )
this.ContextMenuBuilder( this, this.contextMenu, this._menuClickPt, objState );
}
}
}
/// <summary>
/// Handler for the "Copy" context menu item. Copies the current image to a bitmap on the
/// clipboard.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void MenuClick_Copy( System.Object sender, System.EventArgs e )
{
Copy( _isShowCopyMessage );
}
/// <summary>
/// Handler for the "Copy" context menu item. Copies the current image to a bitmap on the
/// clipboard.
/// </summary>
/// <param name="isShowMessage">boolean value that determines whether or not a prompt will be
/// displayed. true to show a message of "Image Copied to ClipBoard".</param>
public void Copy( bool isShowMessage )
{
if ( _masterPane != null )
{
//Clipboard.SetDataObject( _masterPane.GetImage(), true );
// Threaded copy mode to avoid crash with MTA
// Contributed by Dave Moor
Thread ct = new Thread( new ThreadStart( this.ClipboardCopyThread ) );
//ct.ApartmentState = ApartmentState.STA;
ct.ApartmentState = ApartmentState.STA;
//ct.SetApartmentState( ApartmentState.STA );
ct.Start();
ct.Join();
if ( isShowMessage )
{
string str = _resourceManager.GetString( "copied_to_clip" );
//MessageBox.Show( "Image Copied to ClipBoard" );
MessageBox.Show( str );
}
}
}
/// <summary>
/// A threaded version of the copy method to avoid crash with MTA
/// </summary>
private void ClipboardCopyThread()
{
Clipboard.SetDataObject( _masterPane.GetImage(), true );
}
/// <summary>
/// Handler for the "Save Image As" context menu item. Copies the current image to the selected
/// file.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void MenuClick_SaveAs( System.Object sender, System.EventArgs e )
{
SaveAs();
}
/// <summary>
/// Handler for the "Save Image As" context menu item. Copies the current image to the selected
/// file in either the Emf (vector), or a variety of Bitmap formats.
/// </summary>
/// <remarks>
/// Note that <see cref="SaveAsBitmap" /> and <see cref="SaveAsEmf" /> methods are provided
/// which allow for Bitmap-only or Emf-only handling of the "Save As" context menu item.
/// </remarks>
public void SaveAs()
{
if ( _masterPane != null )
{
_saveFileDialog.Filter =
"Emf Format (*.emf)|*.emf|" +
"PNG Format (*.png)|*.png|" +
"Gif Format (*.gif)|*.gif|" +
"Jpeg Format (*.jpg)|*.jpg|" +
"Tiff Format (*.tif)|*.tif|" +
"Bmp Format (*.bmp)|*.bmp";
if ( _saveFileDialog.ShowDialog() == DialogResult.OK )
{
Stream myStream = _saveFileDialog.OpenFile();
if ( myStream != null )
{
if ( _saveFileDialog.FilterIndex == 1 )
{
myStream.Close();
_masterPane.GetMetafile().Save( _saveFileDialog.FileName );
}
else
{
ImageFormat format = ImageFormat.Png;
if ( _saveFileDialog.FilterIndex == 3 )
format = ImageFormat.Gif;
else if ( _saveFileDialog.FilterIndex == 4 )
format = ImageFormat.Jpeg;
else if ( _saveFileDialog.FilterIndex == 5 )
format = ImageFormat.Tiff;
else if ( _saveFileDialog.FilterIndex == 6 )
format = ImageFormat.Bmp;
_masterPane.GetImage().Save( myStream, format );
myStream.Close();
}
}
}
}
}
/// <summary>
/// Handler for the "Save Image As" context menu item. Copies the current image to the selected
/// Bitmap file.
/// </summary>
/// <remarks>
/// Note that this handler saves as a bitmap only. The default handler is
/// <see cref="SaveAs" />, which allows for Bitmap or EMF formats
/// </remarks>
public void SaveAsBitmap()
{
if ( _masterPane != null )
{
_saveFileDialog.Filter =
"PNG Format (*.png)|*.png|" +
"Gif Format (*.gif)|*.gif|" +
"Jpeg Format (*.jpg)|*.jpg|" +
"Tiff Format (*.tif)|*.tif|" +
"Bmp Format (*.bmp)|*.bmp";
if ( _saveFileDialog.ShowDialog() == DialogResult.OK )
{
ImageFormat format = ImageFormat.Png;
if ( _saveFileDialog.FilterIndex == 2 )
format = ImageFormat.Gif;
else if ( _saveFileDialog.FilterIndex == 3 )
format = ImageFormat.Jpeg;
else if ( _saveFileDialog.FilterIndex == 4 )
format = ImageFormat.Tiff;
else if ( _saveFileDialog.FilterIndex == 5 )
format = ImageFormat.Bmp;
Stream myStream = _saveFileDialog.OpenFile();
if ( myStream != null )
{
_masterPane.GetImage().Save( myStream, format );
myStream.Close();
}
}
}
}
/// <summary>
/// Handler for the "Save Image As" context menu item. Copies the current image to the selected
/// Emf format file.
/// </summary>
/// <remarks>
/// Note that this handler saves as an Emf format only. The default handler is
/// <see cref="SaveAs" />, which allows for Bitmap or EMF formats.
/// </remarks>
public void SaveAsEmf()
{
if ( _masterPane != null )
{
_saveFileDialog.Filter = "Emf Format (*.emf)|*.emf";
if ( _saveFileDialog.ShowDialog() == DialogResult.OK )
{
Stream myStream = _saveFileDialog.OpenFile();
if ( myStream != null )
{
myStream.Close();
_masterPane.GetMetafile().Save( _saveFileDialog.FileName );
}
}
}
}
/// <summary>
/// Handler for the "Show Values" context menu item. Toggles the <see cref="IsShowPointValues"/>
/// property, which activates the point value tooltips.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void MenuClick_ShowValues( object sender, System.EventArgs e )
{
this.IsShowPointValues = !( (MenuItem)sender ).Checked;
}
/// <summary>
/// Handler for the "Set Scale to Default" context menu item. Sets the scale ranging to
/// full auto mode for all axes.
/// </summary>
/// <remarks>
/// This method differs from the <see cref="ZoomOutAll" /> method in that it sets the scales
/// to full auto mode. The <see cref="ZoomOutAll" /> method sets the scales to their initial
/// setting prior to any user actions (which may or may not be full auto mode).
/// </remarks>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void MenuClick_RestoreScale( object sender, EventArgs e )
{
if ( _masterPane != null )
{
GraphPane pane = _masterPane.FindPane( _menuClickPt );
RestoreScale( pane );
}
}
/// <summary>
/// Handler for the "Set Scale to Default" context menu item. Sets the scale ranging to
/// full auto mode for all axes.
/// </summary>
/// <remarks>
/// This method differs from the <see cref="ZoomOutAll" /> method in that it sets the scales
/// to full auto mode. The <see cref="ZoomOutAll" /> method sets the scales to their initial
/// setting prior to any user actions (which may or may not be full auto mode).
/// </remarks>
/// <param name="primaryPane">The <see cref="GraphPane" /> object which is to have the
/// scale restored</param>
public void RestoreScale( GraphPane primaryPane )
{
if ( primaryPane != null )
{
//Go ahead and save the old zoomstates, which provides an "undo"-like capability
//ZoomState oldState = primaryPane.ZoomStack.Push( primaryPane, ZoomState.StateType.Zoom );
ZoomState oldState = new ZoomState( primaryPane, ZoomState.StateType.Zoom );
using ( Graphics g = this.CreateGraphics() )
{
if ( _isSynchronizeXAxes || _isSynchronizeYAxes )
{
foreach ( GraphPane pane in _masterPane._paneList )
{
pane.ZoomStack.Push( pane, ZoomState.StateType.Zoom );
ResetAutoScale( pane, g );
}
}
else
{
primaryPane.ZoomStack.Push( primaryPane, ZoomState.StateType.Zoom );
ResetAutoScale( primaryPane, g );
}
// Provide Callback to notify the user of zoom events
if ( this.ZoomEvent != null )
this.ZoomEvent( this, oldState, new ZoomState( primaryPane, ZoomState.StateType.Zoom ) );
//g.Dispose();
}
Refresh();
}
}
private void ResetAutoScale( GraphPane pane, Graphics g )
{
pane.XAxis.ResetAutoScale( pane, g );
foreach ( YAxis axis in pane.YAxisList )
axis.ResetAutoScale( pane, g );
foreach ( Y2Axis axis in pane.Y2AxisList )
axis.ResetAutoScale( pane, g );
}
/*
public void RestoreScale( GraphPane primaryPane )
{
if ( primaryPane != null )
{
Graphics g = this.CreateGraphics();
ZoomState oldState = new ZoomState( primaryPane, ZoomState.StateType.Zoom );
//ZoomState newState = null;
if ( _isSynchronizeXAxes || _isSynchronizeYAxes )
{
foreach ( GraphPane pane in _masterPane._paneList )
{
if ( pane == primaryPane )
{
pane.XAxis.ResetAutoScale( pane, g );
foreach ( YAxis axis in pane.YAxisList )
axis.ResetAutoScale( pane, g );
foreach ( Y2Axis axis in pane.Y2AxisList )
axis.ResetAutoScale( pane, g );
}
}
}
else
{
primaryPane.XAxis.ResetAutoScale( primaryPane, g );
foreach ( YAxis axis in primaryPane.YAxisList )
axis.ResetAutoScale( primaryPane, g );
foreach ( Y2Axis axis in primaryPane.Y2AxisList )
axis.ResetAutoScale( primaryPane, g );
}
// Provide Callback to notify the user of zoom events
if ( this.ZoomEvent != null )
this.ZoomEvent( this, oldState, new ZoomState( primaryPane, ZoomState.StateType.Zoom ) );
g.Dispose();
Refresh();
}
}
*/
/*
public void ZoomOutAll( GraphPane primaryPane )
{
if ( primaryPane != null && !primaryPane.ZoomStack.IsEmpty )
{
ZoomState.StateType type = primaryPane.ZoomStack.Top.Type;
ZoomState oldState = new ZoomState( primaryPane, type );
//ZoomState newState = pane.ZoomStack.PopAll( pane );
ZoomState newState = null;
if ( _isSynchronizeXAxes || _isSynchronizeYAxes )
{
foreach ( GraphPane pane in _masterPane._paneList )
{
ZoomState state = pane.ZoomStack.PopAll( pane );
if ( pane == primaryPane )
newState = state;
}
}
else
newState = primaryPane.ZoomStack.PopAll( primaryPane );
// Provide Callback to notify the user of zoom events
if ( this.ZoomEvent != null )
this.ZoomEvent( this, oldState, newState );
Refresh();
}
}
*/
/// <summary>
/// Handler for the "UnZoom/UnPan" context menu item. Restores the scale ranges to the values
/// before the last zoom or pan operation.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void MenuClick_ZoomOut( System.Object sender, System.EventArgs e )
{
if ( _masterPane != null )
{
GraphPane pane = _masterPane.FindPane( _menuClickPt );
ZoomOut( pane );
}
}
/// <summary>
/// Handler for the "UnZoom/UnPan" context menu item. Restores the scale ranges to the values
/// before the last zoom, pan, or scroll operation.
/// </summary>
/// <remarks>
/// Triggers a <see cref="ZoomEvent" /> for any type of undo (including pan, scroll, zoom, and
/// wheelzoom). This method will affect all the
/// <see cref="GraphPane" /> objects in the <see cref="MasterPane" /> if
/// <see cref="IsSynchronizeXAxes" /> or <see cref="IsSynchronizeYAxes" /> is true.
/// </remarks>
/// <param name="primaryPane">The primary <see cref="GraphPane" /> object which is to be
/// zoomed out</param>
public void ZoomOut( GraphPane primaryPane )
{
if ( primaryPane != null && !primaryPane.ZoomStack.IsEmpty )
{
ZoomState.StateType type = primaryPane.ZoomStack.Top.Type;
ZoomState oldState = new ZoomState( primaryPane, type );
ZoomState newState = null;
if ( _isSynchronizeXAxes || _isSynchronizeYAxes )
{
foreach ( GraphPane pane in _masterPane._paneList )
{
ZoomState state = pane.ZoomStack.Pop( pane );
if ( pane == primaryPane )
newState = state;
}
}
else
newState = primaryPane.ZoomStack.Pop( primaryPane );
// Provide Callback to notify the user of zoom events
if ( this.ZoomEvent != null )
this.ZoomEvent( this, oldState, newState );
Refresh();
}
}
/// <summary>
/// Handler for the "Undo All Zoom/Pan" context menu item. Restores the scale ranges to the values
/// before all zoom and pan operations
/// </summary>
/// <remarks>
/// This method differs from the <see cref="RestoreScale" /> method in that it sets the scales
/// to their initial setting prior to any user actions. The <see cref="RestoreScale" /> method
/// sets the scales to full auto mode (regardless of what the initial setting may have been).
/// </remarks>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void MenuClick_ZoomOutAll( System.Object sender, System.EventArgs e )
{
if ( _masterPane != null )
{
GraphPane pane = _masterPane.FindPane( _menuClickPt );
ZoomOutAll( pane );
}
}
/// <summary>
/// Handler for the "Undo All Zoom/Pan" context menu item. Restores the scale ranges to the values
/// before all zoom and pan operations
/// </summary>
/// <remarks>
/// This method differs from the <see cref="RestoreScale" /> method in that it sets the scales
/// to their initial setting prior to any user actions. The <see cref="RestoreScale" /> method
/// sets the scales to full auto mode (regardless of what the initial setting may have been).
/// </remarks>
/// <param name="primaryPane">The <see cref="GraphPane" /> object which is to be zoomed out</param>
public void ZoomOutAll( GraphPane primaryPane )
{
if ( primaryPane != null && !primaryPane.ZoomStack.IsEmpty )
{
ZoomState.StateType type = primaryPane.ZoomStack.Top.Type;
ZoomState oldState = new ZoomState( primaryPane, type );
//ZoomState newState = pane.ZoomStack.PopAll( pane );
ZoomState newState = null;
if ( _isSynchronizeXAxes || _isSynchronizeYAxes )
{
foreach ( GraphPane pane in _masterPane._paneList )
{
ZoomState state = pane.ZoomStack.PopAll( pane );
if ( pane == primaryPane )
newState = state;
}
}
else
newState = primaryPane.ZoomStack.PopAll( primaryPane );
// Provide Callback to notify the user of zoom events
if ( this.ZoomEvent != null )
this.ZoomEvent( this, oldState, newState );
Refresh();
}
}
#endregion
#region Printing
/// <summary>
/// Handler for the "Page Setup..." context menu item. Displays a
/// <see cref="PageSetupDialog" />.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void MenuClick_PageSetup( object sender, EventArgs e )
{
DoPageSetup();
}
/// <summary>
/// Handler for the "Print..." context menu item. Displays a
/// <see cref="PrintDialog" />.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void MenuClick_Print( object sender, EventArgs e )
{
DoPrint();
}
/// <summary>
/// Rendering method used by the print context menu items
/// </summary>
/// <param name="sender">The applicable <see cref="PrintDocument" />.</param>
/// <param name="e">A <see cref="PrintPageEventArgs" /> instance providing
/// page bounds, margins, and a Graphics instance for this printed output.
/// </param>
private void Graph_PrintPage( object sender, PrintPageEventArgs e )
{
PrintDocument pd = sender as PrintDocument;
MasterPane mPane = this.MasterPane;
bool[] isPenSave = new bool[mPane.PaneList.Count + 1];
bool[] isFontSave = new bool[mPane.PaneList.Count + 1];
isPenSave[0] = mPane.IsPenWidthScaled;
isFontSave[0] = mPane.IsFontsScaled;
for ( int i = 0; i < mPane.PaneList.Count; i++ )
{
isPenSave[i + 1] = mPane[i].IsPenWidthScaled;
isFontSave[i + 1] = mPane[i].IsFontsScaled;
if ( _isPrintScaleAll )
{
mPane[i].IsPenWidthScaled = true;
mPane[i].IsFontsScaled = true;
}
}
RectangleF saveRect = mPane.Rect;
SizeF newSize = mPane.Rect.Size;
if ( _isPrintFillPage && _isPrintKeepAspectRatio )
{
float xRatio = (float)e.MarginBounds.Width / (float)newSize.Width;
float yRatio = (float)e.MarginBounds.Height / (float)newSize.Height;
float ratio = Math.Min( xRatio, yRatio );
newSize.Width *= ratio;
newSize.Height *= ratio;
}
else if ( _isPrintFillPage )
newSize = e.MarginBounds.Size;
mPane.ReSize( e.Graphics, new RectangleF( e.MarginBounds.Left,
e.MarginBounds.Top, newSize.Width, newSize.Height ) );
mPane.Draw( e.Graphics );
using ( Graphics g = this.CreateGraphics() )
{
mPane.ReSize( g, saveRect );
//g.Dispose();
}
mPane.IsPenWidthScaled = isPenSave[0];
mPane.IsFontsScaled = isFontSave[0];
for ( int i = 0; i < mPane.PaneList.Count; i++ )
{
mPane[i].IsPenWidthScaled = isPenSave[i + 1];
mPane[i].IsFontsScaled = isFontSave[i + 1];
}
}
/// <summary>
/// Gets or sets the <see cref="System.Drawing.Printing.PrintDocument" /> instance
/// that is used for all of the context menu printing functions.
/// </summary>
public PrintDocument PrintDocument
{
get
{
// Add a try/catch pair since the users of the control can't catch this one
try
{
if ( _pdSave == null )
{
_pdSave = new PrintDocument();
_pdSave.PrintPage += new PrintPageEventHandler( Graph_PrintPage );
}
}
catch ( Exception exception )
{
MessageBox.Show( exception.Message );
}
return _pdSave;
}
set { _pdSave = value; }
}
/// <summary>
/// Display a <see cref="PageSetupDialog" /> to the user, allowing them to modify
/// the print settings for this <see cref="ZedGraphControl" />.
/// </summary>
public void DoPageSetup()
{
PrintDocument pd = PrintDocument;
// Add a try/catch pair since the users of the control can't catch this one
try
{
if ( pd != null )
{
//pd.PrintPage += new PrintPageEventHandler( GraphPrintPage );
PageSetupDialog setupDlg = new PageSetupDialog();
setupDlg.Document = pd;
if ( setupDlg.ShowDialog() == DialogResult.OK )
{
pd.PrinterSettings = setupDlg.PrinterSettings;
pd.DefaultPageSettings = setupDlg.PageSettings;
// BUG in PrintDocument!!! Converts in/mm repeatedly
// http://support.microsoft.com/?id=814355
// from http://www.vbinfozine.com/tpagesetupdialog.shtml, by Palo Mraz
//if ( System.Globalization.RegionInfo.CurrentRegion.IsMetric )
//{
// setupDlg.Document.DefaultPageSettings.Margins = PrinterUnitConvert.Convert(
// setupDlg.Document.DefaultPageSettings.Margins,
// PrinterUnit.Display, PrinterUnit.TenthsOfAMillimeter );
//}
}
}
}
catch ( Exception exception )
{
MessageBox.Show( exception.Message );
}
}
/// <summary>
/// Display a <see cref="PrintDialog" /> to the user, allowing them to select a
/// printer and print the <see cref="MasterPane" /> contained in this
/// <see cref="ZedGraphControl" />.
/// </summary>
public void DoPrint()
{
// Add a try/catch pair since the users of the control can't catch this one
try
{
PrintDocument pd = PrintDocument;
if ( pd != null )
{
//pd.PrintPage += new PrintPageEventHandler( Graph_PrintPage );
PrintDialog pDlg = new PrintDialog();
pDlg.Document = pd;
if ( pDlg.ShowDialog() == DialogResult.OK )
pd.Print();
}
}
catch ( Exception exception )
{
MessageBox.Show( exception.Message );
}
}
/// <summary>
/// Display a <see cref="PrintPreviewDialog" />, allowing the user to preview and
/// subsequently print the <see cref="MasterPane" /> contained in this
/// <see cref="ZedGraphControl" />.
/// </summary>
public void DoPrintPreview()
{
// Add a try/catch pair since the users of the control can't catch this one
try
{
PrintDocument pd = PrintDocument;
if ( pd != null )
{
PrintPreviewDialog ppd = new PrintPreviewDialog();
//pd.PrintPage += new PrintPageEventHandler( Graph_PrintPage );
ppd.Document = pd;
ppd.Show();
}
}
catch ( Exception exception )
{
MessageBox.Show( exception.Message );
}
}
#endregion
#region Zoom States
/// <summary>
/// Save the current states of the GraphPanes to a separate collection. Save a single
/// (<see paramref="primaryPane" />) GraphPane if the panes are not synchronized
/// (see <see cref="IsSynchronizeXAxes" /> and <see cref="IsSynchronizeYAxes" />),
/// or save a list of states for all GraphPanes if the panes are synchronized.
/// </summary>
/// <param name="primaryPane">The primary GraphPane on which zoom/pan/scroll operations
/// are taking place</param>
/// <param name="type">The <see cref="ZoomState.StateType" /> that describes the
/// current operation</param>
/// <returns>The <see cref="ZoomState" /> that corresponds to the
/// <see paramref="primaryPane" />.
/// </returns>
private ZoomState ZoomStateSave( GraphPane primaryPane, ZoomState.StateType type )
{
ZoomStateClear();
if ( _isSynchronizeXAxes || _isSynchronizeYAxes )
{
foreach ( GraphPane pane in _masterPane._paneList )
{
ZoomState state = new ZoomState( pane, type );
if ( pane == primaryPane )
_zoomState = state;
_zoomStateStack.Add( state );
}
}
else
_zoomState = new ZoomState( primaryPane, type );
return _zoomState;
}
/// <summary>
/// Restore the states of the GraphPanes to a previously saved condition (via
/// <see cref="ZoomStateSave" />. This is essentially an "undo" for live
/// pan and scroll actions. Restores a single
/// (<see paramref="primaryPane" />) GraphPane if the panes are not synchronized
/// (see <see cref="IsSynchronizeXAxes" /> and <see cref="IsSynchronizeYAxes" />),
/// or save a list of states for all GraphPanes if the panes are synchronized.
/// </summary>
/// <param name="primaryPane">The primary GraphPane on which zoom/pan/scroll operations
/// are taking place</param>
private void ZoomStateRestore( GraphPane primaryPane )
{
if ( _isSynchronizeXAxes || _isSynchronizeYAxes )
{
for ( int i = 0; i < _masterPane._paneList.Count; i++ )
{
if ( i < _zoomStateStack.Count )
_zoomStateStack[i].ApplyState( _masterPane._paneList[i] );
}
}
else if ( _zoomState != null )
_zoomState.ApplyState( primaryPane );
ZoomStateClear();
}
/// <summary>
/// Place the previously saved states of the GraphPanes on the individual GraphPane
/// <see cref="ZedGraph.GraphPane.ZoomStack" /> collections. This provides for an
/// option to undo the state change at a later time. Save a single
/// (<see paramref="primaryPane" />) GraphPane if the panes are not synchronized
/// (see <see cref="IsSynchronizeXAxes" /> and <see cref="IsSynchronizeYAxes" />),
/// or save a list of states for all GraphPanes if the panes are synchronized.
/// </summary>
/// <param name="primaryPane">The primary GraphPane on which zoom/pan/scroll operations
/// are taking place</param>
/// <returns>The <see cref="ZoomState" /> that corresponds to the
/// <see paramref="primaryPane" />.
/// </returns>
private void ZoomStatePush( GraphPane primaryPane )
{
if ( _isSynchronizeXAxes || _isSynchronizeYAxes )
{
for ( int i = 0; i < _masterPane._paneList.Count; i++ )
{
if ( i < _zoomStateStack.Count )
_masterPane._paneList[i].ZoomStack.Add( _zoomStateStack[i] );
}
}
else if ( _zoomState != null )
primaryPane.ZoomStack.Add( _zoomState );
ZoomStateClear();
}
/// <summary>
/// Clear the collection of saved states.
/// </summary>
private void ZoomStateClear()
{
_zoomStateStack.Clear();
_zoomState = null;
}
/// <summary>
/// Clear all states from the undo stack for each GraphPane.
/// </summary>
private void ZoomStatePurge()
{
foreach ( GraphPane pane in _masterPane._paneList )
pane.ZoomStack.Clear();
}
#endregion
}
}