Click here to Skip to main content
15,892,480 members
Articles / Programming Languages / C#

An XML- and State Machine-based Design of a WinForms Control

Rate me:
Please Sign up or sign in to vote.
4.98/5 (35 votes)
1 Dec 20024 min read 86.2K   1.3K   49  
Usage of state machine and comprehensive XML description of control helps its user to considerably simplify control handling code.
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Reflection;
using OGCLib;

//
// General Information about an assembly is controlled through the following 
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
//
[assembly: AssemblyTitle("OGCVisualElementLib")]
[assembly: AssemblyDescription("This assembly contains classes for visual element.")]
[assembly: AssemblyCompany("Igor Ladnik")]
[assembly: AssemblyProduct("Open Group Control")]

[assembly: AssemblyVersion("1.2.*")]

namespace OGCVisualElementLib
{
	///////////////////////////////////////////////////////////////////////////////////
	// Class State 
	///////////////////////////////////////////////////////////////////////////////////
	public class State
	{
		// Variables
		private string      name;             // state name, defined in XML config. file
		private int         id;			      // Serial number in the element's alState collection.
		                                      // Order is defined in XML config. file.
		private Color       transpColor;      // color made transparent
		private Bitmap      initPicture;	  // original bitmap (without transparent background)
		private Bitmap      picture;		  // bitmap with transparent background		
		private OGControl	ogControl = null; // reference to the parent control object

		// CONSTRUCTOR
		protected internal State(OGControl ogControl, string name, int id)
		{
			this.ogControl = ogControl;
			this.name = name;
			this.id = id;
		}

		// PROPERTIES
		public string Name
		{
			get { return name; }
		}

		internal protected int Id
		{		
			get { return id;  }
			set { id = value; }
		}

		// Get/Set parent control
		internal protected OGControl OGCtrl
		{
			get { return ogControl;  }
			set { ogControl = value; }
		}

		internal protected Bitmap Picture
		{
			get	{ return picture;  }
			set	{ picture = value; }
		}

		internal protected Bitmap InitPicture
		{
			get	{ return initPicture;  }
			set	{ initPicture = value; }
		}

		internal protected Color TranspColor
		{
			get	{ return transpColor;  }
			set	{ transpColor = value; }
		}

		// METHODS

		// Modify pictures orientation according to orientation of the control
		public virtual void UpdateGeometry()
		{
			RotateFlipType rotateFlipType = GetRotateFlipType();
			picture.RotateFlip(rotateFlipType);
			initPicture.RotateFlip(rotateFlipType);
		}	

		public bool HitTest(MouseEventArgs mea, Point position)
		{
			bool br = false;
			Point hitPoint = new Point(mea.X-position.X, mea.Y-position.Y);
			Rectangle imageRect = new Rectangle(0, 0, picture.Size.Width, picture.Size.Height);

			if (imageRect.Contains(hitPoint))
				br = (initPicture.GetPixel(hitPoint.X, hitPoint.Y) != transpColor);
			
			return br;
		}

		internal protected void CreatePictures(string fullPicureName)
		{
			if (null != picture)
			{
				picture.Dispose();
				picture = null;
			}

			try
			{
				picture = new Bitmap(fullPicureName);
			}
			catch
			{
				picture = null;

				ErrorType errorType = ErrorType.Picture;
				string errorMessage = string.Format(
					ogControl.GetErrorMessage((int)errorType), name);
				ogControl.OnError(new ErrorEventArgs(ErrorSeverity.Error, errorMessage));
			}

			if (null != picture)
			{
				initPicture = new Bitmap(picture);
				transpColor = picture.GetPixel(0, 0);
				picture.MakeTransparent(transpColor);
			}
		}

		protected RotateFlipType GetRotateFlipType()
		{
			RotateFlipType rotateFlipType = RotateFlipType.RotateNoneFlipNone;
			if (null != ogControl)
				switch (ogControl.Angle)
				{
					case 90:
						rotateFlipType = RotateFlipType.Rotate90FlipNone;
						break;
	
					case -90:
						rotateFlipType = RotateFlipType.Rotate270FlipNone;
						break;
				} 			

			return rotateFlipType;
		}	
	}

	///////////////////////////////////////////////////////////////////////////////////
	// class OGCVisualElement
	///////////////////////////////////////////////////////////////////////////////////
	public class OGCVisualElement : IElement
	{
		// Variables
		protected OGControl ogControl = null;
		private string		name;
		private int         id;			      // currently, serial number of element in 
		                                      //   the control's alElement collection
		private Point		position;
		
		// Specify positions of element for hrizontal and vertical orientation of control
		private Point		horizPosition;		
		private Point		vertPosition;			
		
		private int			currentState;     // current element's state
		private ArrayList	alState = null;   // states collection 

		// State Transition matrix (particularly, for visual element reduced to vector)
		private int[]       aiControlStateTransition = null;
		
		// false - if SetCurrentState(int currentState) method of element has not been called yet.
		// true  - otherwise
		private bool	    justStarted = true;

