//============================================================================ //ZedGraph Class Library - A Flexible Line Graph/Bar Graph Library in C# //Copyright (C) 2006 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.Drawing; using System.Text; using System.Runtime.Serialization; using System.Security.Permissions; namespace DrawGraph { /// /// internal class to store pane layout details for the /// /// /// John Champion /// $Revision: 3.1 $ $Date: 2006/06/24 20:26:44 $ [Serializable] public class PaneLayoutMgr : ICloneable, ISerializable { // =========== PANE LAYOUT STUFF ================ #region Fields /// /// 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; #endregion #region Constructors internal void Init() { _paneLayout = MasterPane.Default.PaneLayout; _countList = null; _isColumnSpecified = false; _prop = null; } internal PaneLayoutMgr() { Init(); } internal PaneLayoutMgr( PaneLayoutMgr rhs ) { _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 /// /// 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 PaneLayoutMgr Clone() { return new PaneLayoutMgr( this ); } #endregion #region Serialization /// /// Current schema value that defines the version of the serialized file /// internal const int schema = 10; /// /// Constructor for deserializing objects /// /// A instance that defines the serialized data /// /// A instance that contains the serialized data /// public PaneLayoutMgr( SerializationInfo info, StreamingContext 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( "schema" ); _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 virtual void GetObjectData( SerializationInfo info, StreamingContext context ) { info.AddValue( "schema", schema ); info.AddValue( "paneLayout", _paneLayout ); info.AddValue( "countList", _countList ); info.AddValue( "isColumnSpecified", _isColumnSpecified ); info.AddValue( "prop", _prop ); } #endregion #region 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 . /// /// /// public void SetLayout( PaneLayout paneLayout ) { Init(); _paneLayout = paneLayout; } /// /// 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 /// 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( int rows, int columns ) { Init(); if ( rows < 1 ) rows = 1; if ( columns < 1 ) columns = 1; int[] countList = new int[rows]; for (int i=0; i /// 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. /// /// 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( bool isColumnSpecified, int[] countList ) { SetLayout( 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. /// /// 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( bool isColumnSpecified, int[] countList, float[] proportion ) { Init(); // use defaults if the parameters are invalid if ( countList != null && countList.Length > 0 ) { this._prop = new float[countList.Length]; // Sum up the total proportional factors float sumProp = 0.0f; for ( int i = 0; i < countList.Length; i++ ) { this._prop[i] = ( proportion == null || proportion.Length <= i || proportion[i] < 1e-10 ) ? 1.0f : proportion[i]; sumProp += this._prop[i]; } // Make prop sum to 1.0 for ( int i=0; i /// 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. /// A instance to be used for font sizing, /// etc. in determining the layout configuration. /// The instance which is to /// be resized. /// /// /// /// public void DoLayout( Graphics g, MasterPane master ) { if ( this._countList != null ) DoLayout( g, master, this._isColumnSpecified, this._countList, this._prop ); else { int count = master.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, master, rows, cols ); break; case PaneLayout.SingleColumn: rows = count; cols = 1; DoLayout( g, master, rows, cols ); break; case PaneLayout.SingleRow: rows = 1; cols = count; DoLayout( g, master, rows, cols ); break; default: case PaneLayout.SquareColPreferred: rows = root; cols = root; if ( count <= root * ( root - 1 ) ) rows--; DoLayout( g, master, rows, cols ); break; case PaneLayout.SquareRowPreferred: rows = root; cols = root; if ( count <= root * ( root - 1 ) ) cols--; DoLayout( g, master, rows, cols ); break; case PaneLayout.ExplicitCol12: DoLayout( g, master, true, new int[2] { 1, 2 }, null ); break; case PaneLayout.ExplicitCol21: DoLayout( g, master, true, new int[2] { 2, 1 }, null ); break; case PaneLayout.ExplicitCol23: DoLayout( g, master, true, new int[2] { 2, 3 }, null ); break; case PaneLayout.ExplicitCol32: DoLayout( g, master, true, new int[2] { 3, 2 }, null ); break; case PaneLayout.ExplicitRow12: DoLayout( g, master, false, new int[2] { 1, 2 }, null ); break; case PaneLayout.ExplicitRow21: DoLayout( g, master, false, new int[2] { 2, 1 }, null ); break; case PaneLayout.ExplicitRow23: DoLayout( g, master, false, new int[2] { 2, 3 }, null ); break; case PaneLayout.ExplicitRow32: DoLayout( g, master, 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, MasterPane master, int rows, int columns ) { if ( rows < 1 ) rows = 1; if ( columns < 1 ) columns = 1; int[] countList = new int[rows]; for (int i=0; i /// 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, MasterPane master, bool isColumnSpecified, int[] countList, float[] proportion ) { // calculate scaleFactor on "normal" pane size (BaseDimension) float scaleFactor = master.CalcScaleFactor(); // innerRect is the area for the GraphPane's RectangleF innerRect = master.CalcClientRect( g, scaleFactor ); master.Legend.CalcRect( g, master, scaleFactor, ref innerRect ); // scaled InnerGap is the area between the GraphPane.Rect's float scaledInnerGap = (float)( master._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; if ( iPane >= master._paneList.Count ) return; for ( int colNum = 0; colNum < columns; colNum++ ) { master[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 >= master._paneList.Count ) return; master[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 this._countList = null; this._rows = rows; this._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 ); this._legend.CalcRect( g, this, scaleFactor, ref innerRect ); // scaled InnerGap is the area between the GraphPane.Rect's float scaledInnerGap = (float)( this._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 this._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 } }