//============================================================================
//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
//=============================================================================
#region Using directives
using System;
using System.Text;
using System.Drawing;
using System.Collections;
using System.Runtime.Serialization;
using System.Security.Permissions;
#endregion
namespace DrawGraph
{
///
/// A collection class containing a list of objects
/// organized together in some form.
///
///
/// John Champion
/// $Revision: 3.24 $ $Date: 2007/06/02 06:56:03 $
[Serializable]
public class MasterPane : PaneBase, ICloneable, ISerializable, IDeserializationCallback
{
#region Fields
///
/// Private field that holds a collection of objects for inclusion
/// in this . Use the public property
/// to access this collection.
///
internal PaneList _paneList;
///
/// Private field that sets the amount of space between the GraphPanes. Use the public property
/// to access this value;
///
internal float _innerPaneGap;
///
///Private field that stores a boolean value which signifies whether all
///s in the chart use the same entries in their
/// If set to true, only one set of entries will be displayed in
///this instance. If set to false, this instance will display all
///entries from all s.
///
private bool _isUniformLegendEntries;
///
/// private field that determines if the
///
/// function will automatically set
/// the of each in the
/// such that the scale factors have the same value.
///
private bool _isCommonScaleFactor;
///
/// private field that saves the paneLayout format specified when
/// was called. This value will
/// default to if
/// (or an overload) was never called.
///
internal PaneLayout _paneLayout;
///
/// Private field that stores the boolean value that determines whether
/// is specifying rows or columns.
///
internal bool _isColumnSpecified;
///
/// private field that stores the row/column item count that was specified to the
/// method. This values will be
/// null if was never called.
///
internal int[] _countList;
///
/// private field that stores the row/column size proportional values as specified
/// to the method. This
/// value will be null if
/// was never called.
///
internal float[] _prop;
/* ///
/// private field to store the instance, which
/// manages the persistence and handling of pane layout information.
///
private PaneLayoutMgr _paneLayoutMgr;
*/
#endregion
#region Defaults
///
/// A simple struct that defines the
/// default property values for the class.
///
public new struct Default
{
///
/// The default pane layout for
///
/// method calls.
///
///
///
///
///
///
public static PaneLayout PaneLayout = PaneLayout.SquareColPreferred;
///
/// The default value for the property.
/// This is the size of the margin between adjacent
/// objects, in units of points (1/72 inch).
///
///
public static float InnerPaneGap = 10;
///
/// The default value for the property for
/// the class.
///
public static bool IsShowLegend = false;
///
/// The default value for the property.
///
public static bool IsUniformLegendEntries = false;
///
/// The default value for the property.
///
public static bool IsCommonScaleFactor = false;
}
#endregion
#region Properties
///
/// Gets or sets the collection instance that holds the list of
/// objects that are included in this .
///
///
///
public PaneList PaneList
{
get { return _paneList; }
set { _paneList = value; }
}
/*
///
/// Gets the instance, which manages the pane layout
/// settings, and handles the layout functions.
///
///
///
///
///
///
public PaneLayoutMgr PaneLayoutMgr
{
get { return _paneLayoutMgr; }
}
*/
///
/// Gets or sets the size of the margin between adjacent
/// objects.
///
/// This property is scaled according to ,
/// based on . The default value comes from
/// .
///
/// The value is in points (1/72nd inch).
public float InnerPaneGap
{
get { return _innerPaneGap; }
set { _innerPaneGap = value; }
}
///
/// Gets or set the value of the
///
public bool IsUniformLegendEntries
{
get { return (_isUniformLegendEntries); }
set { _isUniformLegendEntries = value; }
}
///
/// Gets or sets a value that determines if the
/// method will automatically set the
///
/// of each in the such that the
/// scale factors have the same value.
///
///
/// The scale factors, calculated by , determine
/// scaled font sizes, tic lengths, etc. This function will insure that for
/// multiple graphpanes, a certain specified font size will be the same for
/// all the panes.
///
///
///
///
///
///
public bool IsCommonScaleFactor
{
get { return _isCommonScaleFactor; }
set { _isCommonScaleFactor = value; }
}
#endregion
#region Constructors
///
/// Default constructor for the class. Sets the to (0, 0, 500, 375).
///
public MasterPane() : this( "", new RectangleF( 0, 0, 500, 375 ) )
{
}
///
/// Default constructor for the class. Specifies the of
/// the , and the size of the .
///
public MasterPane( string title, RectangleF paneRect ) : base( title, paneRect )
{
_innerPaneGap = Default.InnerPaneGap;
//_paneLayoutMgr = new PaneLayoutMgr();
_isUniformLegendEntries = Default.IsUniformLegendEntries ;
_isCommonScaleFactor = Default.IsCommonScaleFactor;
_paneList = new PaneList();
_legend.IsVisible = Default.IsShowLegend;
InitLayout();
}
private void InitLayout()
{
_paneLayout = Default.PaneLayout;
_countList = null;
_isColumnSpecified = false;
_prop = null;
}
///
/// The Copy Constructor - Make a deep-copy clone of this class instance.
///
/// The object from which to copy
public MasterPane( MasterPane rhs ) : base( rhs )
{
// copy all the value types
//_paneLayoutMgr = rhs._paneLayoutMgr.Clone();
_innerPaneGap = rhs._innerPaneGap;
_isUniformLegendEntries = rhs._isUniformLegendEntries;
_isCommonScaleFactor = rhs._isCommonScaleFactor;
// Then, fill in all the reference types with deep copies
_paneList = rhs._paneList.Clone();
_paneLayout = rhs._paneLayout;
_countList = rhs._countList;
_isColumnSpecified = rhs._isColumnSpecified;
_prop = rhs._prop;
}
///
/// Implement the interface in a typesafe manner by just
/// calling the typed version of to make a deep copy.
///
/// A deep copy of this object
object ICloneable.Clone()
{
return this.Clone();
}
///
/// Typesafe, deep-copy clone method.
///
/// A new, independent copy of this class
public MasterPane Clone()
{
return new MasterPane( this );
}
#endregion
#region Serialization
///
/// Current schema value that defines the version of the serialized file
///
// schema changed to 2 with addition of 'prop'
public const int schema2 = 10;
///
/// Constructor for deserializing objects
///
/// A instance that defines the serialized data
///
/// A instance that contains the serialized data
///
protected MasterPane( SerializationInfo info, StreamingContext context ) : base( info, context )
{
// The schema value is just a file version parameter. You can use it to make future versions
// backwards compatible as new member variables are added to classes
int sch = info.GetInt32( "schema2" );
_paneList = (PaneList) info.GetValue( "paneList", typeof(PaneList) );
//_paneLayoutMgr = (PaneLayoutMgr) info.GetValue( "paneLayoutMgr", typeof(PaneLayoutMgr) );
_innerPaneGap = info.GetSingle( "innerPaneGap" );
_isUniformLegendEntries = info.GetBoolean( "isUniformLegendEntries" );
_isCommonScaleFactor = info.GetBoolean( "isCommonScaleFactor" );
_paneLayout = (PaneLayout)info.GetValue( "paneLayout", typeof( PaneLayout ) );
_countList = (int[])info.GetValue( "countList", typeof( int[] ) );
_isColumnSpecified = info.GetBoolean( "isColumnSpecified" );
_prop = (float[])info.GetValue( "prop", typeof( float[] ) );
}
///
/// Populates a instance with the data needed to serialize the target object
///
/// A instance that defines the serialized data
/// A instance that contains the serialized data
[SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter=true)]
public override void GetObjectData( SerializationInfo info, StreamingContext context )
{
base.GetObjectData( info, context );
info.AddValue( "schema2", schema2 );
info.AddValue( "paneList", _paneList );
//info.AddValue( "paneLayoutMgr", _paneLayoutMgr );
info.AddValue( "innerPaneGap", _innerPaneGap );
info.AddValue( "isUniformLegendEntries", _isUniformLegendEntries );
info.AddValue( "isCommonScaleFactor", _isCommonScaleFactor );
info.AddValue( "paneLayout", _paneLayout );
info.AddValue( "countList", _countList );
info.AddValue( "isColumnSpecified", _isColumnSpecified );
info.AddValue( "prop", _prop );
}
///
/// Respond to the callback when the MasterPane objects are fully initialized.
///
///
public void OnDeserialization(object sender)
{
Bitmap bitmap = new Bitmap( 10, 10 );
Graphics g = Graphics.FromImage( bitmap );
ReSize( g, _rect );
}
#endregion
#region List Methods
///
/// Indexer to access the specified object from
/// by its ordinal position in the list.
///
/// The ordinal position (zero-based) of the
/// object to be accessed.
/// A object reference.
public GraphPane this[ int index ]
{
get { return( (GraphPane) _paneList[index] ); }
set { _paneList[index] = value; }
}
///
/// Indexer to access the specified object from
/// by its string.
///
/// The string title of the
/// object to be accessed.
/// A object reference.
public GraphPane this[ string title ]
{
get { return _paneList[title]; }
}
///
/// Add a object to the collection at the end of the list.
///
/// A reference to the object to
/// be added
///
public void Add( GraphPane pane )
{
_paneList.Add( pane );
}
///
/// Call for all objects in the
/// list.
///
///
/// This overload of AxisChange just uses the default Graphics instance for the screen.
/// If you have a Graphics instance available from your Windows Form, you should use
/// the overload instead.
///
public void AxisChange()
{
using ( Graphics g = Graphics.FromHwnd( IntPtr.Zero ) )
AxisChange( g );
}
///
/// Call for all objects in the
/// list.
///
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
public void AxisChange( Graphics g )
{
foreach ( GraphPane pane in _paneList )
pane.AxisChange( g );
}
///
/// Redo the layout using the current size of the ,
/// and also handle resizing the
/// contents by calling .
///
/// This method will use the pane layout that was specified by a call to
/// . If
/// has not previously been called,
/// it will default to .
///
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
///
///
///
///
public void ReSize( Graphics g )
{
ReSize( g, _rect );
}
///
/// Change the size of the , and also handle resizing the
/// contents by calling .
///
/// This method will use the pane layout that was specified by a call to
/// . If
/// has not previously been called,
/// it will default to .
///
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
///
///
///
///
///
public override void ReSize( Graphics g, RectangleF rect )
{
_rect = rect;
DoLayout( g );
CommonScaleFactor();
}
///
/// Method that forces the scale factor calculations
/// (via ),
/// to give a common scale factor for all objects in the
/// .
///
///
/// This will make it such that a given font size will result in the same output font
/// size for all 's. Note that this does not make the scale
/// factor for the 's the same as that of the
/// .
///
///
public void CommonScaleFactor()
{
if ( _isCommonScaleFactor )
{
// Find the maximum scaleFactor of all the GraphPanes
float maxFactor = 0;
foreach ( GraphPane pane in PaneList )
{
pane.BaseDimension = PaneBase.Default.BaseDimension;
float scaleFactor = pane.CalcScaleFactor();
maxFactor = scaleFactor > maxFactor ? scaleFactor : maxFactor;
}
// Now, calculate the base dimension
foreach ( GraphPane pane in PaneList )
{
float scaleFactor = pane.CalcScaleFactor();
pane.BaseDimension *= scaleFactor / maxFactor;
}
}
}
///
/// Render all the objects in the to the
/// specified graphics device.
///
/// This method should be part of the Paint() update process. Calling this routine
/// will redraw all
/// features of all the items. No preparation is required other than
/// instantiated objects that have been added to the list with the
/// method.
///
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
public override void Draw( Graphics g )
{
// Draw the pane border & background fill, the title, and the GraphObj objects that lie at
// ZOrder.GBehindAll
base.Draw( g );
if ( _rect.Width <= 1 || _rect.Height <= 1 )
return;
float scaleFactor = CalcScaleFactor();
// Clip everything to the rect
g.SetClip( _rect );
// For the MasterPane, All GraphItems go behind the GraphPanes, except those that
// are explicity declared as ZOrder.AInFront
_graphObjList.Draw( g, this, scaleFactor, ZOrder.G_BehindChartFill );
_graphObjList.Draw( g, this, scaleFactor, ZOrder.E_BehindCurves );
_graphObjList.Draw( g, this, scaleFactor, ZOrder.D_BehindAxis );
_graphObjList.Draw( g, this, scaleFactor, ZOrder.C_BehindChartBorder );
// Reset the clipping
g.ResetClip();
foreach ( GraphPane pane in _paneList )
pane.Draw( g );
// Clip everything to the rect
g.SetClip( _rect );
_graphObjList.Draw( g, this, scaleFactor, ZOrder.B_BehindLegend );
// Recalculate the legend rect, just in case it has not yet been done
// innerRect is the area for the GraphPane's
RectangleF innerRect = CalcClientRect( g, scaleFactor );
_legend.CalcRect( g, this, scaleFactor, ref innerRect );
_legend.Draw( g, this, scaleFactor );
_graphObjList.Draw( g, this, scaleFactor, ZOrder.A_InFront );
// Reset the clipping
g.ResetClip();
}
///
/// Find the pane and the object within that pane that lies closest to the specified
/// mouse (screen) point.
///
///
/// This method first finds the within the list that contains
/// the specified mouse point. It then calls the
/// method to determine which object, if any, was clicked. With the exception of the
/// , all the parameters in this method are identical to those
/// in the method.
/// If the mouse point lies within the of any
/// item, then that pane will be returned (otherwise it will be
/// null). Further, within the selected pane, if the mouse point is within the
/// bounding box of any of the items (or in the case
/// of and , within
/// pixels), then the object will be returned.
/// You must check the type of the object to determine what object was
/// selected (for example, "if ( object is Legend ) ..."). The
/// parameter returns the index number of the item
/// within the selected object (such as the point number within a
/// object.
///
/// The screen point, in pixel coordinates.
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
/// A reference to the object that was clicked.
/// A reference to the nearest object to the
/// specified screen point. This can be any of ,
/// , ,
/// , , or .
/// Note: If the pane title is selected, then the object
/// will be returned.
///
/// The index number of the item within the selected object
/// (where applicable). For example, for a object,
/// will be the index number of the nearest data point,
/// accessible via CurveItem.Points[index].
/// index will be -1 if no data points are available.
/// true if a was found, false otherwise.
///
public bool FindNearestPaneObject( PointF mousePt, Graphics g, out GraphPane pane,
out object nearestObj, out int index )
{
pane = null;
nearestObj = null;
index = -1;
GraphObj saveGraphItem = null;
int saveIndex = -1;
float scaleFactor = CalcScaleFactor();
// See if the point is in a GraphObj
// If so, just save the object and index so we can see if other overlying objects were
// intersected as well.
if ( this.GraphObjList.FindPoint( mousePt, this, g, scaleFactor, out index ) )
{
saveGraphItem = this.GraphObjList[index];
saveIndex = index;
// If it's an "In-Front" item, then just return it
if ( saveGraphItem.ZOrder == ZOrder.A_InFront )
{
nearestObj = saveGraphItem;
index = saveIndex;
return true;
}
}
foreach ( GraphPane tPane in _paneList )
{
if ( tPane.Rect.Contains( mousePt ) )
{
pane = tPane;
return tPane.FindNearestObject( mousePt, g, out nearestObj, out index );
}
}
// If no items were found in the GraphPanes, then return the item found on the MasterPane (if any)
if ( saveGraphItem != null )
{
nearestObj = saveGraphItem;
index = saveIndex;
return true;
}
return false;
}
///
/// Find the within the that contains the
/// within its .
///
/// The mouse point location where you want to search
/// A object that contains the mouse point, or
/// null if no was found.
public GraphPane FindPane( PointF mousePt )
{
foreach ( GraphPane pane in _paneList )
{
if ( pane.Rect.Contains( mousePt ) )
return pane;
}
return null;
}
///
/// Find the within the that contains the
/// within its .
///
/// The mouse point location where you want to search
/// A object that contains the mouse point, or
/// null if no was found.
public GraphPane FindChartRect( PointF mousePt )
{
foreach ( GraphPane pane in _paneList )
{
if ( pane.Chart._rect.Contains( mousePt ) )
return pane;
}
return null;
}
#endregion
#region Layout Methods
/// The SetLayout() methods setup the desired layout of the
/// objects within a . These functions
/// do not make any changes, they merely set the parameters so that future calls
/// to or
/// will use the desired layout.
/// The layout options include a set of "canned" layouts provided by the
/// enumeration, options to just set a specific
/// number of rows and columns of panes (and all pane sizes are the same), and more
/// customized options of specifying the number or rows in each column or the number of
/// columns in each row, along with proportional values that determine the size of each
/// individual column or row.
///
///
/// Automatically set all of the 's in
/// the list to a pre-defined layout configuration from a
/// enumeration.
///
/// This method uses a enumeration to describe the type of layout
/// to be used. Overloads are available that provide other layout options
/// A enumeration that describes how
/// the panes should be laid out within the .
///
/// A graphic device object to be drawn into. This is normally created with a call to
/// the CreateGraphics() method of the Control or Form.
///
///
///
///
public void SetLayout( Graphics g, PaneLayout paneLayout )
{
InitLayout();
_paneLayout = paneLayout;
DoLayout( g );
}
///
/// Automatically set all of the 's in
/// the list to a reasonable configuration.
///
/// This method explicitly specifies the number of rows and columns to use
/// in the layout, and all objects will have the same size.
/// Overloads are available that provide other layout options
///
/// A graphic device object to be drawn into. This is normally created with a call to
/// the CreateGraphics() method of the Control or Form.
///
/// The number of rows of objects
/// to include in the layout
/// The number of columns of objects
/// to include in the layout
///
///
///
public void SetLayout( Graphics g, int rows, int columns )
{
InitLayout();
if ( rows < 1 )
rows = 1;
if ( columns < 1 )
columns = 1;
int[] countList = new int[rows];
for ( int i = 0; i < rows; i++ )
countList[i] = columns;
SetLayout( g, true, countList, null );
}
///
/// Automatically set all of the 's in
/// the list to the specified configuration.
///
/// This method specifies the number of rows in each column, or the number of
/// columns in each row, allowing for irregular layouts. Overloads are available that
/// provide other layout options.
///
///
/// A graphic device object to be drawn into. This is normally created with a call to
/// the CreateGraphics() method of the Control or Form.
///
/// Specifies whether the number of columns in each row, or
/// the number of rows in each column will be specified. A value of true indicates the
/// number of columns in each row are specified in .
/// An integer array specifying either the number of columns in
/// each row or the number of rows in each column, depending on the value of
/// .
///
///
///
public void SetLayout( Graphics g, bool isColumnSpecified, int[] countList )
{
SetLayout( g, isColumnSpecified, countList, null );
}
///
/// Automatically set all of the 's in
/// the list to the specified configuration.
///
/// This method specifies the number of panes in each row or column, allowing for
/// irregular layouts.
/// This method specifies the number of rows in each column, or the number of
/// columns in each row, allowing for irregular layouts. Additionally, a
/// parameter is provided that allows varying column or
/// row sizes. Overloads for SetLayout() are available that provide other layout options.
///
///
/// A graphic device object to be drawn into. This is normally created with a call to
/// the CreateGraphics() method of the Control or Form.
///
/// Specifies whether the number of columns in each row, or
/// the number of rows in each column will be specified. A value of true indicates the
/// number of columns in each row are specified in .
/// An integer array specifying either the number of columns in
/// each row or the number of rows in each column, depending on the value of
/// .
/// An array of float values specifying proportional sizes for each
/// row or column. Note that these proportions apply to the non-specified dimension -- that is,
/// if is true, then these proportions apply to the row
/// heights, and if is false, then these proportions apply
/// to the column widths. The values in this array are arbitrary floats -- the dimension of
/// any given row or column is that particular proportional value divided by the sum of all
/// the values. For example, let be true, and
/// is an array with values of { 1.0, 2.0, 3.0 }. The sum of
/// those values is 6.0. Therefore, the first row is 1/6th of the available height, the
/// second row is 2/6th's of the available height, and the third row is 3/6th's of the
/// available height.
///
///
///
///
public void SetLayout( Graphics g, bool isColumnSpecified, int[] countList, float[] proportion )
{
InitLayout();
// use defaults if the parameters are invalid
if ( countList != null && countList.Length > 0 )
{
_prop = new float[countList.Length];
// Sum up the total proportional factors
float sumProp = 0.0f;
for ( int i = 0; i < countList.Length; i++ )
{
_prop[i] = ( proportion == null || proportion.Length <= i || proportion[i] < 1e-10 ) ?
1.0f : proportion[i];
sumProp += _prop[i];
}
// Make prop sum to 1.0
for ( int i = 0; i < countList.Length; i++ )
_prop[i] /= sumProp;
_isColumnSpecified = isColumnSpecified;
_countList = countList;
DoLayout( g );
}
}
///
/// Modify the sizes of each
/// such that they fit within the
/// in a pre-configured layout.
///
/// The method (and overloads) is
/// used for setting the layout configuration.
///
///
///
///
public void DoLayout( Graphics g )
{
if ( _countList != null )
DoLayout( g, _isColumnSpecified, _countList, _prop );
else
{
int count = _paneList.Count;
if ( count == 0 )
return;
int rows,
cols,
root = (int)( Math.Sqrt( (double)count ) + 0.9999999 );
//float[] widthList = new float[5];
switch ( _paneLayout )
{
case PaneLayout.ForceSquare:
rows = root;
cols = root;
DoLayout( g, rows, cols );
break;
case PaneLayout.SingleColumn:
rows = count;
cols = 1;
DoLayout( g, rows, cols );
break;
case PaneLayout.SingleRow:
rows = 1;
cols = count;
DoLayout( g, rows, cols );
break;
default:
case PaneLayout.SquareColPreferred:
rows = root;
cols = root;
if ( count <= root * ( root - 1 ) )
rows--;
DoLayout( g, rows, cols );
break;
case PaneLayout.SquareRowPreferred:
rows = root;
cols = root;
if ( count <= root * ( root - 1 ) )
cols--;
DoLayout( g, rows, cols );
break;
case PaneLayout.ExplicitCol12:
DoLayout( g, true, new int[2] { 1, 2 }, null );
break;
case PaneLayout.ExplicitCol21:
DoLayout( g, true, new int[2] { 2, 1 }, null );
break;
case PaneLayout.ExplicitCol23:
DoLayout( g, true, new int[2] { 2, 3 }, null );
break;
case PaneLayout.ExplicitCol32:
DoLayout( g, true, new int[2] { 3, 2 }, null );
break;
case PaneLayout.ExplicitRow12:
DoLayout( g, false, new int[2] { 1, 2 }, null );
break;
case PaneLayout.ExplicitRow21:
DoLayout( g, false, new int[2] { 2, 1 }, null );
break;
case PaneLayout.ExplicitRow23:
DoLayout( g, false, new int[2] { 2, 3 }, null );
break;
case PaneLayout.ExplicitRow32:
DoLayout( g, false, new int[2] { 3, 2 }, null );
break;
}
}
}
///
/// Internal method that applies a previously set layout with a specific
/// row and column count. This method is only called by
/// .
///
internal void DoLayout( Graphics g, int rows, int columns )
{
if ( rows < 1 )
rows = 1;
if ( columns < 1 )
columns = 1;
int[] countList = new int[rows];
for ( int i = 0; i < rows; i++ )
countList[i] = columns;
DoLayout( g, true, countList, null );
}
///
/// Internal method that applies a previously set layout with a rows per column or
/// columns per row configuration. This method is only called by
/// .
///
internal void DoLayout( Graphics g, bool isColumnSpecified, int[] countList,
float[] proportion )
{
// calculate scaleFactor on "normal" pane size (BaseDimension)
float scaleFactor = CalcScaleFactor();
// innerRect is the area for the GraphPane's
RectangleF innerRect = CalcClientRect( g, scaleFactor );
_legend.CalcRect( g, this, scaleFactor, ref innerRect );
// scaled InnerGap is the area between the GraphPane.Rect's
float scaledInnerGap = (float)( _innerPaneGap * scaleFactor );
int iPane = 0;
if ( isColumnSpecified )
{
int rows = countList.Length;
float y = 0.0f;
for ( int rowNum = 0; rowNum < rows; rowNum++ )
{
float propFactor = _prop == null ? 1.0f / rows : _prop[rowNum];
float height = ( innerRect.Height - (float)( rows - 1 ) * scaledInnerGap ) *
propFactor;
int columns = countList[rowNum];
if ( columns <= 0 )
columns = 1;
float width = ( innerRect.Width - (float)( columns - 1 ) * scaledInnerGap ) /
(float)columns;
for ( int colNum = 0; colNum < columns; colNum++ )
{
if ( iPane >= _paneList.Count )
return;
this[iPane].Rect = new RectangleF(
innerRect.X + colNum * ( width + scaledInnerGap ),
innerRect.Y + y,
width,
height );
iPane++;
}
y += height + scaledInnerGap;
}
}
else
{
int columns = countList.Length;
float x = 0.0f;
for ( int colNum = 0; colNum < columns; colNum++ )
{
float propFactor = _prop == null ? 1.0f / columns : _prop[colNum];
float width = ( innerRect.Width - (float)( columns - 1 ) * scaledInnerGap ) *
propFactor;
int rows = countList[colNum];
if ( rows <= 0 )
rows = 1;
float height = ( innerRect.Height - (float)( rows - 1 ) * scaledInnerGap ) / (float)rows;
for ( int rowNum = 0; rowNum < rows; rowNum++ )
{
if ( iPane >= _paneList.Count )
return;
this[iPane].Rect = new RectangleF(
innerRect.X + x,
innerRect.Y + rowNum * ( height + scaledInnerGap ),
width,
height );
iPane++;
}
x += width + scaledInnerGap;
}
}
}
/*
///
/// Automatically set all of the 's in
/// the list to a reasonable configuration.
///
/// This method explicitly specifies the number of rows and columns to use in the layout.
/// A more automatic overload, using a enumeration, is available.
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
/// The number of rows of objects
/// to include in the layout
/// The number of columns of objects
/// to include in the layout
public void DoPaneLayout( Graphics g, int rows, int columns )
{
// save the layout settings for future reference
_countList = null;
_rows = rows;
_columns = columns;
// calculate scaleFactor on "normal" pane size (BaseDimension)
float scaleFactor = this.CalcScaleFactor();
// innerRect is the area for the GraphPane's
RectangleF innerRect = CalcClientRect( g, scaleFactor );
_legend.CalcRect( g, this, scaleFactor, ref innerRect );
// scaled InnerGap is the area between the GraphPane.Rect's
float scaledInnerGap = (float)( _innerPaneGap * scaleFactor );
float width = ( innerRect.Width - (float)( columns - 1 ) * scaledInnerGap ) / (float)columns;
float height = ( innerRect.Height - (float)( rows - 1 ) * scaledInnerGap ) / (float)rows;
int i = 0;
foreach ( GraphPane pane in _paneList )
{
float rowNum = (float)( i / columns );
float colNum = (float)( i % columns );
pane.Rect = new RectangleF(
innerRect.X + colNum * ( width + scaledInnerGap ),
innerRect.Y + rowNum * ( height + scaledInnerGap ),
width,
height );
i++;
}
}
*/
#endregion
}
}