		// CONSTRUCTOR
		internal protected OGCVisualElement(OGControl ogControl)
		{
			this.ogControl = ogControl;
			position.Y += ogControl.CaptionHeight; 

			alState = new ArrayList();
		}

		// PROPERTIES
		public Point Position
		{
			get	{ return position;  }
			set	{ position = value; }
		}

		public int X
		{
			get	{ return position.X;  }
			set	{ position.X = value; }
		}

		public int Y
		{
			get	{ return position.Y;  }
			set	{ position.Y = value; }
		}

		public Size Size
		{
			get	{ return CurrentStateObject.Picture.Size; }
		}

		public int CurrentState
		{
			get	{ return currentState;  }
		}

		public State CurrentStateObject
		{
			get
			{
				State state = null;
				if (alState.Count > 0)
					state = (State)alState[currentState];

				return state;
			}
		}

		public Bitmap Picture
		{
			get	
			{ 
				Bitmap picture = null;
				State state = CurrentStateObject;
				if (null != state)
					picture = state.Picture;
				
				return picture;
			}
		}

		public OGControl OGCtrl
		{
			get { return ogControl; }
		}

		protected int StatesCount
		{
			get { return alState.Count; }
		}
		
		// INDEXERS 
		
		// Get element's states by id
		protected internal virtual State this[int id]
		{
			get
			{
				if (alState.Count > 0)
					foreach (State state in alState)
						if (id == state.Id)
							return state;
				
				return null;
			}
		}

		// Get element's states by by name
		protected internal State this[string name]
		{
			get
			{
				if (alState.Count > 0)
					foreach (State state in alState)
						if (name == state.Name)
							return state;
				
				return null;
			}
		}

		// METHODS
		public void Draw(Graphics grfx, bool show)
		{	
			if (show)
				grfx.DrawImage(CurrentStateObject.Picture, position);
		}

		// Virtual
		protected virtual State StateFactory(string stateName, string pictureName, string ext)
		{
			State state = new State(ogControl, stateName, alState.Count);
			string fullPictureName = pictureName + "." + ext;
			state.CreatePictures(fullPictureName);
			return state;
		}

		// IElement implementation methods
		public void Initialize(string name, Point horizPosition, Point vertPosition, Size size)
		{
			if (null != ogControl)
			{
				this.name = name;
				id = ogControl.VisualElementsNumber;
				this.horizPosition = horizPosition;
				this.vertPosition = vertPosition;
				
				this.horizPosition.Y += ogControl.CaptionHeight; 
				this.vertPosition.Y += ogControl.CaptionHeight; 			
				
				Position = OGCLib.Orientation.Horizontal == ogControl.GetOrientation() 
					? this.horizPosition : this.vertPosition;
			}
		}
		
		public void SetControlStateTransitionElement(int currCtrlState, int currState, 
			int nextCtrlState)
		{
			if (null == aiControlStateTransition)
			{
				aiControlStateTransition = new int[ogControl.ControlStatesMax];
				for (int i=0; i<ogControl.ControlStatesMax; i++)
					aiControlStateTransition[i] = -1;
			}

			aiControlStateTransition[currCtrlState] = nextCtrlState;
		}

		public int AddState(string name, string pictureName, string ext)
		{
			State state = StateFactory(name, pictureName, ext);
			state.Id = alState.Count;
			alState.Add(state);
			return alState.Count;
		}

		public int GetNewControlState()
		{
			if (null != ogControl && null != aiControlStateTransition)
				return aiControlStateTransition[ogControl.CurrentState];
	
			return -1;
		}

		public void SetCurrentState(int currentState)
		{
			if (-1 != currentState)
				this.currentState = currentState;
			else
				if (justStarted)
					this.currentState = 0;
			
			justStarted = false;
		}

		public bool HasImage()
		{
			return true;
		}

		public string GetName()
		{
			return name;
		}

		public int GetId()
		{
			return id;
		}

		public string GetStateName()
		{
			return CurrentStateObject.Name;
		}

		public int GetNextStatesNum()
		{
			return 1;
		}

		public void UpdateGeometry()
		{
			position = OGCLib.Orientation.Horizontal == ogControl.GetOrientation()
				? horizPosition : vertPosition;

			if (alState.Count > 0)
				foreach (State state in alState)
					state.UpdateGeometry();
		}

		public bool HitTest(MouseEventArgs mea)
		{
			bool br = false;
			State state = CurrentStateObject;
			if (null != state)
			{
				state = (State)alState[currentState];
				br = state.HitTest(mea, position);
			}
			return br;
		}
	}

	///////////////////////////////////////////////////////////////////////////////////
	// class Factory
	///////////////////////////////////////////////////////////////////////////////////
	public class Factory : IFactory
	{
		public IElement CreateElement(OGControl ogControl)
		{
			return new OGCVisualElement(ogControl);
		}
	}	
}



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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior)
Israel Israel


  • Nov 2010: Code Project Contests - Windows Azure Apps - Winner
  • Feb 2011: Code Project Contests - Windows Azure Apps - Grand Prize Winner



Comments and Discussions