Click here to Skip to main content
15,891,943 members
Articles / Programming Languages / C#

AI: Dawkins Biomorphs / And Other Evolving Creatures

Rate me:
Please Sign up or sign in to vote.
4.80/5 (35 votes)
29 Jan 2007CPOL4 min read 167.9K   965   56  
An implementation of Dawkins Biomorphs and some more crazy evolving creatures.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace UserControls
{
    #region CollapsePanel CLASS
    /// <summary>
    /// Provides an XP type Collapsible panel, that can be one of 2 states, collapsed or
    /// expanded. 
    /// </summary>
    public partial class CollapsePanel : Panel
    {
        #region Instance Fields
        //instance fields
        private Color titleBarTextColor = Color.Black;
        private Color panelBorderColor = Color.Gray;
        private Color titleBarStartColor = Color.SteelBlue;
        private Color titleBarEndColor = Color.White;
        private String titleText="Title1";
        private Font titleBarFont = new Font(FontFamily.GenericSerif, 10.0f);
        private System.Windows.Forms.ImageList imageList;
        private int panelMinSize = 20;
        private int oPanelHeight;
        private int imageIndex = 0;
        private const int imageBorder = 2;
        private const int expandBorder = 4;
        private int squareSize = 7;
        private int squareBorder = 2;
        private CollapsePanelCurrentState state = CollapsePanelCurrentState.Expanded;
        /// <summary>
        /// A CollapsePanelCurrentState changed event.
        /// </summary>
        [Category("State"),
        Description("Raised when Panel state has changed.")]
        public event CollapsePanelCurrentStateChangedEventHandler CollapsePanelCurrentStateChanged;
        #endregion
        #region Constructor
        /// <summary>
        /// Constructs a new CollapsePanel panel object
        /// </summary>
        public CollapsePanel()
        {
            InitializeComponent();
            this.Paint += new PaintEventHandler(CollapsePanel_Paint);
            this.MouseUp += new MouseEventHandler(CollapsePanel_MouseUp);
            this.MouseMove += new MouseEventHandler(CollapsePanel_MouseMove);
            this.Resize += new EventHandler(CollapsePanel_Resize);
            this.Invalidate();
        }
        #endregion
        #region Private Methods
        /// <summary>
        /// The resize event, that is fired when the CollapsePanel is resized
        /// </summary>
        /// <param name="sender">The CollapsePanel</param>
        /// <param name="e">The event args</param>
        private void CollapsePanel_Resize(object sender, EventArgs e)
        {
            this.Invalidate();
        }

        /// <summary>
        /// The MouseMove event, that is fired when the CollapsePanel is mouse is moved
        /// this is used to show different cursors dependant on mouse co-ordinates
        /// </summary>
        /// <param name="sender">The CollapsePanel</param>
        /// <param name="e">The event args</param>
        private void CollapsePanel_MouseMove(object sender, MouseEventArgs e)
        {
            //Change the cursor type dependant on the area that the user is hovering over with
            //the mouse
            if ((e.Button == MouseButtons.None) && (IsOverTitle(e.X, e.Y)))
            {
                this.Cursor = Cursors.Hand;
            }
            else
            {
               this.Cursor = Cursors.Default;
            }
        }

        /// <summary>
        /// The MouseUp event, that is fired when the CollapsePanel is mouse button is 
        /// released. This will either collapse the panel to expand it, depending on
        /// its current state
        /// this is used to show different cursors dependant on mouse co-ordinates
        /// </summary>
        /// <param name="sender">The CollapsePanel</param>
        /// <param name="e">The event args</param>
        private void CollapsePanel_MouseUp(object sender, MouseEventArgs e)
        {
            //was the click in the correct area to change the panel state
            if ((e.Button == MouseButtons.Left) && (IsOverTitle(e.X, e.Y)))
            {
                if ((this.imageList != null) && (this.imageList.Images.Count >= 2))
                {
                    if (this.imageIndex == 0)
                    {
                        // Currently expanded, so store the current height.
                        this.state = CollapsePanelCurrentState.Collapsed;
                    }
                    else
                    {
                        // Currently collapsed, so expand the oPanel.
                        this.state = CollapsePanelCurrentState.Expanded;
                    }
                    UpdateDisplayedState();
                }
            }
        }

        /// <summary>
        /// The Paint event, that is fired when the CollapsePanel is painted. This 
        /// event paints the CollapsePanel using custom GDI+ painting methods
        /// </summary>
        /// <param name="sender">The CollapsePanel</param>
        /// <param name="e">The event args</param>
        private void CollapsePanel_Paint(object sender, PaintEventArgs e)
        {
            //draw the title area with correct colors
            Graphics g = e.Graphics;
            //draw the title panel area 
            g.SmoothingMode = SmoothingMode.AntiAlias;
            Rectangle recTitleBar = new Rectangle(0, 0, Width, panelMinSize);
            LinearGradientBrush lbTitleBarColor = new LinearGradientBrush(
            recTitleBar, titleBarStartColor, titleBarEndColor, LinearGradientMode.Horizontal);
            g.FillRectangle(lbTitleBarColor, recTitleBar);
            //draw 4 squares in border color
            SolidBrush sbSquares = new SolidBrush(Color.White);
            Rectangle recSquarePos = new Rectangle(Width - (squareSize + (squareBorder*2)), squareBorder, squareSize, squareSize);
            g.FillRectangle(sbSquares, recSquarePos);
            
            recSquarePos = new Rectangle(Width - (squareSize + (squareBorder * 2)), (squareBorder * 2) + squareSize, squareSize, squareSize);
            g.FillRectangle(sbSquares, recSquarePos);

            recSquarePos = new Rectangle(Width - (2*(squareSize + (squareBorder * 2))), squareBorder, squareSize, squareSize);
            g.FillRectangle(sbSquares, recSquarePos);

            recSquarePos = new Rectangle(Width - (2*(squareSize + (squareBorder * 2))), (squareBorder * 2) + squareSize, squareSize, squareSize);
            g.FillRectangle(sbSquares, recSquarePos);

            recSquarePos = new Rectangle(Width - (3*(squareSize + (squareBorder * 2))), squareBorder, squareSize, squareSize);
            Pen pSquare = new Pen(sbSquares);
            g.DrawRectangle(pSquare, recSquarePos);
            // Draw the expand/collapse image
            Image iState= ImageList.Images[(int)this.state];
            g.DrawImage(iState, new Point(2,2));
            //Draw the title text
            Brush bTitleBarTextColor = new SolidBrush(TitleBarTextColor);
            int xPos= iState.Width + (imageBorder*4);
            int yPos=panelMinSize/2 - titleBarFont.Height/2;
            g.DrawString(titleText, titleBarFont, bTitleBarTextColor, xPos, yPos);
            //draw the title area border
            Brush bPanelBorderColor = new SolidBrush(PanelBorderColor);
            Pen pPanelBorderColor = new Pen(bPanelBorderColor);
            Rectangle recTitleBarBorder = new Rectangle(0, 0, Width - 1, panelMinSize - 1);
            g.DrawRectangle(pPanelBorderColor, recTitleBarBorder);
            //draw the main panel area border
            Rectangle recMainAreaBorder = new Rectangle(0, 0, Width - 1, Height - 1);
            g.DrawRectangle(pPanelBorderColor, recMainAreaBorder);
        }

        /// <summary>
        /// returns true if the mouse is over the title area
        /// </summary>
        /// <param name="xPos">The current mouse XPos</param>
        /// <param name="yPos">The current mouse YPos</param>
        /// <returns>true if the mouse is over the title area</returns>
        private bool IsOverTitle(int xPos, int yPos)
        {
            // Get the dimensions of the title label
            Rectangle rectTest = new Rectangle(0, 0, Width, panelMinSize);
            // Check if the supplied coordinates are over the title label
            if (rectTest.Contains(xPos, yPos))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// Updates the state of the CollapsePanel
        /// </summary>
        private void UpdateDisplayedState()
        {
            switch (this.state)
            {
                case CollapsePanelCurrentState.Collapsed:
                    // Entering collapsed state, so store the current height.
                    this.oPanelHeight = this.Height;
                    // Collapse the oPanel
                    this.Height = panelMinSize;
                    // Update the image.
                    this.imageIndex = 1;
                    break;
                case CollapsePanelCurrentState.Expanded:
                    // Entering expanded state, so expand the oPanel.
                    this.Height = this.oPanelHeight;
                    // Update the image.
                    this.imageIndex = 0;
                    break;
                default:
                    // Ignore
                    break;
            }
            this.Invalidate();

            OnCollapsePanelCurrentStateChanged(new PanelEventArgs(this));
        }
        #endregion
        #region Protected Methods
        /// <summary>
        /// Raises the OnCollapsePanelCurrentStateChanged event for the <see cref="UserControls.CollapsePanel.CollapsePanelCurrentStateChanged">CollapsePanelCurrentStateChanged</see>. 
        /// Any users of the <see cref="UserControls.CollapsePanel.CollapsePanelCurrentStateChanged">CollapsePanelCurrentStateChanged</see> may now subscribe to this event 
        /// using a CollapsePanelCurrentStateChangedEventHandler delegate.
        /// </summary>
        /// <param name="e">The <see cref="UserControls.PanelEventArgs">PanelEventArgs</see>that contains the event data</param>
        protected virtual void OnCollapsePanelCurrentStateChanged(PanelEventArgs e)
        {
            if (CollapsePanelCurrentStateChanged != null)
            {
                // Invokes the delegates. 
                CollapsePanelCurrentStateChanged(this, e);
            }
        }
        #endregion
        #region Public Methods / Events / Properties
        /// <summary>
        /// Gets/sets the font used for the title bar text.
        /// </summary>
        [Category("Title"),
        Description("The font used to display the title text.")]
        public Font TitleFont
        {
            get
            {
                return this.titleBarFont;
            }
            set
            {
                this.titleBarFont = value;
                this.Invalidate();
            }
        }

        /// <summary>
        /// Gets/sets the image list used for the expand/collapse image.
        /// </summary>
        [Category("Title"),
        Description("The image list to get the images displayed for expanding/collapsing the CollapsePanel.")]
        public ImageList ImageList
        {
            get
            {
                return this.imageList;
            }
            set
            {
                this.imageList = value;
                //is the imageList valid
                if (this.imageList != null)
                {
                    //are there images within it
                    if (this.imageList.Images.Count > 0)
                    {
                        this.imageIndex = 0;
                    }
                }
                else
                {
                    this.imageIndex = -1;
                }
                this.Invalidate();
            }
        }

        /// <summary>
        /// Gets/sets the font used for the title bar text.
        /// </summary>
        [Category("Title"),
        Description("The color used to display the title text.")]
        public Color TitleBarTextColor
        {
            get { return this.titleBarTextColor; }
            set 
            { 
                this.titleBarTextColor = value;
                this.Invalidate();
            }
        }

        /// <summary>
        /// Gets/sets the font used for the title bar text.
        /// </summary>
        [Category("Title"),
        Description("The title text.")]
        public String TitleText
        {
            get { return this.titleText; }
            set 
            { 
                this.titleText = value;
                this.Invalidate();
            }
        }

        /// <summary>
        /// Gets/sets the font used for the title bar text.
        /// </summary>
        [Category("Title"),
        Description("The border color used to display the title area border.")]
        public Color PanelBorderColor
        {
            get { return this.panelBorderColor; }
            set
            {
                this.panelBorderColor = value;
                this.Invalidate();
            }
        }

        /// <summary>
        /// Gets/sets the start color used for the title bar area 
        /// </summary>
        [Category("Title"),
        Description("The start color used to display the title area background.")]
        public Color TitleBarStartColor
        {
            get { return titleBarStartColor; }
            set 
            {
                this.Invalidate();
                this.titleBarStartColor = value; 
            }
        }

        /// <summary>
        /// Gets/sets the <see cref="UserControls.CollapsePanelCurrentState">CollapsePanelCurrentState</see>, which
        /// can either be Expanded/Collapsed
        /// </summary>
        [Browsable(false)]
        public CollapsePanelCurrentState CollapsePanelCurrentState
        {
            get
            {
                return this.state;
            }
            set
            {
                CollapsePanelCurrentState oldState = this.state;
                this.state = value;
                if (oldState != this.state)
                {
                    // State has changed to update the display
                    UpdateDisplayedState();
                }
            }
        }

        /// <summary>
        /// Gets/sets the end color used for the title bar area 
        /// </summary>
        [Category("Title"),
        Description("The end color used to display the title area background.")]
        public Color TitleBarEndColor
        {
            get { return titleBarEndColor; }
            set 
            {
                this.Invalidate();
                this.titleBarEndColor = value; 
            }
        }
        #endregion
    }
    #endregion
    #region Public Enumeration
    /// <summary>
    /// Defines the state of a <see cref="UserControls.CollapsePanel">CollapsePanel</see>.
    /// </summary>
    public enum CollapsePanelCurrentState
    {
        /// <summary>
        /// The <see cref="UserControls.CollapsePanel">CollapsePanel</see> is expanded.
        /// </summary>
        Expanded,
        /// <summary>
        /// The <see cref="UserControls.CollapsePanel">CollapsePanel</see> is collapsed.
        /// </summary>
        Collapsed
    }
    #endregion
    #region Delegates
    /// <summary>
    /// A delegate type for hooking up a <see cref="UserControls.CollapsePanel">CollapsePanel</see> state
    /// change notifications.
    /// </summary>
    public delegate void CollapsePanelCurrentStateChangedEventHandler(object sender, PanelEventArgs e);
    #endregion
    #region PanelEventArgs CLASS
    /// <summary>
    /// Provides PanelEventArgs for the <see cref="UserControls.CollapsePanel.CollapsePanelCurrentStateChanged">CollapsePanelCurrentStateChanged</see> event.
    /// This event is then used by the <see cref="UserControls.CollapsePanelBar">CollapsePanelBar</see> to determine the new layout
    /// positions for all of the <see cref="UserControls.CollapsePanel">CollapsePanel</see> contained.
    /// </summary>
    public class PanelEventArgs : System.EventArgs
    {
        #region Instance Fields
        //Instance Fields
        private CollapsePanel oPanel;
        #endregion
        #region Public Constructor
        /// <summary>
        /// Simply creates a new PanelEventArgs object using the paremeter provided
        /// </summary>
        /// <param name="sender">The originating <see cref="UserControls.CollapsePanel">CollapsePanel</see>.</param>
        public PanelEventArgs(CollapsePanel sender)
        {
            this.oPanel = sender;
        }
        #endregion
        #region Public Properties
        /// <summary>
        /// Gets the <see cref="UserControls.CollapsePanel">CollapsePanel</see> that triggered the event.
        /// </summary>
        public CollapsePanel CollapsePanel
        {
            get
            {
                return this.oPanel;
            }
        }

        /// <summary>
        /// Gets the CollapsePanelCurrentState of the <see cref="UserControls.CollapsePanel">CollapsePanel</see> that triggered the event.
        /// </summary>
        public CollapsePanelCurrentState CollapsePanelCurrentState
        {
            get
            {
                return this.oPanel.CollapsePanelCurrentState;
            }
        }
        #endregion
    }
    #endregion
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence

Both of these at Sussex University UK.

Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2016
  • Codeproject MVP 2016
  • Microsoft C# MVP 2015
  • Codeproject MVP 2015
  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Comments and Discussions