Click here to Skip to main content
15,898,222 members
Articles / Desktop Programming / Windows Forms

BusyBar

Rate me:
Please Sign up or sign in to vote.
4.84/5 (79 votes)
25 May 2005CPOL9 min read 250.8K   3.2K   170  
The only progress bar you will ever need
using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.Reflection;
using System.Runtime.Serialization;
using System.Diagnostics;

internal class ResFinder
{
	// Set this to the default namespace of your project
	// This will enable the designer bitmaps
	public const string DefaultNamespace = "BusyBar";
}

namespace Common
{

//-----------------------------------------------------------------------------
// BusyBar

	/// <summary>
	/// Summary description for BusyBar.
	/// </summary>
//	[ DesignerCategory( "Code" ) ]
	[ DefaultProperty( "Value" ) ]
//	[ Bindable( false ) ]
	[ Designer( typeof ( BusyBar.BusyBarDesigner ) ) ]
	[ ToolboxBitmap( typeof( ResFinder ), ResFinder.DefaultNamespace + ".Bitmaps.BusyBar.bmp" ) ]
	public class BusyBar : Control, ISupportInitialize, ICloneable
	{

//-----------------------------------------------------------------------------
// BusyBarDesigner

		public class BusyBarDesigner : ControlDesigner
		{
			protected override void PreFilterProperties( IDictionary properties )
			{
				base.PreFilterProperties( properties );

				properties.Remove( "DataBindings" );
				properties.Remove( "Tag" );
			}
		}

//-----------------------------------------------------------------------------
// statics

		private static readonly object EventBorderStyle    = new object();
		private static readonly object EventMargin         = new object();
		private static readonly object EventCornerRadius   = new object();
		private static readonly object EventMinimum        = new object();
		private static readonly object EventMaximum        = new object();
		private static readonly object EventValue          = new object();
		private static readonly object EventStep           = new object();
		private static readonly object EventPin            = new object();
		private static readonly object EventReverse        = new object();
		private static readonly object EventBounce         = new object();
		private static readonly object EventDrawBar        = new object();
		private static readonly object EventVertical       = new object();
		private static readonly object EventWrapInitial    = new object();
		private static readonly object EventWrap           = new object();
		private static readonly object EventPainterPreset  = new object();
		private static readonly object EventPainterObject  = new object();
//		private static readonly object EventPainterWorker  = new object();

//-----------------------------------------------------------------------------
// Fields

		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		private BorderStyle     _BorderStyle    = BorderStyle.FixedSingle ;
		private int             _Margin         = 2                       ;
		private int             _CornerRadius   = 9                       ;
		private int             _Minimum        = 0                       ;
		private int             _Maximum        = 100                     ;
		private int             _Value          = 0                       ;
		private int             _Step           = 1                       ;
		private Pins            _Pin            = Pins.None               ;
		private bool            _Reverse        = false                   ;
		private bool            _Bounce         = false                   ;
		private bool            _DrawBar        = true                    ;
		private bool            _Vertical       = false                   ;
		private bool            _WrapInitial    = false                   ;
		private bool            _Wrap           = true                    ;
		private PainterPresets  _PainterPreset  = PainterPresets.None     ;
		private IPainter        _PainterObject  = null                    ;

		private IPainter        _PainterWorker  = null                    ;

		private bool            _Initialising   = false                   ;
		private bool            _InitSetWorker  = false                   ;
		private bool            _Bouncing       = false                   ;

//-----------------------------------------------------------------------------
// Events

		[ Category( "1.BusyBar" ) ] public event EventHandler BorderStyleChanged    { add { Events.AddHandler( EventBorderStyle   , value ); } remove { Events.RemoveHandler( EventBorderStyle   , value ); } }
		[ Category( "1.BusyBar" ) ] public event EventHandler MarginChanged         { add { Events.AddHandler( EventMargin        , value ); } remove { Events.RemoveHandler( EventMargin        , value ); } }
		[ Category( "1.BusyBar" ) ] public event EventHandler CornerRadiusChanged   { add { Events.AddHandler( EventCornerRadius  , value ); } remove { Events.RemoveHandler( EventCornerRadius  , value ); } }
		[ Category( "1.BusyBar" ) ] public event EventHandler MinimumChanged        { add { Events.AddHandler( EventMinimum       , value ); } remove { Events.RemoveHandler( EventMinimum       , value ); } }
		[ Category( "1.BusyBar" ) ] public event EventHandler MaximumChanged        { add { Events.AddHandler( EventMaximum       , value ); } remove { Events.RemoveHandler( EventMaximum       , value ); } }
		[ Category( "1.BusyBar" ) ] public event EventHandler ValueChanged          { add { Events.AddHandler( EventValue         , value ); } remove { Events.RemoveHandler( EventValue         , value ); } }
		[ Category( "1.BusyBar" ) ] public event EventHandler StepChanged           { add { Events.AddHandler( EventStep          , value ); } remove { Events.RemoveHandler( EventStep          , value ); } }
		[ Category( "1.BusyBar" ) ] public event EventHandler PinChanged            { add { Events.AddHandler( EventPin           , value ); } remove { Events.RemoveHandler( EventPin           , value ); } }
		[ Category( "1.BusyBar" ) ] public event EventHandler ReverseChanged        { add { Events.AddHandler( EventReverse       , value ); } remove { Events.RemoveHandler( EventReverse       , value ); } }
		[ Category( "1.BusyBar" ) ] public event EventHandler BounceChanged         { add { Events.AddHandler( EventBounce        , value ); } remove { Events.RemoveHandler( EventBounce        , value ); } }
		[ Category( "1.BusyBar" ) ] public event EventHandler DrawBarChanged        { add { Events.AddHandler( EventDrawBar       , value ); } remove { Events.RemoveHandler( EventDrawBar       , value ); } }
		[ Category( "1.BusyBar" ) ] public event EventHandler VerticalChanged       { add { Events.AddHandler( EventVertical      , value ); } remove { Events.RemoveHandler( EventVertical      , value ); } }
		[ Category( "1.BusyBar" ) ] public event EventHandler WrapInitialChanged    { add { Events.AddHandler( EventWrapInitial   , value ); } remove { Events.RemoveHandler( EventWrapInitial   , value ); } }
		[ Category( "1.BusyBar" ) ] public event EventHandler WrapChanged           { add { Events.AddHandler( EventWrap          , value ); } remove { Events.RemoveHandler( EventWrap          , value ); } }
		[ Category( "1.BusyBar" ) ] public event EventHandler PainterPresetChanged  { add { Events.AddHandler( EventPainterPreset , value ); } remove { Events.RemoveHandler( EventPainterPreset , value ); } }
		[ Category( "1.BusyBar" ) ] public event EventHandler PainterObjectChanged  { add { Events.AddHandler( EventPainterObject , value ); } remove { Events.RemoveHandler( EventPainterObject , value ); } }
//		[ Category( "1.BusyBar" ) ] public event EventHandler PainterWorkerChanged  { add { Events.AddHandler( EventPainterWorker , value ); } remove { Events.RemoveHandler( EventPainterWorker , value ); } }

//-----------------------------------------------------------------------------
// ISupportInitialize Members

		public void BeginInit()
		{
			Debug.Assert( ! _Initialising );

			_Initialising = true;
		}

		public void EndInit()
		{
			Debug.Assert( _Initialising );

			_Initialising = false;

			OnEndInit();
		}

//-----------------------------------------------------------------------------
// Defaults

		public void SetDefaults()
		{
			if ( _Initialising ) { Debug.Assert( false ); return; }

			BackColor = Color.White;

//	no		BeginInit();
			_Initialising = true;

//			BorderStyle = BorderStyle.FixedSingle;
			Margin = 2;
			CornerRadius = 9;
			Minimum = 0;
			Maximum = 100;
			Value = 25;
			Pin = Pins.None;
			Reverse = false;
			Bounce = false;
			DrawBar = true;
//			Vertical = false;
			WrapInitial = false;
			Wrap = true;
//			PainterPreset  = PainterPresets.None;
//			PainterObject  = null;
//			PainterWorker  = null;

//	no		EndInit();
			_Initialising = false;

			SetRegion();
		}

//-----------------------------------------------------------------------------
// Properties

		[ Category( "1.BusyBar" ) ]
		[ DefaultValue( BorderStyle.FixedSingle ) ]
//		[ RefreshProperties( RefreshProperties.Repaint ) ]
		[ Description( "The style of the control's border") ]
		public BorderStyle BorderStyle
		{
			get { return _BorderStyle; }

			set
			{
				_BorderStyle = value;

				OnBorderStyleChanged( EventArgs.Empty );

				Invalidate();
			}
		}

		[ Category( "1.BusyBar" ) ]
		[ DefaultValue( 2 ) ]
		[ Description( "The space between the border and the bar") ]
		public int Margin
		{
			get { return _Margin; }
			
			set
			{
				_Margin = value;

				OnMarginChanged( EventArgs.Empty );

				Invalidate();
			}
		}

		[ Category( "1.BusyBar" ) ]
		[ DefaultValue( 9 ) ]
//		[ RefreshProperties( RefreshProperties.Repaint ) ]
		[ Description( "The radius of the control's corners") ]
		public int CornerRadius
		{
			get { return _CornerRadius; }

			set
			{
				_CornerRadius = value;

				SetRegion();

				OnCornerRadiusChanged( EventArgs.Empty );

				Invalidate();
			}
		}

		[ Category( "1.BusyBar" ) ]
		[ DefaultValue( 0 ) ]
		[ Description( "The lower bound") ]
		public int Minimum
		{
			get { return _Minimum; }

			set
			{
				if ( ! _Initialising )
					if ( value > _Value )
						throw new ArgumentException(
							"Minimum must be less than Value" );

				_Minimum = value;

				OnMinimumChanged( EventArgs.Empty );

				Invalidate();
			}
		
		}

		[ Category( "1.BusyBar" ) ]
		[ DefaultValue( 100 ) ]
		[ Description( "The upper bound") ]
		public int Maximum
		{
			get { return _Maximum; }

			set
			{
				if ( ! _Initialising )
					if ( value < _Value )
						throw new ArgumentException(
							"Maximum must be greater than Value" );

				_Maximum = value;

				OnMaximumChanged( EventArgs.Empty );

				Invalidate();
			}
		}

		[ Category( "1.BusyBar" ) ]
		[ DefaultValue( 0 ) ]
		[ Description( "The current value") ]
		public int Value
		{
			get { return _Value; }

			set
			{
				if ( ! _Initialising )
					if ( value < _Minimum || value > _Maximum )
						throw new ArgumentException(
							"Value must be between Minimum and Maximum" );

				_Value = value;

				OnValueChanged( EventArgs.Empty );

				Invalidate();
			}
		}

		[ Category( "1.BusyBar" ) ]
		[ DefaultValue( 1 ) ]
		[ Description( "The size of each step") ]
		public int Step
		{
			get { return _Step; }
			
			set
			{
				_Step = value;

				OnStepChanged( EventArgs.Empty );

				Invalidate();
			}
		}

		[ Category( "1.BusyBar" ) ]
		[ DefaultValue( Pins.None ) ]
		[ Description( "Whether the bar is anchored") ]
		public Pins Pin
		{
			get { return _Pin; }

			set
			{
				_Pin = value;

				OnPinChanged( EventArgs.Empty );

				Invalidate();
			}
		}

		[ Category( "1.BusyBar" ) ]
		[ DefaultValue( false ) ]
		[ Description( "Set to true to go right-to-left or bottom-to-top") ]
		public bool Reverse
		{
			get { return _Reverse; }

			set
			{
				_Reverse = value;

				OnReverseChanged( EventArgs.Empty );

				Invalidate();
			}
		}

		[ Category( "1.BusyBar" ) ]
		[ DefaultValue( false ) ]
		[ Description( "Boing !") ]
		public bool Bounce
		{
			get { return _Bounce; }

			set
			{
				_Bounce = value;

				OnBounceChanged( EventArgs.Empty );

				Invalidate();
			}
		}

		[ Category( "1.BusyBar" ) ]
		[ DefaultValue( true ) ]
		[ Description( "Enable or disable the bar drawing") ]
		public bool DrawBar
		{
			get { return _DrawBar; }

			set
			{
				_DrawBar = value;

				OnDrawBarChanged( EventArgs.Empty );

				Invalidate();
			}
		}

		[ Category( "1.BusyBar" ) ]
		[ DefaultValue( false ) ]
		[ Description( "Control orientation") ]
		public bool Vertical
		{
			get { return _Vertical; }

			set
			{
				_Vertical = value;

				OnVerticalChanged( EventArgs.Empty );

				Invalidate();
			}
		}

		[ Category( "1.BusyBar" ) ]
		[ DefaultValue( false ) ]
		[ Description( "Initial wrap around") ]
		public bool WrapInitial
		{
			get { return _WrapInitial; }
			
			set
			{
				_WrapInitial = value;

				OnWrapInitialChanged( EventArgs.Empty );

				Invalidate();
			}
		}

		[ Category( "1.BusyBar" ) ]
		[ DefaultValue( true ) ]
		[ Description( "Wrap around") ]
		public bool Wrap
		{
			get { return _Wrap; }
			
			set
			{
				_Wrap = value;

				OnWrapChanged( EventArgs.Empty );

				Invalidate();
			}
		}

		[ Category( "2.Painter" ) ]
		[ DefaultValue( PainterPresets.None ) ]
		[ Description( "Painter preset") ]
		[ RefreshProperties( RefreshProperties.All ) ]
		public PainterPresets PainterPreset
		{
			get { return _PainterPreset; }
			
			set
			{
				_PainterPreset = value;

				if ( _PainterPreset != PainterPresets.None )
				{
					_PainterObject = null;
//					_PainterWorker = null;
				}

				if ( ! _Initialising ) SetWorker();
				else
					_InitSetWorker = true;

				OnPainterPresetChanged( EventArgs.Empty );
				OnPainterObjectChanged( EventArgs.Empty );

				Invalidate();
			}
		}

		[ Category( "2.Painter" ) ]
		[ DefaultValue( null ) ]
		[ Description( "Painter object") ]
		[ RefreshProperties( RefreshProperties.All ) ]
		public IPainter PainterObject
		{
			get
			{
				return _PainterObject;
			}

			set
			{
				_PainterObject = value;

				if ( _PainterObject != null )
				{
					_PainterPreset = PainterPresets.None;
//					_PainterWorker = null;

					_PainterObject.BusyBar = this;
				}

				if ( ! _Initialising ) SetWorker();
				else
					_InitSetWorker = true;

				OnPainterPresetChanged( EventArgs.Empty );
				OnPainterObjectChanged( EventArgs.Empty );

				Invalidate();
			}
		}

		[ Browsable( false ) ]
		[ Category( "2.Painter" ) ]
		[ DefaultValue( null ) ]
		[ Description( "The worker painter object") ]
		[ DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden ) ]
		public IPainter PainterWorker
		{
			get { return _PainterWorker; }
		}

//-----------------------------------------------------------------------------
// OnEndInit

		private void OnEndInit()
		{
			ValidateRange();

			if ( _InitSetWorker )
			{
				_InitSetWorker = false;

				SetWorker();
			}

//			SetRegion();

			Invalidate();
		}

		private void ValidateRange()
		{
			if ( _Value < _Minimum || _Value > _Maximum )
				throw new ArgumentException(
					"Value must be between Minimum and Maximum" );
		}

//-----------------------------------------------------------------------------
// SetWorker

		private void SetWorker()
		{
			if ( _PainterObject != null )
				SetWorkerFromObject();
			else
				SetWorkerFromPreset();
		}

		private void SetWorkerFromPreset()
		{
			switch ( _PainterPreset )
			{
			case PainterPresets.None:
				_PainterWorker = null;
				break;

			case PainterPresets.Line:
				_PainterWorker = new PainterLine( this, false );
				break;

			case PainterPresets.XP:
				_PainterWorker = new PainterXP( this, false );
				break;

			case PainterPresets.PathGradient:
				_PainterWorker = new PainterPathGradient( this, false );
				break;

			case PainterPresets.Clock:
				_PainterWorker = new PainterClock( this, false );
				break;

			case PainterPresets.Sillyscope:
				_PainterWorker = new PainterSillyscope( this, false );
				break;

			default:
				Debug.Assert( false );
				break;
			}
		}

		private void SetWorkerFromObject()
		{
			_PainterWorker = _PainterObject;
		}

//-----------------------------------------------------------------------------
// Constructors

		public BusyBar()
		{
			InitializeComponent();

			DoSetStyle();
		}

		protected BusyBar( BusyBar o )
		{
			InitializeComponent();

			CopyThis( o );
		}

		private void CopyThis( BusyBar o )
		{
			BackColor = o.BackColor;
			ForeColor = o.ForeColor;

			_BorderStyle   = o._BorderStyle   ;
			_Margin        = o._Margin        ;
			_CornerRadius  = o._CornerRadius  ;
			_Minimum       = o._Minimum       ;
			_Maximum       = o._Maximum       ;
			_Value         = o._Value         ;
			_Step          = o._Step          ;
			_Pin           = o._Pin           ;
			_Reverse       = o._Reverse       ;
			_Bounce        = o._Bounce        ;
			_DrawBar       = o._DrawBar       ;
			_Vertical      = o._Vertical      ;
			_WrapInitial   = o._WrapInitial   ;
			_Wrap          = o._Wrap          ;
			_PainterPreset = o._PainterPreset ;

			if ( o._PainterObject == null ) _PainterObject = null;
			else
			{
				_PainterObject = ( IPainter ) o._PainterObject.Clone();
				_PainterObject.BusyBar = this;
			}

			if ( o._PainterWorker == null ) _PainterWorker = null;
			else
			{
				_PainterWorker = ( IPainter ) o._PainterWorker.Clone();
				_PainterWorker.BusyBar = this;
			}

//			SetWorker();

			DoSetStyle();
		}

		public virtual BusyBar CreateCopy()
		{
			return new BusyBar( this );
		}

		public virtual object Clone()
		{
			return CreateCopy();
		}

		private void DoSetStyle()
		{
			SetStyle(
				ControlStyles.DoubleBuffer |
				ControlStyles.AllPaintingInWmPaint | 
				ControlStyles.UserPaint | 
				ControlStyles.Opaque | 
				ControlStyles.ResizeRedraw,
				true );
		}

//		protected override CreateParams CreateParams
//		{
//			get
//			{
//				CreateParams p = base.CreateParams;
//
//				if ( _BorderStyle == BorderStyle.Fixed3D )
//					p.ExStyle |= 0x200;
//
//				return p;
//			}
//		}


		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if( components != null )
					components.Dispose();
			}
			base.Dispose( disposing );
		}

//-----------------------------------------------------------------------------
// InitializeComponent

		#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()
		{
			// 
			// BusyBar
			// 
			this.Resize += new System.EventHandler(this.BusyBar_Resize);

		}
		#endregion

//-----------------------------------------------------------------------------
// Events

		protected virtual void OnBorderStyleChanged   ( EventArgs e ) { EventHandler h = Events[ EventBorderStyle   ] as EventHandler; if ( h != null ) h( this, e ); }
		protected virtual void OnMarginChanged        ( EventArgs e ) { EventHandler h = Events[ EventMargin        ] as EventHandler; if ( h != null ) h( this, e ); }
		protected virtual void OnCornerRadiusChanged  ( EventArgs e ) { EventHandler h = Events[ EventCornerRadius  ] as EventHandler; if ( h != null ) h( this, e ); }
		protected virtual void OnMinimumChanged       ( EventArgs e ) { EventHandler h = Events[ EventMinimum       ] as EventHandler; if ( h != null ) h( this, e ); }
		protected virtual void OnMaximumChanged       ( EventArgs e ) { EventHandler h = Events[ EventMaximum       ] as EventHandler; if ( h != null ) h( this, e ); }
		protected virtual void OnValueChanged         ( EventArgs e ) { EventHandler h = Events[ EventValue         ] as EventHandler; if ( h != null ) h( this, e ); }
		protected virtual void OnStepChanged          ( EventArgs e ) { EventHandler h = Events[ EventStep          ] as EventHandler; if ( h != null ) h( this, e ); }
		protected virtual void OnPinChanged           ( EventArgs e ) { EventHandler h = Events[ EventPin           ] as EventHandler; if ( h != null ) h( this, e ); }
		protected virtual void OnReverseChanged       ( EventArgs e ) { EventHandler h = Events[ EventReverse       ] as EventHandler; if ( h != null ) h( this, e ); }
		protected virtual void OnBounceChanged        ( EventArgs e ) { EventHandler h = Events[ EventBounce        ] as EventHandler; if ( h != null ) h( this, e ); }
		protected virtual void OnDrawBarChanged       ( EventArgs e ) { EventHandler h = Events[ EventDrawBar       ] as EventHandler; if ( h != null ) h( this, e ); }
		protected virtual void OnVerticalChanged      ( EventArgs e ) { EventHandler h = Events[ EventVertical      ] as EventHandler; if ( h != null ) h( this, e ); }
		protected virtual void OnWrapInitialChanged   ( EventArgs e ) { EventHandler h = Events[ EventWrapInitial   ] as EventHandler; if ( h != null ) h( this, e ); }
		protected virtual void OnWrapChanged          ( EventArgs e ) { EventHandler h = Events[ EventWrap          ] as EventHandler; if ( h != null ) h( this, e ); }
		protected virtual void OnPainterPresetChanged ( EventArgs e ) { EventHandler h = Events[ EventPainterPreset ] as EventHandler; if ( h != null ) h( this, e ); }
		protected virtual void OnPainterObjectChanged ( EventArgs e ) { EventHandler h = Events[ EventPainterObject ] as EventHandler; if ( h != null ) h( this, e ); }
//		protected virtual void OnPainterWorkerChanged ( EventArgs e ) { EventHandler h = Events[ EventPainterWorker ] as EventHandler; if ( h != null ) h( this, e ); }
																															
//-----------------------------------------------------------------------------
// Paths

		private void SetPath( Rectangle c, GraphicsPath path )
		{
//			c.Inflate( -10, -10 );

			if ( c.Width <= 0 || c.Height <= 0 ) return;

			const int k = 7;

			int d = _CornerRadius;

			if ( d + k > c.Width  ) d = c.Width  - k;
			if ( d + k > c.Height ) d = c.Height - k;
			if ( d <= 0 ) return;

			int left = c.Left;
			int right = c.Right - d - 0;

			int top = c.Top;
			int bottom = c.Bottom - d - 0;

			path.AddArc( left      , top        , d     , d     , 180, 90 );
			path.AddArc( right     , top        , d     , d + k , 270, 90 );
			path.AddArc( right - k , bottom - k , d + k , d + k , 000, 90 );
			path.AddArc( left      , bottom     , d + k , d     , 090, 90 );
			path.CloseFigure();
		}

		private GraphicsPath Path( int space )
		{
			GraphicsPath path = new GraphicsPath();

			Rectangle c = ClientRectangle;
			c.Inflate( - space, - space );

			if ( _CornerRadius <= 0 )
			{
				path.AddRectangle( c );
			}
			else
			{
				SetPath( c, path );
			}

			return path;
		}

		private GraphicsPath OutlinePath
		{
			get
			{
				return Path( 0 );
			}
		}

		private GraphicsPath InteriorPath
		{
			get
			{
				int space = ( _BorderStyle == BorderStyle.None ) ? 0 : 1;

				return Path( space );
			}
		}

		private GraphicsPath ClientPath
		{
			get
			{
				int space = ( _BorderStyle == BorderStyle.None ) ? 0 : 1;
				space += _Margin;

				return Path( space );
			}
		}

		private Region OutlineRegion
		{
			get
			{
				Region r = null;

				if ( _CornerRadius <= 0 )
					r = new Region( ClientRectangle );
				else
					r = new Region( OutlinePath );

				return r;
			}
		}

		private Region InteriorRegion
		{
			get
			{
				Region r = null;

				if ( _CornerRadius <= 0 )
				{
					Rectangle c = ClientRectangle;
					if ( _BorderStyle != BorderStyle.None ) c.Inflate( -1, -1 );
					r = new Region( c );
				}
				else
					r = new Region( InteriorPath );

				return r;
			}
		}

		private Region ClientRegion
		{
			get
			{
				Region r = null;

				if ( _CornerRadius <= 0 )
				{
					Rectangle c = ClientRectangle;
					if ( _BorderStyle != BorderStyle.None ) c.Inflate( -1, -1 );
					c.Inflate( - _Margin, - _Margin );
					r = new Region( c );
				}
				else
					r = new Region( ClientPath );

				return r;
			}
		}

//-----------------------------------------------------------------------------
// Handlers

		private void BusyBar_Resize(object sender, System.EventArgs e)
		{
			SetRegion();
		}

		protected override void OnPaintBackground( PaintEventArgs e )
		{
			base.OnPaintBackground( e );
		}

		protected override void OnPaint( PaintEventArgs e )
		{
			base.OnPaint( e );

			Graphics g = e.Graphics;

			g.Clear( BackColor );

			PaintBorder( g );

			if ( _PainterWorker != null )
			{
				Region r = ClientRegion;
				g.Clip = r;
				_PainterWorker.Paint( g, r );
			}
		}

		private void PaintBorder( Graphics g )
		{
			switch ( _BorderStyle )
			{
			case BorderStyle.None:
				break;

			case BorderStyle.FixedSingle:
			{
				if ( _CornerRadius <= 0 )
				{
					ControlPaint.DrawBorder3D( g, ClientRectangle, Border3DStyle.Flat );
				}
				else
				{
					PaintBorderPath( g );
				}

				break;
			}

			case BorderStyle.Fixed3D:
			{
				if ( _CornerRadius <= 0 )
				{
					ControlPaint.DrawBorder3D( g, ClientRectangle, Border3DStyle.SunkenOuter );
				}
				else
				{
					PaintBorderPath( g );
				}

				break;
			}

			default:
				Debug.Assert( false );
				break;
			}
		}

		private void PaintBorderPath( Graphics g )
		{
//			g.DrawPath( Pens.Black, OutlinePath );

			g.FillPath( Brushes.Black, OutlinePath );

//			g.FillPath( Brushes.Red, InteriorPath );

			using ( Brush brush = new SolidBrush( BackColor ) )
				g.FillPath( brush, InteriorPath );
//				g.FillPath( brush, ClientPath );
		}

//-----------------------------------------------------------------------------
// Methods

		public void SetRegion()
		{
			if ( _CornerRadius <= 0 )
				Region = null;
			else
				Region = OutlineRegion;

			Invalidate();
		}

		public void Reset()
		{
			_Value = _Reverse ? _Maximum : _Minimum;

			if ( _PainterWorker != null ) _PainterWorker.Reset();

			Invalidate();
		}

		public void PerformStep()
		{
			if ( ! _Bounce )
			{
				int i = _Reverse ? -1 : 1;
				_Value += i * _Step;

				if ( _Value < _Minimum ) _Value = _Maximum;
				if ( _Value > _Maximum ) _Value = _Minimum;
			}
			else
			{
				int i = _Bouncing ? -1 : 1;
				_Value += i * _Step;

				if ( _Value < _Minimum )
				{
					_Value = _Minimum;
					_Bouncing = false;
				}

				if ( _Value > _Maximum )
				{
					_Value = _Maximum;
					_Bouncing = true;
				}
			}

			Invalidate();
		}

//-----------------------------------------------------------------------------
// enums

		public enum Pins
		{
			None,
			Start,
			End,
		}

		public enum PainterPresets
		{
			None,
			Line,
			XP,
			PathGradient,
			Clock,
			Sillyscope,
		}

//-----------------------------------------------------------------------------

		// BusyBar
	}

//-----------------------------------------------------------------------------
// IPainter

	public interface IPainter : ICloneable
	{
		IPainter CreateCopy();
		BusyBar BusyBar { get; set; }
		void Reset();
		void Paint( Graphics g, Region r );
	}

//-----------------------------------------------------------------------------
// PainterBase

//	[ Designer( typeof( PainterBase.PainterBaseDesigner ), typeof( IDesigner ) ) ]
//	[ TypeConverter( typeof( PainterBase.PainterBaseTypeConverter ) ) ]
	public abstract class PainterBase : Component, IPainter
//	public class PainterBase : Component, IPainter
	{
		public class PainterBaseDesigner : ComponentDesigner
		{
		}

		public class PainterBaseTypeConverter : TypeConverter
		{
			public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
			{
				MessageBox.Show( "PainterBase.CanConvertFrom " + sourceType.FullName );
				return base.CanConvertFrom (context, sourceType);
			}

			public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
			{
				bool b = base.CanConvertTo (context, destinationType);
				MessageBox.Show( "PainterBase.CanConvertTo " + destinationType.FullName + " is " + b );
				if ( destinationType == typeof( InstanceDescriptor ) ) return true;
				return b;
			}

			public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
			{
				MessageBox.Show( "PainterBase.ConvertTo " + destinationType.FullName + "\nfrom " + value.GetType().FullName );
//				if ( destinationType == typeof( InstanceDescriptor ) );
				return base.ConvertTo (context, culture, value, destinationType);
			}

		}

		private BusyBar _Bar = null;

		protected BusyBar Bar { get { return _Bar; } }

		[ Browsable( false ) ]
		[ Category( "0.BusyBar" ) ]
		[ DefaultValue( null ) ]
		[ Description( "The BusyBar that is using this painter") ]
		[ DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden ) ]
		public BusyBar BusyBar
		{
			get { return _Bar; }
			
			set
			{
//				if ( value == null ) throw new ArgumentException( "Value must not be null" );

				_Bar = value;

				if ( _Bar != null ) OnBarSet();
			}
		}

		protected PainterBase()
		{
		}

		protected PainterBase( BusyBar bar )
		{
			_Bar = bar;
		}

		protected PainterBase( PainterBase o )
		{
			CopyThis( o );
		}

		public virtual void Copy( PainterBase o )
		{
			CopyThis( o );
		}

		private void CopyThis( PainterBase o )
		{
			_Bar = o._Bar;
		}

		public abstract IPainter CreateCopy();
//		public virtual IPainter CreateCopy() { Debug.Assert( false ); return null; }

		public virtual object Clone()
		{
			return CreateCopy();
		}

		protected virtual void OnBarSet()
		{
			Reset();
		}

		public virtual void Reset() {}

		protected virtual void SetDefaults( bool setBarDefaults )
		{
			if ( Bar != null && setBarDefaults ) Bar.SetDefaults();
		}

		public virtual void Paint( Graphics g, Region r )
		{
//			g.FillRegion( Brushes.Silver, r );
		}
	}

//-----------------------------------------------------------------------------
// PainterLine

//	[ ToolboxItem( typeof( PainterLine.PainterLineToolboxItem ) ) ]
//	[ Designer( typeof( PainterLine.PainterLineDesigner ), typeof( IDesigner ) ) ]
//	[ TypeConverter( typeof( PainterLine.PainterLineTypeConverter ) ) ]
	[ ToolboxBitmap( typeof( ResFinder ), ResFinder.DefaultNamespace + ".Bitmaps.PainterLine.bmp" ) ]
//	[ ToolboxBitmap( typeof( ResFinder ), "Bitmaps.PainterLine.bmp" ) ]
//	[ ToolboxBitmap( typeof( ResFinder ), "PainterLine.bmp" ) ]
	public class PainterLine : PainterBase
	{
		public class PainterLineTypeConverter : TypeConverter
		{
			public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
			{
				bool b = base.CanConvertFrom (context, sourceType);
				MessageBox.Show( "PainterLine.CanConvertFrom " + sourceType.FullName + "\nfrom: " + context.Instance + "\nis " + b );
				return b;
			}

			public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
			{
				bool b = base.CanConvertTo (context, destinationType);
				MessageBox.Show( "PainterLine.CanConvertTo " + destinationType.FullName + " is " + b );
				if ( destinationType == typeof( InstanceDescriptor ) ) return true;
				return b;
			}

			public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
			{
				if ( 1 == 1 )
				{
					string s = String.Empty;
					s += "PainterLine.ConvertTo " + destinationType.FullName;
					s += "\nfrom " + value.GetType().FullName;
					
					if ( context == null ) s += "\ncontext is null";
					else
						if ( context.Instance == null ) s += "\nInstance is null";
					else
						s += "\nInstance: " + context.Instance.GetType().FullName;

					MessageBox.Show( s );
				}
				
				if ( destinationType == typeof( InstanceDescriptor ) )
					if ( value is PainterLine )
					{
						PainterLine o = ( PainterLine ) value;

						ConstructorInfo ctor = typeof( PainterLine ).GetConstructor(
							Type.EmptyTypes );

						if ( ctor != null )
						{
							MessageBox.Show( "PainterLine.ConvertTo success!" );
							return new InstanceDescriptor(
								ctor,
								null,
								true );
						}

//						ConstructorInfo ctor = typeof( PainterLine ).GetConstructor(
//							BindingFlags.Public | BindingFlags.Instance,
//							null,
//							new Type[]
//							{
//								typeof( Color ),
//								typeof( int ),
//							},
//							null );
//
//						if ( ctor != null )
//						{
//							MessageBox.Show( "PainterLine.ConvertTo success!" );
//							return new InstanceDescriptor(
//								ctor,
//								new object[]
//								{
//									o.LineColor,
//									o.LineWidth,
//								},
//								true );
//						}
					}
				
				return base.ConvertTo (context, culture, value, destinationType);
			}

		}

		[ Serializable ]
			public class PainterLineToolboxItem : ToolboxItem
			//, ISerializable
		{
			public PainterLineToolboxItem()
			{
				DisplayName = "Fubar";
			}

			public PainterLineToolboxItem( SerializationInfo info, StreamingContext context )
			{
				base.Deserialize( info, context );
				DisplayName = "Fubar";
			}

			protected override void Deserialize(SerializationInfo info, StreamingContext context)
			{
				base.Deserialize( info, context );
				DisplayName = "Fubar";
			}

			protected override void Serialize(SerializationInfo info, StreamingContext context)
			{
				base.Serialize( info, context );
			}

//			public void GetObjectData(SerializationInfo info, StreamingContext context)
//			{
//			}
		}

		public class PainterLineDesigner : ComponentDesigner
		{
		}

		public enum Presets
		{
			None,
			Bar,
		}

		private Presets _Preset = Presets.None;

		private Color _LineColor = Color.Empty;
		private int _LineWidth = 1;

		private bool _Wrap = false;

		[ Category( "1.Presets" ) ]
		[ DefaultValue( Presets.None ) ]
		[ Description( "Preset settings") ]
		[ RefreshProperties( RefreshProperties.All ) ]
		[ DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden ) ]
		public Presets Preset
		{
			get { return _Preset; }
			
			set
			{
				_Preset = value;

				SetFromPreset( true );

				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "2.Line" ) ]
//		[ DefaultValue( Color.Empty ) ]
		[ Description( "The Color used to draw the line") ]
		public Color LineColor
		{
			get { return _LineColor; }

			set
			{
				_LineColor = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "2.Line" ) ]
		[ DefaultValue( 1 ) ]
		[ Description( "The width of the line") ]
		public int LineWidth
		{
			get { return _LineWidth; }

			set
			{
				_LineWidth = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		public PainterLine() {}

//		public PainterLine(
//			Color lineColor,
//			int lineWidth )
//		{
//			_LineColor = lineColor;
//			_LineWidth = lineWidth;
//		}

		public PainterLine( BusyBar bar ) : base ( bar )
		{
			OnBarSet();

			// Presets.None
			SetFromPreset( true );
		}

		public PainterLine( BusyBar bar, bool setBarDefaults ) : base ( bar )
		{
			OnBarSet();

			// Presets.None
			SetFromPreset( setBarDefaults );
		}

		protected PainterLine( PainterLine o ) : base( o )
		{
//			OnBarSet();

			CopyThis( o );
		}

		public override void Copy( PainterBase o )
		{
			base.Copy( o );

			if ( ! ( o is PainterLine ) ) Debug.Assert( false );
			else
				CopyThis( ( PainterLine ) o );
		}

		private void CopyThis( PainterLine o )
		{
			_Preset    = o._Preset    ;

			_LineColor = o._LineColor ;
			_LineWidth = o._LineWidth ;

//			_Wrap      = o._Wrap      ;
		}

		public override IPainter CreateCopy()
		{
			return new PainterLine( this );
		}

		protected override void OnBarSet()
		{
			base.OnBarSet();

			if ( _LineColor == Color.Empty ) _LineColor = Bar.ForeColor;
		}

		public override void Reset()
		{
			base.Reset();

			_Wrap = Bar.WrapInitial;
		}

		protected override void SetDefaults( bool setBarDefaults )
		{
			base.SetDefaults( setBarDefaults );

			_LineColor = Color.Empty;
			_LineWidth = 1;

			if ( Bar != null )
			{
				_LineColor  = Bar.ForeColor;
			}
		}

		private void SetFromPreset( bool setBarDefaults )
		{
			switch ( _Preset )
			{
			case Presets.None:

				SetDefaults( setBarDefaults );

				break;

			case Presets.Bar:

				SetDefaults( setBarDefaults );

				_LineWidth = 50;

				break;

			default:
				Debug.Assert( false );
				break;
			}
		}

		public override void Paint( Graphics g, Region r )
		{
			base.Paint( g, r );

			if ( Bar.DrawBar )
			{
				RectangleF bounds = r.GetBounds( g );
				float ratio = ( ( float ) Bar.Value ) / ( Bar.Maximum - Bar.Minimum );

				if ( ! Bar.Vertical )
				{
					float x2 = bounds.Left + ( bounds.Width * ratio );
					float x1 = x2 - bounds.Width;
					float x3 = x2 + bounds.Width;

					if (
						x1 + ( _LineWidth / 2 ) < bounds.Left &&
						x3 - ( _LineWidth / 2 ) > bounds.Right )
						_Wrap = Bar.Wrap;

					using ( Pen pen = new Pen( _LineColor, _LineWidth ) )
					{
						if ( _Wrap ) g.DrawLine( pen, x1, bounds.Top, x1, bounds.Bottom );
						g.DrawLine( pen, x2, bounds.Top, x2, bounds.Bottom );
						if ( _Wrap ) g.DrawLine( pen, x3, bounds.Top, x3, bounds.Bottom );
					}
				}
					// Vertical
				else
				{
					float y2 = bounds.Top + ( bounds.Height * ratio );
					float y1 = y2 - bounds.Height;
					float y3 = y2 + bounds.Height;

					if (
						y1 + ( _LineWidth / 2 ) < bounds.Top &&
						y3 - ( _LineWidth / 2 ) > bounds.Bottom )
						_Wrap = Bar.Wrap;

					using ( Pen pen = new Pen( _LineColor, _LineWidth ) )
					{
						if ( _Wrap ) g.DrawLine( pen, bounds.Left, y1, bounds.Right, y1 );
						g.DrawLine( pen, bounds.Left, y2, bounds.Right, y2 );
						if ( _Wrap ) g.DrawLine( pen, bounds.Left, y3, bounds.Right, y3 );
					}
				}
			}
		}
	}

//-----------------------------------------------------------------------------
// 

	public class BusyBarGrid
	{
		public static void Draw(
			Graphics g,
			Color lineColor,
			int lineWidth,
			float spaceX,
			float spaceY )
		{
			if ( lineWidth <= 0 ) return;

			RectangleF r = g.Clip.GetBounds( g );

			using ( Pen pen = new Pen( lineColor, lineWidth ) )
			{
				// Vertical
				float xCentre = r.Left + ( r.Width / 2f );
				float xCount = ( r.Width % spaceX ) + 1;
				float xExtent = spaceX * xCount;
				float xLeft = xCentre - xExtent;
				float xRight = xCentre + xExtent;

				for ( float x = xLeft ; x < xRight ; x += spaceX )
					g.DrawLine( pen, x, r.Top, x, r.Bottom );

				// Horizontal
				float yCentre = r.Top + ( r.Height / 2f );
				float yCount = ( r.Height % spaceY ) + 1;
				float yExtent = spaceY * yCount;
				float yTop = yCentre - yExtent;
				float yBottom = yCentre + yExtent;

				for ( float y = yTop ; y < yBottom ; y += spaceY )
					g.DrawLine( pen, r.Left, y, r.Right, y );
			}
		}
	}



//-----------------------------------------------------------------------------
// BlockLines

	public class BlockLines
	{
		private int _BlockWidth = 0;
		private int _BlockLineWidth = 0;
		private bool _BlockScroll = false;
		private RectangleF _Bounds = RectangleF.Empty;
		private RectangleF _R1 = RectangleF.Empty;
		private RectangleF _R2 = RectangleF.Empty;
		private RectangleF _R3 = RectangleF.Empty;
		private float _XValue = 0;
		private float _YValue = 0;
//		private BusyBar.Pins _Pin = BusyBar.Pins.None;

		private float _R1Top = 0;
		private float _R1Left = 0;
		private float _R1Right = 0;
		private float _R1Bottom = 0;
		private float _R2Top = 0;
		private float _R2Left = 0;
		private float _R2Right = 0;
		private float _R2Bottom = 0;
		private float _R3Top = 0;
		private float _R3Left = 0;
		private float _R3Right = 0;
		private float _R3Bottom = 0;

		private bool _R1TopSet = false;
		private bool _R1LeftSet = false;
		private bool _R2TopSet = false;
		private bool _R2LeftSet = false;
		private bool _R3LeftSet = false;
		private bool _R3TopSet = false;

		public int BlockWidth { get { return _BlockWidth; } set { _BlockWidth = value; } }
		public int BlockLineWidth { get { return _BlockLineWidth; } set { _BlockLineWidth = value; } }
		public bool BlockScroll { get { return _BlockScroll; } set { _BlockScroll = value; } }
		public RectangleF Bounds { get { return _Bounds; } set { _Bounds = value; } }
		public RectangleF R1 { get { return _R1; } set { _R1 = value; } }
		public RectangleF R2 { get { return _R2; } set { _R2 = value; } }
		public RectangleF R3 { get { return _R3; } set { _R3 = value; } }
		public float XValue { get { return _XValue; } set { _XValue = value; } }
		public float YValue { get { return _YValue; } set { _YValue = value; } }
//		public BusyBar.Pins Pin { get { return _Pin; } set { _Pin = value; } }

		public float R1Top { get { return _R1Top; } }
		public float R1Left { get { return _R1Left; } }
		public float R1Right { get { return _R1Right; } }
		public float R1Bottom { get { return _R1Bottom; } }
		public float R2Top { get { return _R2Top; } }
		public float R2Left { get { return _R2Left; } }
		public float R2Right { get { return _R2Right; } }
		public float R2Bottom { get { return _R2Bottom; } }
		public float R3Top { get { return _R3Top; } }
		public float R3Left { get { return _R3Left; } }
		public float R3Right { get { return _R3Right; } }
		public float R3Bottom { get { return _R3Bottom; } }

		public ArrayList HorizontalLines
		{
			get
			{
				ArrayList list = new ArrayList();

				int period = _BlockWidth + _BlockLineWidth;

				if ( ! _BlockScroll )
				{
					float xLine = _Bounds.Left - ( 2 * period );
					for ( ; xLine < _Bounds.Right + ( 2 * period ) ; xLine += period )
					{
						bool z = false;

						if ( xLine >= _R1.Left && xLine <= _R1.Right )
						{
							if ( ! _R1LeftSet ) { _R1LeftSet = true; _R1Left = xLine; }
							_R1Right = xLine;
							z = true;
						}

						if ( xLine >= _R2.Left && xLine <= _R2.Right )
						{
							if ( ! _R2LeftSet ) { _R2LeftSet = true; _R2Left = xLine; }
							_R2Right = xLine;
							z = true;
						}

						if ( xLine >= _R3.Left && xLine <= _R3.Right )
						{
							if ( ! _R3LeftSet ) { _R3LeftSet = true; _R3Left = xLine; }
							_R3Right = xLine;
							z = true;
						}

						if ( z ) list.Add( xLine );
					}

//					if ( _Pin == BusyBar.Pins.End )
//					{
//						_R2Right += period;
//						list.Add( _R2Right );
//					}
				}
					// BlockScroll
				else
				{
					float xLine = 0;

					xLine = _Bounds.Left - ( 2 * period );
					xLine += _XValue % period;
					xLine -= _Bounds.Width % period;
					for ( ; xLine < _Bounds.Right + ( 2 * period ) ; xLine += period )
						if ( xLine >= _R1.Left && xLine <= _R1.Right )
						{
							if ( ! _R1LeftSet ) { _R1LeftSet = true; _R1Left = xLine; }
							_R1Right = xLine;
							list.Add( xLine );
						}

					xLine = _Bounds.Left - ( 2 * period );
					xLine += _XValue % period;
					for ( ; xLine < _Bounds.Right + ( 2 * period ) ; xLine += period )
						if ( xLine >= _R2.Left && xLine <= _R2.Right )
						{
							if ( ! _R2LeftSet ) { _R2LeftSet = true; _R2Left = xLine; }
							_R2Right = xLine;
							list.Add( xLine );
						}

					xLine = _Bounds.Left - ( 2 * period );
					xLine += _XValue % period;
					xLine += _Bounds.Width % period;
					for ( ; xLine < _Bounds.Right + ( 2 * period ) ; xLine += period )
						if ( xLine >= _R3.Left && xLine <= _R3.Right )
						{
							if ( ! _R3LeftSet ) { _R3LeftSet = true; _R3Left = xLine; }
							_R3Right = xLine;
							list.Add( xLine );
						}
				}

				return list;
			}
		}
		public ArrayList VerticalLines
		{
			get
			{
				ArrayList list = new ArrayList();

				int period = _BlockWidth + _BlockLineWidth;

				if ( ! _BlockScroll )
				{
					float yLine = _Bounds.Top - ( 2 * period );
					for ( ; yLine < _Bounds.Bottom + ( 2 * period ) ; yLine += period )
					{
						bool z = false;

						if ( yLine >= _R1.Top && yLine <= _R1.Bottom )
						{
							if ( ! _R1TopSet ) { _R1TopSet = true; _R1Top = yLine; }
							_R1Bottom = yLine;
							z = true;
						}

						if ( yLine >= _R2.Top && yLine <= _R2.Bottom )
						{
							if ( ! _R2TopSet ) { _R2TopSet = true; _R2Top = yLine; }
							_R2Bottom = yLine;
							z = true;
						}

						if ( yLine >= _R3.Top && yLine <= _R3.Bottom )
						{
							if ( ! _R3TopSet ) { _R3TopSet = true; _R3Top = yLine; }
							_R3Bottom = yLine;
							z = true;
						}

						if ( z ) list.Add( yLine );
					}
				}
				else
				{
					float yLine = 0;

					yLine = _Bounds.Top - ( 2 * period );
					yLine += _YValue % period;
					yLine -= _Bounds.Height % period;
					for ( ; yLine < _Bounds.Bottom + ( 2 * period ) ; yLine += period )
						if ( yLine >= _R1.Top && yLine <= _R1.Bottom )
						{
							if ( ! _R1TopSet ) { _R1TopSet = true; _R1Top = yLine; }
							_R1Bottom = yLine;
							list.Add( yLine );
						}

					yLine = _Bounds.Top - ( 2 * period );
					yLine += _YValue % period;
					for ( ; yLine < _Bounds.Bottom + ( 2 * period ) ; yLine += period )
						if ( yLine >= _R2.Top && yLine <= _R2.Bottom )
						{
							if ( ! _R2TopSet ) { _R2TopSet = true; _R2Top = yLine; }
							_R2Bottom = yLine;
							list.Add( yLine );
						}

					yLine = _Bounds.Top - ( 2 * period );
					yLine += _YValue % period;
					yLine += _Bounds.Height % period;
					for ( ; yLine < _Bounds.Bottom + ( 2 * period ) ; yLine += period )
						if ( yLine >= _R3.Top && yLine <= _R3.Bottom )
						{
							if ( ! _R3TopSet ) { _R3TopSet = true; _R3Top = yLine; }
							_R3Bottom = yLine;
							list.Add( yLine );
						}
				}

				return list;
			}
		}
	}


//-----------------------------------------------------------------------------
// PainterBlockBase

	public abstract class PainterBlockBase : PainterBase
	{
		private const           float _DefaultBlockPercent   = 50          ;
		private const           int   _DefaultBlockWidth     = 6           ;
		private const           bool  _DefaultBlockSmooth    = false       ;
		private const           bool  _DefaultBlockScroll    = true        ;
		private static readonly Color _DefaultBlockLineColor = Color.Empty ;
		private const           int   _DefaultBlockLineWidth = 2           ;

		private float _BlockPercent   = _DefaultBlockPercent   ;
		private int   _BlockWidth     = _DefaultBlockWidth     ;
		private bool  _BlockSmooth    = _DefaultBlockSmooth    ;
		private bool  _BlockScroll    = _DefaultBlockScroll    ;
		private Color _BlockLineColor = _DefaultBlockLineColor ;
		private int   _BlockLineWidth = _DefaultBlockLineWidth ;

		[ Category( "Blocks" ) ]
		[ DefaultValue( _DefaultBlockPercent ) ]
		[ Description( "The percentage of the control filled with blocks") ]
		public float BlockPercent
		{
			get { return _BlockPercent; }

			set
			{
				if ( value < 0 || value > 100 )
					throw new ArgumentException(
						"Value must be between 0 and 100" );

				_BlockPercent = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "Blocks" ) ]
		[ DefaultValue( _DefaultBlockWidth ) ]
		[ Description( "The width of each block") ]
		public int BlockWidth
		{
			get { return _BlockWidth; }
			
			set
			{
				_BlockWidth = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "Blocks" ) ]
		[ DefaultValue( _DefaultBlockSmooth ) ]
		[ Description( "Whether partial blocks are drawn") ]
		public bool BlockSmooth
		{
			get { return _BlockSmooth; }
			
			set
			{
				_BlockSmooth = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "Blocks" ) ]
		[ DefaultValue( _DefaultBlockScroll ) ]
		[ Description( "Whether the blocks move") ]
		public bool BlockScroll
		{
			get { return _BlockScroll; }
			
			set
			{
				_BlockScroll = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "Blocks" ) ]
//		[ DefaultValue( Color.Empty ) ]
		[ Description( "The Color used to draw the lines separating the blocks") ]
		public Color BlockLineColor
		{
			get { return _BlockLineColor; }

			set
			{
				_BlockLineColor = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "Blocks" ) ]
		[ DefaultValue( _DefaultBlockLineWidth ) ]
		[ Description( "The width of the lines separating the blocks") ]
		public int BlockLineWidth
		{
			get { return _BlockLineWidth; }

			set
			{
				_BlockLineWidth = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		protected PainterBlockBase() {}

		protected PainterBlockBase( BusyBar bar ) : base ( bar )
		{
			OnBarSet();
		}

		protected PainterBlockBase( PainterBlockBase o ) : base( o )
		{
//			OnBarSet();

			CopyThis( o );
		}

		public override void Copy( PainterBase o )
		{
			base.Copy( o );

			if ( ! ( o is PainterBlockBase ) ) Debug.Assert( false );
			else
				CopyThis( ( PainterBlockBase ) o );
		}

		private void CopyThis( PainterBlockBase o )
		{
			_BlockPercent    = o._BlockPercent    ;
			_BlockWidth      = o._BlockWidth      ;
			_BlockSmooth     = o._BlockSmooth     ;
			_BlockScroll     = o._BlockScroll     ;
			_BlockLineColor  = o._BlockLineColor  ;
			_BlockLineWidth  = o._BlockLineWidth  ;
		}

		protected override void OnBarSet()
		{
			base.OnBarSet();

			_BlockLineColor = Bar.BackColor;
		}

		protected override void SetDefaults( bool setBarDefaults )
		{
			base.SetDefaults( setBarDefaults );

			_BlockPercent   = _DefaultBlockPercent   ;
			_BlockWidth     = _DefaultBlockWidth     ;
			_BlockSmooth    = _DefaultBlockSmooth    ;
			_BlockScroll    = _DefaultBlockScroll    ;
			_BlockLineColor = _DefaultBlockLineColor ;
			_BlockLineWidth = _DefaultBlockLineWidth ;

			if ( Bar != null ) _BlockLineColor = Bar.BackColor;
		}

	}

//-----------------------------------------------------------------------------
// PainterXP

	[ ToolboxBitmap( typeof( ResFinder ), ResFinder.DefaultNamespace + ".Bitmaps.PainterXP.bmp" ) ]
	public class PainterXP : PainterBlockBase
	{
		public enum Presets
		{
			None,
			System,
		}

		private static readonly Color _DefaultColorDark  = Color.FromArgb( 131, 174, 119 );
		private static readonly Color _DefaultColorLight = Color.FromArgb( 195, 227, 186 );

		private Presets _Preset = Presets.None;

		private Color _ColorDark  = _DefaultColorDark  ;
		private Color _ColorLight = _DefaultColorLight ;

		private bool _Wrap = false;

		[ Category( "1.Presets" ) ]
		[ DefaultValue( Presets.None ) ]
		[ Description( "Preset settings") ]
		[ RefreshProperties( RefreshProperties.All ) ]
		[ DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden ) ]
		public Presets Preset
		{
			get { return _Preset; }
			
			set
			{
				_Preset = value;

				SetFromPreset( true );

				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "2.Colors" ) ]
//		[ DefaultValue( Color.Empty ) ]
		[ Description( "The Color used to draw the bar") ]
		public Color ColorDark
		{
			get { return _ColorDark; }

			set
			{
				_ColorDark = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "2.Colors" ) ]
//		[ DefaultValue( Color.Empty ) ]
		[ Description( "The Color used to draw the bar") ]
		public Color ColorLight
		{
			get { return _ColorLight; }

			set
			{
				_ColorLight = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		public PainterXP() {}

		public PainterXP( BusyBar bar ) : base ( bar )
		{
			OnBarSet();

			// Presets.None
			SetFromPreset( true );
		}

		public PainterXP( BusyBar bar, bool setBarDefaults ) : base ( bar  )
		{
			OnBarSet();

			// Presets.None
			SetFromPreset( setBarDefaults );
		}

		protected PainterXP( PainterXP o ) : base( o )
		{
//			OnBarSet();

			CopyThis( o );
		}

		public override void Copy( PainterBase o )
		{
			base.Copy( o );

			if ( ! ( o is PainterXP ) ) Debug.Assert( false );
			else
				CopyThis( ( PainterXP ) o );
		}

		private void CopyThis( PainterXP o )
		{
			_Preset          = o._Preset          ;

			_ColorDark       = o._ColorDark       ;
			_ColorLight      = o._ColorLight      ;

//			_Wrap            = o._Wrap            ;
		}

		public override IPainter CreateCopy()
		{
			return new PainterXP( this );
		}

		protected override void OnBarSet()
		{
			base.OnBarSet();

			if ( _ColorDark  == Color.Empty ) _ColorDark  = _DefaultColorDark  ;
			if ( _ColorLight == Color.Empty ) _ColorLight = _DefaultColorLight ;
		}

		public override void Reset()
		{
			base.Reset();

			_Wrap = Bar.WrapInitial;
		}

		protected override void SetDefaults( bool setBarDefaults )
		{
			base.SetDefaults( setBarDefaults );

			_ColorDark  = _DefaultColorDark  ;
			_ColorLight = _DefaultColorLight ;
		}

		private void SetFromPreset( bool setBarDefaults )
		{
			switch ( _Preset )
			{
			case Presets.None:

				SetDefaults( setBarDefaults );

				break;

			case Presets.System:

				SetDefaults( setBarDefaults );

				if ( Bar != null )
				{
					Bar.Pin = BusyBar.Pins.Start;
				}

				BlockScroll = false;

				break;

			default:
				Debug.Assert( false );
				break;
			}
		}

		public override void Paint( Graphics g, Region r )
		{
//			g.ResetClip();

			base.Paint( g, r );

			if ( ! Bar.DrawBar ) return;

			RectangleF bounds = r.GetBounds( g );
			float ratio = ( ( float ) Bar.Value ) / ( Bar.Maximum - Bar.Minimum );

			if ( ! Bar.Vertical )
			{
				float xOffset = bounds.Width * ratio;

				if ( ! BlockSmooth && Bar.Pin != BusyBar.Pins.None  )
				{
					int xPeriod = BlockWidth + BlockLineWidth;
					int xIntPeriods = ( int ) Math.Floor( bounds.Width / xPeriod );

					float xWholeWidth = ( 1 + xIntPeriods ) * xPeriod;
					float xFudge = xWholeWidth / bounds.Width;

					xOffset *= xFudge;
				}

				float xValue = bounds.Left + xOffset;

				float b = bounds.Width * BlockPercent / 100f;
				float xLeft = xValue - ( b / 2f );

				RectangleF r2 = RectangleF.Empty;
				RectangleF r1 = RectangleF.Empty;
				RectangleF r3 = RectangleF.Empty;

				switch ( Bar.Pin )
				{
				case BusyBar.Pins.None:
				{
					r2 = new RectangleF( xLeft , bounds.Top, b, bounds.Height );
					r1 = r2; r1.Offset( - bounds.Width, 0 );
					r3 = r2; r3.Offset( + bounds.Width, 0 );
					break;
				}

				case BusyBar.Pins.Start:
				{
					r2 = new RectangleF(
						bounds.Left,
						bounds.Top,
						xOffset,
						bounds.Height );

					break;
				}

				case BusyBar.Pins.End:
				{
					r2 = new RectangleF(
						xValue,
						bounds.Top,
						bounds.Width - xOffset,
						bounds.Height );

					break;
				}

				default:
					Debug.Assert( false );
					return;
				}

				if ( r1.Right < bounds.Left && r3.Left > bounds.Right ) _Wrap = Bar.Wrap;

				BlockLines blocks = new BlockLines();

				blocks.BlockWidth     = BlockWidth     ;
				blocks.BlockLineWidth = BlockLineWidth ;
				blocks.BlockScroll    = BlockScroll    ;
				blocks.Bounds         = bounds         ;
				blocks.R1             = r1             ;
				blocks.R2             = r2             ;
				blocks.R3             = r3             ;
				blocks.XValue         = xValue         ;

				ArrayList lines = blocks.HorizontalLines;

				if ( ! BlockSmooth )
				{
					r1.X = blocks.R1Left;
					r2.X = blocks.R2Left;
					r3.X = blocks.R3Left;

					r1.Width = blocks.R1Right - r1.Left;
					r2.Width = blocks.R2Right - r2.Left;
					r3.Width = blocks.R3Right - r3.Left;

					if ( Bar.Pin == BusyBar.Pins.Start && lines.Count > 0 )
					{
						r2.X -= BlockWidth + BlockLineWidth;
						r2.Width += BlockWidth + BlockLineWidth;
					}

					if ( Bar.Pin == BusyBar.Pins.End && lines.Count > 0 )
						r2.Width += BlockWidth + BlockLineWidth;
				}

				if ( r2.Width <= 0 || r2.Height <= 0 ) return;

//				g.DrawRectangle( pen, r2.X, r2.Y, r2.Width, r2.Height );

				Blend blend = new Blend( 5 );
				blend.Positions = new float[] { 0f, 0.2f, 0.3f, 0.8f,   1f };
				blend.Factors   = new float[] { 0f,   1f,   0f,   0f, 0.8f };

				ColorBlend colourBlend = new ColorBlend( 5 );
				colourBlend.Colors = new Color[] { _ColorDark, _ColorLight, _ColorDark, _ColorDark, _ColorLight };
				colourBlend.Positions = new float[] { 0f, 0.2f, 0.3f, 0.8f, 1f };

				using ( LinearGradientBrush brush = new LinearGradientBrush(
//							r2, Color.Empty, Color.Empty, LinearGradientMode.Vertical ) ) 
//							bounds, _ColorDark, _ColorLight, LinearGradientMode.Vertical ) ) 
							r2, _ColorDark, _ColorLight, LinearGradientMode.Vertical ) ) 
				{
					brush.Blend = blend;
//					brush.InterpolationColors = colourBlend;
					brush.GammaCorrection = true;
//					brush.WrapMode = WrapMode.Tile;

					bool bOther = _Wrap && ( Bar.Pin == BusyBar.Pins.None );

					if ( bOther ) g.FillRectangle( brush, r1 );
					if ( 1 == 1 ) g.FillRectangle( brush, r2 );
//					if ( 1 == 1 ) g.FillRectangle( Brushes.Red, r2 );
					if ( bOther ) g.FillRectangle( brush, r3 );
				}

				if ( BlockLineWidth > 0 )
					using ( Pen pen2 = new Pen( BlockLineColor, BlockLineWidth ) )
					{
						foreach ( float xLine in lines )
							g.DrawLine( pen2, xLine, bounds.Top, xLine, bounds.Bottom );
					}

//				g.DrawLine( Pens.Red, blocks.R1Left, bounds.Top, blocks.R1Left, bounds.Bottom );
//				g.DrawLine( Pens.Red, blocks.R1Right, bounds.Top, blocks.R1Right, bounds.Bottom );
//				g.DrawLine( Pens.Red, blocks.R2Left, bounds.Top, blocks.R2Left, bounds.Bottom );
//				g.DrawLine( Pens.Red, blocks.R2Right, bounds.Top, blocks.R2Right, bounds.Bottom );
//				g.DrawLine( Pens.Red, blocks.R3Left, bounds.Top, blocks.R3Left, bounds.Bottom );
//				g.DrawLine( Pens.Red, blocks.R3Right, bounds.Top, blocks.R3Right, bounds.Bottom );
			}
				// Vertical
			else 
			{
				float yOffset = bounds.Height * ratio;

				if ( ! BlockSmooth && Bar.Pin != BusyBar.Pins.None  )
				{
					int yPeriod = BlockWidth + BlockLineWidth;
					int yIntPeriods = ( int ) Math.Floor( bounds.Height / yPeriod );

					float yWholeHeight = ( 1 + yIntPeriods ) * yPeriod;
					float yFudge = yWholeHeight / bounds.Height;

					yOffset *= yFudge;
//					yOffset += yPeriod;
				}

				float yValue = bounds.Top + yOffset;

				float b = bounds.Height * BlockPercent / 100f;
				float yTop = yValue - ( b / 2f );

				RectangleF r2 = RectangleF.Empty;
				RectangleF r1 = RectangleF.Empty;
				RectangleF r3 = RectangleF.Empty;

				switch ( Bar.Pin )
				{
				case BusyBar.Pins.None:
				{
					r2 = new RectangleF( bounds.Left, yTop, bounds.Width, b );
					r1 = r2; r1.Offset( 0, - bounds.Height );
					r3 = r2; r3.Offset( 0, + bounds.Height );
					break;
				}

				case BusyBar.Pins.Start:
				{
					r2 = new RectangleF(
						bounds.Left,
						bounds.Top,
						bounds.Width,
						yOffset );

					break;
				}

				case BusyBar.Pins.End:
				{
					r2 = new RectangleF(
						bounds.Top,
						yValue,
						bounds.Width,
						bounds.Height - yOffset );

					break;
				}

				default:
					Debug.Assert( false );
					return;
				}

				if ( r1.Bottom < bounds.Top && r3.Top > bounds.Bottom ) _Wrap = Bar.Wrap;

				BlockLines blocks = new BlockLines();

				blocks.BlockWidth     = BlockWidth     ;
				blocks.BlockLineWidth = BlockLineWidth ;
				blocks.BlockScroll    = BlockScroll    ;
				blocks.Bounds         = bounds         ;
				blocks.R1             = r1             ;
				blocks.R2             = r2             ;
				blocks.R3             = r3             ;
				blocks.YValue         = yValue         ;

				ArrayList lines = blocks.VerticalLines;

				if ( ! BlockSmooth )
				{
					r1.Y = blocks.R1Top;
					r2.Y = blocks.R2Top;
					r3.Y = blocks.R3Top;

					r1.Height = blocks.R1Bottom - r1.Top;
					r2.Height = blocks.R2Bottom - r2.Top;
					r3.Height = blocks.R3Bottom - r3.Top;

					if ( Bar.Pin == BusyBar.Pins.Start && lines.Count > 0 )
					{
						r2.Y -= BlockWidth + BlockLineWidth;
						r2.Height += BlockWidth + BlockLineWidth;
					}

					if ( Bar.Pin == BusyBar.Pins.End && lines.Count > 0 )
						r2.Height += BlockWidth + BlockLineWidth;
				}

				if ( r2.Width <= 0 || r2.Height <= 0 ) return;

//				g.DrawRectangle( pen, r2.X, r2.Y, r2.Width, r2.Height );

				Blend blend = new Blend( 5 );
				blend.Positions = new float[] { 0f, 0.2f, 0.3f, 0.8f,   1f };
				blend.Factors   = new float[] { 0f,   1f,   0f,   0f, 0.8f };

				ColorBlend colourBlend = new ColorBlend( 5 );
				colourBlend.Colors = new Color[] { _ColorDark, _ColorLight, _ColorDark, _ColorDark, _ColorLight };
				colourBlend.Positions = new float[] { 0f, 0.2f, 0.3f, 0.8f, 1f };

				using ( LinearGradientBrush brush = new LinearGradientBrush(
//							r2, Color.Empty, Color.Empty, LinearGradientMode.Vertical ) ) 
//							bounds, _ColorDark, _ColorLight, LinearGradientMode.Vertical ) ) 
							r2, _ColorDark, _ColorLight, LinearGradientMode.Horizontal ) ) 
				{
					brush.Blend = blend;
//					brush.InterpolationColors = colourBlend;
					brush.GammaCorrection = true;
//					brush.WrapMode = WrapMode.Tile;

					bool bOther = _Wrap && ( Bar.Pin == BusyBar.Pins.None );

					if ( bOther ) g.FillRectangle( brush, r1 );
					if ( 1 == 1 ) g.FillRectangle( brush, r2 );
//					if ( 1 == 1 ) g.FillRectangle( Brushes.Red, r2 );
					if ( bOther ) g.FillRectangle( brush, r3 );
				}

				if ( BlockLineWidth > 0 )
					using ( Pen pen2 = new Pen( BlockLineColor, BlockLineWidth ) )
					{
						foreach ( float yLine in lines )
							g.DrawLine( pen2, bounds.Left, yLine, bounds.Right, yLine );
					}

//				g.DrawLine( Pens.Red, blocks.R1Left, bounds.Top, blocks.R1Left, bounds.Bottom );
//				g.DrawLine( Pens.Red, blocks.R1Right, bounds.Top, blocks.R1Right, bounds.Bottom );
//				g.DrawLine( Pens.Red, blocks.R2Left, bounds.Top, blocks.R2Left, bounds.Bottom );
//				g.DrawLine( Pens.Red, blocks.R2Right, bounds.Top, blocks.R2Right, bounds.Bottom );
//				g.DrawLine( Pens.Red, blocks.R3Left, bounds.Top, blocks.R3Left, bounds.Bottom );
//				g.DrawLine( Pens.Red, blocks.R3Right, bounds.Top, blocks.R3Right, bounds.Bottom );
			}
		}
	}

//-----------------------------------------------------------------------------
// PainterPathGradient

	[ ToolboxBitmap( typeof( ResFinder ), ResFinder.DefaultNamespace + ".Bitmaps.PainterPathGradient.bmp" ) ]
	public class PainterPathGradient : PainterBlockBase
	{
		public enum Presets
		{
			None,
			Kitt,
			Circle,
			Startup,
			Noise,
		}

		public enum Shapes
		{
			Rectangle,
			Diamond,
			Circle,
		}

		private const Shapes _DefaultShape = Shapes.Rectangle;

		private Presets _Preset = Presets.None;
		private Shapes _Shape = _DefaultShape;

		private Color _ColorCentre     = Color.Empty;
		private Color _ColorCorner     = Color.Empty;
		private Color _ColorVertical   = Color.Empty;
		private Color _ColorHorizontal = Color.Empty;

		private bool _Wrap = false;

		[ Category( "1.Presets" ) ]
		[ DefaultValue( Presets.None ) ]
		[ Description( "Preset settings") ]
		[ RefreshProperties( RefreshProperties.All ) ]
		[ DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden ) ]
		public Presets Preset
		{
			get { return _Preset; }
			
			set
			{
				_Preset = value;

				SetFromPreset( true );

				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "2.Shapes" ) ]
		[ DefaultValue( _DefaultShape ) ]
		[ Description( "The shape to draw") ]
		public Shapes Shape
		{
			get { return _Shape; }
			
			set
			{
				_Shape = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "3.Colors" ) ]
//		[ DefaultValue( Color.Empty ) ]
		[ Description( "The Color at the centre") ]
		public Color ColorCentre
		{
			get { return _ColorCentre; }
			
			set
			{
				_ColorCentre = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "3.Colors" ) ]
//		[ DefaultValue( Color.Empty ) ]
		[ Description( "The Color at the corners") ]
		public Color ColorCorner
		{
			get { return _ColorCorner; }
			
			set
			{
				_ColorCorner = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "3.Colors" ) ]
//		[ DefaultValue( Color.Empty ) ]
		[ Description( "The Color at the top and bottom") ]
		public Color ColorVertical
		{
			get { return _ColorVertical; }
			
			set
			{
				_ColorVertical = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "3.Colors" ) ]
//		[ DefaultValue( Color.Empty ) ]
		[ Description( "The Color at the left and right") ]
		public Color ColorHorizontal
		{
			get { return _ColorHorizontal; }
			
			set
			{
				_ColorHorizontal = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		public PainterPathGradient() {}

		public PainterPathGradient( BusyBar bar ) : base ( bar )
		{
			OnBarSet();

			// Presets.None
			SetFromPreset( true );
		}

		public PainterPathGradient( BusyBar bar, bool setBarDefaults ) : base ( bar )
		{
			OnBarSet();

			// Presets.None
			SetFromPreset( setBarDefaults );
		}

		protected PainterPathGradient( PainterPathGradient o ) : base( o )
		{
//			OnBarSet();

			CopyThis( o );
		}

		public override void Copy( PainterBase o )
		{
			base.Copy( o );

			if ( ! ( o is PainterPathGradient ) ) Debug.Assert( false );
			else
				CopyThis( ( PainterPathGradient ) o );
		}

		private void CopyThis( PainterPathGradient o )
		{
			_Preset           = o._Preset          ;

			_Shape            = o._Shape           ;

			_ColorCentre      = o._ColorCentre     ;
			_ColorCorner      = o._ColorCorner     ;
			_ColorVertical    = o._ColorVertical   ;
			_ColorHorizontal  = o._ColorHorizontal ;
								
//			_Wrap             = o._Wrap            ;
		}

		public override IPainter CreateCopy()
		{
			return new PainterPathGradient( this );
		}

		protected override void OnBarSet()
		{
			base.OnBarSet();

			if ( _ColorCentre     == Color.Empty ) _ColorCentre     = Bar.ForeColor;
			if ( _ColorCorner     == Color.Empty ) _ColorCorner     = Bar.BackColor;
			if ( _ColorHorizontal == Color.Empty ) _ColorHorizontal = Bar.BackColor;
			if ( _ColorVertical   == Color.Empty ) _ColorVertical   = Bar.BackColor;
		}

		public override void Reset()
		{
			base.Reset();

			_Wrap = Bar.WrapInitial;
		}

		protected override void SetDefaults( bool setBarDefaults )
		{
			base.SetDefaults( setBarDefaults );

			_Shape = _DefaultShape;

			_ColorCentre     = Color.Empty;
			_ColorCorner     = Color.Empty;
			_ColorHorizontal = Color.Empty;
			_ColorVertical   = Color.Empty;

			if ( Bar != null )
			{
				_ColorCentre     = Bar.ForeColor;
				_ColorCorner     = Bar.BackColor;
				_ColorHorizontal = Bar.BackColor;
				_ColorVertical   = Bar.BackColor;
			}
		}

		private void SetFromPreset( bool setBarDefaults )
		{
			switch ( _Preset )
			{
			case Presets.None:

				SetDefaults( setBarDefaults );

				break;

			case Presets.Kitt:

				SetDefaults( setBarDefaults );

				if ( Bar != null )
				{
					Bar.BackColor = Color.Black;

					Bar.Bounce = true;
					Bar.Wrap = false;
				}

				BlockPercent = 100;
				BlockSmooth = true;
				BlockScroll = false;
				BlockLineColor = Color.Black;
				BlockLineWidth = 2;

				_Shape = Shapes.Diamond;

				_ColorCentre = Color.Red;
				_ColorCorner = Color.Black;
				_ColorHorizontal = Color.Black;
				_ColorVertical = Color.Black;

				break;

			case Presets.Circle:

				SetDefaults( setBarDefaults );

				if ( Bar != null )
				{
					Bar.BackColor = Color.Black;

					Bar.Bounce = true;
					Bar.Wrap = false;
				}

				BlockPercent = 25;
				BlockSmooth = true;
				BlockLineWidth = 0;

				_Shape = Shapes.Circle;

				_ColorCentre = Color.Yellow;
				_ColorCorner = Color.Black;

				break;

			case Presets.Startup:

				SetDefaults( setBarDefaults );

				if ( Bar != null )
				{
//					Bar.BackColor = Color.White;
				}

				BlockPercent = 100;
				BlockSmooth = true;
				BlockLineWidth = 0;

				_Shape = Shapes.Rectangle;

				_ColorCentre = Color.RoyalBlue;
				_ColorCorner = Color.White;
				_ColorHorizontal = Color.White;
				_ColorVertical = Color.RoyalBlue;

				break;

			case Presets.Noise:

				SetDefaults( setBarDefaults );

				if ( Bar != null )
				{
					Bar.Value = 5;
					Bar.Maximum = 10;
				}

				BlockPercent = 80;
				BlockSmooth = true;
				BlockLineWidth = 0;

				_Shape = Shapes.Rectangle;

				_ColorCentre = Color.Silver;
				_ColorVertical = _ColorCentre;

				break;

			default:
				Debug.Assert( false );
				break;
			}
		}

		public override void Paint( Graphics g, Region r )
		{
			base.Paint( g, r );

			if ( ! Bar.DrawBar ) return;

			RectangleF bounds = r.GetBounds( g );
			float ratio = ( ( float ) Bar.Value ) / ( Bar.Maximum - Bar.Minimum );

			if ( ! Bar.Vertical )
			{
				float xOffset = bounds.Width * ratio;

				if ( ! BlockSmooth && Bar.Pin != BusyBar.Pins.None )
				{
					int xPeriod = BlockWidth + BlockLineWidth;
					int xIntPeriods = ( int ) Math.Floor( bounds.Width / xPeriod );

					float xWholeWidth = ( 1 + xIntPeriods ) * xPeriod;
					float xFudge = xWholeWidth / bounds.Width;

					xOffset *= xFudge;
				}

				float xValue = bounds.Left + xOffset;
				float b = bounds.Width * BlockPercent / 100f;
				float xLeft = xValue - ( b / 2 );
				float xRight = xValue + ( b / 2 );
				float yMiddle = bounds.Top + ( bounds.Height / 2 );

				RectangleF r2 = RectangleF.Empty;
				RectangleF r1 = RectangleF.Empty;
				RectangleF r3 = RectangleF.Empty;

				switch ( Bar.Pin )
				{
				case BusyBar.Pins.None:
				{
					r2 = new RectangleF( xLeft, bounds.Top, b, bounds.Height );
					r1 = r2; r1.Offset( - bounds.Width, 0 );
					r3 = r2; r3.Offset( + bounds.Width, 0 );
					break;
				}

				case BusyBar.Pins.Start:
				{
					r2 = new RectangleF(
						bounds.Left,
						bounds.Top,
						xOffset,
						bounds.Height );

					break;
				}

				case BusyBar.Pins.End:
				{
					r2 = new RectangleF(
						xValue,
						bounds.Top,
						bounds.Width - xOffset,
						bounds.Height );

					break;
				}

				default:
					Debug.Assert( false );
					return;
				}

				if ( r2.Width <= 0 || r2.Height <= 0 ) return;

				if ( r2.Left > bounds.Left ) _Wrap = Bar.Wrap;

				BlockLines blocks = new BlockLines();

				blocks.BlockWidth     = BlockWidth     ;
				blocks.BlockLineWidth = BlockLineWidth ;
				blocks.BlockScroll    = BlockScroll    ;
				blocks.Bounds         = bounds         ;
				blocks.R1             = r1             ;
				blocks.R2             = r2             ;
				blocks.R3             = r3             ;
				blocks.XValue         = xValue         ;

				ArrayList lines = blocks.HorizontalLines;

				if ( ! BlockSmooth )
				{
					r1.X = blocks.R1Left;
					r2.X = blocks.R2Left;
					r3.X = blocks.R3Left;

					r1.Width = blocks.R1Right - r1.Left;
					r2.Width = blocks.R2Right - r2.Left;
					r3.Width = blocks.R3Right - r3.Left;

					if ( Bar.Pin == BusyBar.Pins.Start && lines.Count > 0 )
					{
						r2.X -= BlockWidth + BlockLineWidth;
						r2.Width += BlockWidth + BlockLineWidth;
					}

					if ( Bar.Pin == BusyBar.Pins.End && lines.Count > 0 )
						r2.Width += BlockWidth + BlockLineWidth;
				}
					
				GraphicsPath path = null;
				Color[] colours = null;

				switch ( _Shape )
				{
				case Shapes.Rectangle:
				{
					PointF[] points = null;

					if ( Bar.Pin == BusyBar.Pins.None )
					{
						points = new PointF[]
						{
							new PointF( xLeft, bounds.Top ),
							new PointF( xValue, bounds.Top ),
							new PointF( xRight, bounds.Top ),
							new PointF( xRight, yMiddle ),
							new PointF( xRight, bounds.Bottom ),
							new PointF( xValue, bounds.Bottom ),
							new PointF( xLeft, bounds.Bottom ),
							new PointF( xLeft, yMiddle ),
						};
					}
					else
					{
						if ( r2.Width < 1 ) return;

						float xMiddle = ( r2.Left + r2.Right ) / 2;

						points = new PointF[]
						{
							new PointF( r2.Left, bounds.Top ),
							new PointF( xMiddle, bounds.Top ),
							new PointF( r2.Right, bounds.Top ),
							new PointF( r2.Right, yMiddle ),
							new PointF( r2.Right, bounds.Bottom ),
							new PointF( xMiddle, bounds.Bottom ),
							new PointF( r2.Left, bounds.Bottom ),
							new PointF( r2.Left, yMiddle ),
						};
					}

					path = new GraphicsPath();
					path.AddLines( points );
					path.CloseFigure();

					colours = new Color[]
					{
						_ColorCorner,
						_ColorVertical,
						_ColorCorner,
						_ColorHorizontal,
						_ColorCorner,
						_ColorVertical,
						_ColorCorner,
						_ColorHorizontal
					};

					break;
				}

				case Shapes.Diamond:
				{
					PointF[] points = null;

					if ( Bar.Pin == BusyBar.Pins.None )
					{
						points = new PointF[]
						{
							new PointF( xValue, bounds.Top ),
							new PointF( xRight, yMiddle ),
							new PointF( xValue, bounds.Bottom ),
							new PointF( xLeft, yMiddle ),
						};
					}
					else
					{
						if ( r2.Width < 1 ) return;

						float xMiddle = ( r2.Left + r2.Right ) / 2;

						points = new PointF[]
						{
							new PointF( xMiddle, bounds.Top ),
							new PointF( r2.Right, yMiddle ),
							new PointF( xMiddle, bounds.Bottom ),
							new PointF( r2.Left, yMiddle ),
						};
					}
					path = new GraphicsPath();
					path.AddLines( points );
					path.CloseFigure();

					colours = new Color[]
					{
						_ColorVertical,
						_ColorHorizontal,
						_ColorVertical,
						_ColorHorizontal
					};

					break;
				}

				case Shapes.Circle:
				{
					path = new GraphicsPath();

					if ( Bar.Pin == BusyBar.Pins.None )
					{
						path.AddEllipse( xLeft, bounds.Top, b, bounds.Height );
					}
					else
					{
						if ( r2.Width < 1 ) return;

						path.AddEllipse( r2.Left, bounds.Top, r2.Width, bounds.Height );
					}

					colours = new Color[]
					{
						_ColorCorner,
					};

					break;
				}

				default:
					Debug.Assert( false );
					return;
				}

				PathGradientBrush brush = new PathGradientBrush( path );
				brush.CenterColor = _ColorCentre;
				brush.SurroundColors = colours;

				bool bOther = _Wrap && ( Bar.Pin == BusyBar.Pins.None );

				if ( bOther )
				{
					brush.TranslateTransform( - bounds.Width, 0 );
					g.FillRectangle( brush, r1 );
					brush.ResetTransform();
				}

				g.FillRectangle( brush, r2 );

				if ( bOther )
				{
					brush.TranslateTransform( + bounds.Width, 0 );
					g.FillRectangle( brush, r3 );
					brush.ResetTransform();
				}

				if ( BlockLineWidth > 0 )
					using ( Pen pen2 = new Pen( BlockLineColor, BlockLineWidth ) )
					{
						foreach ( float xLine in lines )
							g.DrawLine( pen2, xLine, bounds.Top, xLine, bounds.Bottom );
					}
			}
				// Vertical
			else
			{
				float yOffset = bounds.Height * ratio;

				if ( ! BlockSmooth && Bar.Pin != BusyBar.Pins.None  )
				{
					int yPeriod = BlockWidth + BlockLineWidth;
					int yIntPeriods = ( int ) Math.Floor( bounds.Height / yPeriod );

					float yWholeWidth = ( 1 + yIntPeriods ) * yPeriod;
					float yFudge = yWholeWidth / bounds.Height;

					yOffset *= yFudge;
				}

				float yValue = bounds.Top + yOffset;
				float b = bounds.Height * BlockPercent / 100f;
				float yTop = yValue - ( b / 2 );
				float yBottom = yValue + ( b / 2 );
				float xMiddle = bounds.Left + ( bounds.Width / 2 );

				RectangleF r2 = RectangleF.Empty;
				RectangleF r1 = RectangleF.Empty;
				RectangleF r3 = RectangleF.Empty;

				switch ( Bar.Pin )
				{
				case BusyBar.Pins.None:
				{
					r2 = new RectangleF( bounds.Left, yTop, bounds.Width, b );
					r1 = r2; r1.Offset( 0, - bounds.Height );
					r3 = r2; r3.Offset( 0, + bounds.Height );
					break;
				}

				case BusyBar.Pins.Start:
				{
					r2 = new RectangleF(
						bounds.Left,
						bounds.Top,
						bounds.Width,
						yOffset );

					break;
				}

				case BusyBar.Pins.End:
				{
					r2 = new RectangleF(
						bounds.Left,
						yValue,
						bounds.Width,
						bounds.Height - yOffset );

					break;
				}

				default:
					Debug.Assert( false );
					return;
				}

				if ( r2.Width <= 0 || r2.Height <= 0 ) return;

				if ( r2.Top > bounds.Top ) _Wrap = Bar.Wrap;

				BlockLines blocks = new BlockLines();

				blocks.BlockWidth     = BlockWidth     ;
				blocks.BlockLineWidth = BlockLineWidth ;
				blocks.BlockScroll    = BlockScroll    ;
				blocks.Bounds         = bounds         ;
				blocks.R1             = r1             ;
				blocks.R2             = r2             ;
				blocks.R3             = r3             ;
				blocks.YValue         = yValue         ;

				ArrayList lines = blocks.VerticalLines;

				if ( ! BlockSmooth )
				{
					r1.Y = blocks.R1Top;
					r2.Y = blocks.R2Top;
					r3.Y = blocks.R3Top;

					r1.Height = blocks.R1Bottom - r1.Top;
					r2.Height = blocks.R2Bottom - r2.Top;
					r3.Height = blocks.R3Bottom - r3.Top;

					if ( Bar.Pin == BusyBar.Pins.Start && lines.Count > 0 )
					{
						r2.Y -= BlockWidth + BlockLineWidth;
						r2.Height += BlockWidth + BlockLineWidth;
					}

					if ( Bar.Pin == BusyBar.Pins.End && lines.Count > 0 )
						r2.Height += BlockWidth + BlockLineWidth;
				}
					
				GraphicsPath path = null;
				Color[] colours = null;

				switch ( _Shape )
				{
				case Shapes.Rectangle:
				{
					PointF[] points = null;

					if ( Bar.Pin == BusyBar.Pins.None )
					{
						points = new PointF[]
						{
							new PointF( bounds.Left, yTop ),
							new PointF( xMiddle, yTop ),
							new PointF( bounds.Right, yTop ),
							new PointF( bounds.Right, yValue ),
							new PointF( bounds.Right, yBottom ),
							new PointF( xMiddle, yBottom ),
							new PointF( bounds.Left, yBottom ),
							new PointF( bounds.Left, yValue ),
						};
					}
					else
					{
						if ( r2.Height < 1 ) return;

						float yMiddle = ( r2.Top + r2.Bottom ) / 2;

						points = new PointF[]
						{
							new PointF( bounds.Left, r2.Top ),
							new PointF( xMiddle, r2.Top ),
							new PointF( bounds.Right, r2.Top ),
							new PointF( bounds.Right, yMiddle ),
							new PointF( bounds.Right, r2.Bottom ),
							new PointF( xMiddle, r2.Bottom ),
							new PointF( bounds.Left, r2.Bottom ),
							new PointF( bounds.Left, yMiddle ),
						};
					}

					path = new GraphicsPath();
					path.AddLines( points );
					path.CloseFigure();

					colours = new Color[]
					{
						_ColorCorner,
						_ColorVertical,
						_ColorCorner,
						_ColorHorizontal,
						_ColorCorner,
						_ColorVertical,
						_ColorCorner,
						_ColorHorizontal
					};

					break;
				}

				case Shapes.Diamond:
				{
					PointF[] points = null;

					if ( Bar.Pin == BusyBar.Pins.None )
					{
						points = new PointF[]
						{
							new PointF( xMiddle, yTop ),
							new PointF( bounds.Right, yValue ),
							new PointF( xMiddle, yBottom ),
							new PointF( bounds.Left, yValue ),
						};
					}
					else
					{
						if ( r2.Height < 1 ) return;

						float yMiddle = ( r2.Top + r2.Bottom ) / 2;

						points = new PointF[]
						{
							new PointF( xMiddle, r2.Top ),
							new PointF( bounds.Right, yMiddle ),
							new PointF( xMiddle, r2.Bottom ),
							new PointF( bounds.Left, yMiddle ),
						};
					}

					path = new GraphicsPath();
					path.AddLines( points );
					path.CloseFigure();

					colours = new Color[]
					{
						_ColorVertical,
						_ColorHorizontal,
						_ColorVertical,
						_ColorHorizontal
					};

					break;
				}

				case Shapes.Circle:
				{
					path = new GraphicsPath();

					if ( Bar.Pin == BusyBar.Pins.None )
					{
						path.AddEllipse( bounds.Left, yTop, bounds.Width, b );
					}
					else
					{
						if ( r2.Height < 1 ) return;

						path.AddEllipse( bounds.Left, r2.Top, bounds.Width, r2.Height );
					}

					colours = new Color[]
					{
						_ColorCorner,
					};

					break;
				}

				default:
					Debug.Assert( false );
					return;
				}

				PathGradientBrush brush = new PathGradientBrush( path );
				brush.CenterColor = _ColorCentre;
				brush.SurroundColors = colours;

				bool bOther = _Wrap && ( Bar.Pin == BusyBar.Pins.None );

				if ( bOther )
				{
					brush.TranslateTransform( 0, - bounds.Height );
					g.FillRectangle( brush, r1 );
					brush.ResetTransform();
				}

				g.FillRectangle( brush, r2 );

				if ( bOther )
				{
					brush.TranslateTransform( 0, + bounds.Height );
					g.FillRectangle( brush, r3 );
					brush.ResetTransform();
				}

				if ( BlockLineWidth > 0 )
					using ( Pen pen2 = new Pen( BlockLineColor, BlockLineWidth ) )
					{
						foreach ( float yLine in lines )
							g.DrawLine( pen2, bounds.Left, yLine, bounds.Right, yLine );
					}
			}

		}

	}


//-----------------------------------------------------------------------------
// PainterClock

	[ ToolboxBitmap( typeof( ResFinder ), ResFinder.DefaultNamespace + ".Bitmaps.PainterClock.bmp" ) ]
	public class PainterClock : PainterBase
	{
		public enum Presets
		{
			None,
			Watch,
			Circle,
		}

		public enum HandTypes
		{
			Line,
			Pie,
		}

		private const int _DefaultHourLengthBegin   =  0;
		private const int _DefaultHourLengthEnd     = 50;
		private const int _DefaultHourWidth         =  3;

		private const int _DefaultMinuteLengthBegin =  0;
		private const int _DefaultMinuteLengthEnd   = 90;
		private const int _DefaultMinuteWidth       =  2;


		private Presets _Preset = Presets.None;

		private Color _MarksColor = Color.Empty;
		private int _MarksWidth = 1;

		private Color _HourColor = Color.Empty;
		private HandTypes _HourType = HandTypes.Line;
		private int _HourLengthBegin = _DefaultHourLengthBegin;
		private int _HourLengthEnd   = _DefaultHourLengthEnd  ;
		private int _HourWidth = _DefaultHourWidth;

		private Color _MinuteColor = Color.Empty;
		private HandTypes _MinuteType = HandTypes.Line;
		private int _MinuteLengthBegin = _DefaultMinuteLengthBegin;
		private int _MinuteLengthEnd   = _DefaultMinuteLengthEnd  ;
		private int _MinuteWidth = _DefaultMinuteWidth;
		private int _SpeedRatio = 4;

		[ Category( "1.Presets" ) ]
		[ DefaultValue( Presets.None ) ]
		[ Description( "Preset settings") ]
		[ RefreshProperties( RefreshProperties.All ) ]
		[ DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden ) ]
		public Presets Preset
		{
			get { return _Preset; }
			
			set
			{
				_Preset = value;

				SetFromPreset( true );

				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "2.Marks" ) ]
//		[ DefaultValue( Color.Empty ) ]
		[ Description( "The Color used to draw the marks") ]
		public Color MarksColor
		{
			get { return _MarksColor; }

			set
			{
				_MarksColor = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "2.Marks" ) ]
		[ DefaultValue( 1 ) ]
		[ Description( "The width of the marks lines") ]
		public int MarksWidth
		{
			get { return _MarksWidth; }

			set
			{
				_MarksWidth = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "3.Hour" ) ]
//		[ DefaultValue( Color.Empty ) ]
		[ Description( "The Color used to draw the hour hand") ]
		public Color HourColor
		{
			get { return _HourColor; }

			set
			{
				_HourColor = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "3.Hour" ) ]
		[ DefaultValue( HandTypes.Line ) ]
		[ Description( "The type of the hour hand") ]
		public HandTypes HourType
		{
			get { return _HourType; }
			
			set
			{
				_HourType = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "3.Hour" ) ]
		[ DefaultValue( _DefaultHourLengthBegin ) ]
		[ Description( "The begin length of the hour hand in percent of the radius") ]
		public int HourLengthBegin
		{
			get { return _HourLengthBegin; }
			
			set
			{
				_HourLengthBegin = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "3.Hour" ) ]
		[ DefaultValue( _DefaultHourLengthEnd ) ]
		[ Description( "The end length of the hour hand in percent of the radius") ]
		public int HourLengthEnd
		{
			get { return _HourLengthEnd; }
			
			set
			{
				_HourLengthEnd = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "3.Hour" ) ]
		[ DefaultValue( _DefaultHourWidth ) ]
		[ Description( "The width of the hour hand") ]
		public int HourWidth
		{
			get { return _HourWidth; }

			set
			{
				_HourWidth = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "4.Minute" ) ]
//		[ DefaultValue( Color.Empty ) ]
		[ Description( "The Color used to draw the minute hand") ]
		public Color MinuteColor
		{
			get { return _MinuteColor; }

			set
			{
				_MinuteColor = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "4.Minute" ) ]
		[ DefaultValue( HandTypes.Line ) ]
		[ Description( "The type of the minute hand") ]
		public HandTypes MinuteType
		{
			get { return _MinuteType; }
			
			set
			{
				_MinuteType = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "4.Minute" ) ]
		[ DefaultValue( _DefaultMinuteLengthBegin ) ]
		[ Description( "The begin length of the minute hand in percent of the radius") ]
		public int MinuteLengthBegin
		{
			get { return _MinuteLengthBegin; }
			
			set
			{
				_MinuteLengthBegin = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "4.Minute" ) ]
		[ DefaultValue( _DefaultMinuteLengthEnd ) ]
		[ Description( "The end length of the minute hand in percent of the radius") ]
		public int MinuteLengthEnd
		{
			get { return _MinuteLengthEnd; }
			
			set
			{
				_MinuteLengthEnd = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "4.Minute" ) ]
		[ DefaultValue( _DefaultMinuteWidth ) ]
		[ Description( "The width of the minute hand") ]
		public int MinuteWidth
		{
			get { return _MinuteWidth; }

			set
			{
				_MinuteWidth = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "4.Minute" ) ]
		[ DefaultValue( 4 ) ]
		[ Description( "The speed ratio of the minute hand") ]
		public int SpeedRatio
		{
			get { return _SpeedRatio; }
			
			set
			{
				_SpeedRatio = value;
				if ( Bar != null ) Bar.Invalidate();
			}
		}

		public PainterClock() {}

		public PainterClock( BusyBar bar ) : base ( bar )
		{
			OnBarSet();

			// Presets.None
			SetFromPreset( true );
		}

		public PainterClock( BusyBar bar, bool setBarDefaults ) : base ( bar )
		{
			OnBarSet();

			// Presets.None
			SetFromPreset( setBarDefaults );
		}

		protected PainterClock( PainterClock o ) : base( o )
		{
//			OnBarSet();

			CopyThis( o );
		}

		public override void Copy( PainterBase o )
		{
			base.Copy( o );

			if ( ! ( o is PainterClock ) ) Debug.Assert( false );
			else
				CopyThis( ( PainterClock ) o );
		}

		private void CopyThis( PainterClock o )
		{
			_Preset            = o._Preset            ;

			_MarksColor        = o._MarksColor        ;
			_MarksWidth        = o._MarksWidth        ;
								 
			_HourColor         = o._HourColor         ;
			_HourType          = o._HourType          ;
			_HourLengthBegin   = o._HourLengthBegin   ;
			_HourLengthEnd     = o._HourLengthEnd     ;
			_HourWidth         = o._HourWidth         ;
								 
			_MinuteColor       = o._MinuteColor       ;
			_MinuteType        = o._MinuteType        ;
			_MinuteLengthBegin = o._MinuteLengthBegin ;
			_MinuteLengthEnd   = o._MinuteLengthEnd   ;
			_MinuteWidth       = o._MinuteWidth       ;
			_SpeedRatio        = o._SpeedRatio        ;
		}

		public override IPainter CreateCopy()
		{
			return new PainterClock( this );
		}

		protected override void OnBarSet()
		{
			base.OnBarSet();

			if ( _MarksColor  == Color.Empty ) _MarksColor  = Bar.ForeColor;
			if ( _MinuteColor == Color.Empty ) _MinuteColor = Bar.ForeColor;
			if ( _HourColor   == Color.Empty ) _HourColor   = Bar.ForeColor;
		}

		public override void Reset()
		{
			base.Reset();
		}

		protected override void SetDefaults( bool setBarDefaults )
		{
			base.SetDefaults( setBarDefaults );

			_MarksColor = Color.Empty;
			_MarksWidth = 1;

			_HourColor       = Color.Empty;
			_HourType        = HandTypes.Line;
			_HourLengthBegin = _DefaultHourLengthBegin;
			_HourLengthEnd   = _DefaultHourLengthEnd;
			_HourWidth       = _DefaultHourWidth;

			_MinuteColor       = Color.Empty;
			_MinuteType        = HandTypes.Line;
			_MinuteLengthBegin = _DefaultMinuteLengthBegin;
			_MinuteLengthEnd   = _DefaultMinuteLengthEnd;
			_MinuteWidth       = _DefaultMinuteWidth;
			_SpeedRatio        = 4;

			if ( Bar != null )
			{
				_MarksColor  = Bar.ForeColor;
				_HourColor   = Bar.ForeColor;
				_MinuteColor = Bar.ForeColor;
			}
		}

		private void SetFromPreset( bool setBarDefaults )
		{
			switch ( _Preset )
			{
			case Presets.None:

				SetDefaults( setBarDefaults );

				break;

			case Presets.Watch:

				SetDefaults( setBarDefaults );

				if ( Bar != null )
				{
					Bar.CornerRadius = 70;
					Bar.Maximum = 400;
				}

				_MarksColor = Color.Orange;
				_MarksWidth = 10;

				_HourType = HandTypes.Pie;
				_HourLengthBegin = -20;
				_HourLengthEnd = 50;
				_HourColor = Color.Gold;
				_HourWidth = 20;

				_MinuteType = HandTypes.Pie;
				_MinuteLengthBegin = -10;
				_MinuteLengthEnd = 90;
				_MinuteColor = Color.Orange;
				_MinuteWidth = 10;

				_SpeedRatio = 12;

				break;

			case Presets.Circle:

				SetDefaults( setBarDefaults );

				if ( Bar != null )
				{
					Bar.CornerRadius = 100;
					Bar.Maximum = 400;
					Bar.Reverse = true;
				}

				_MarksColor = Color.Blue;
				_MarksWidth = 3;

				_HourType = HandTypes.Pie;
				_HourLengthBegin = -20;
				_HourLengthEnd = 40;
				_HourColor = Color.DarkBlue;
				_HourWidth = 20;

				_MinuteType = HandTypes.Pie;
				_MinuteLengthBegin = 30;
				_MinuteLengthEnd = 90;
				_MinuteColor = Color.Red;
				_MinuteWidth = 10;

				_SpeedRatio = 12;

				break;

			default:
				Debug.Assert( false );
				break;
			}
		}

		public override void Paint( Graphics g, Region r )
		{
			base.Paint( g, r );

			if ( ! Bar.DrawBar ) return;

			RectangleF bounds = r.GetBounds( g );
			float ratio = ( ( float ) Bar.Value ) / ( Bar.Maximum - Bar.Minimum );

			float minRadius = Single.MaxValue;
			using ( Pen penMarks = new Pen( _MarksColor, _MarksWidth ) )
				for ( int marks = 0 ; marks < 360 ; marks += 30 )
				{
//					float radius = CalcRadius( bounds, marks );
					float radius = CalcRadius( g, r, marks );

					if ( _MarksWidth > 0 )
						DrawLine( g, bounds, penMarks, marks, radius * 0.9f, radius );

					if ( radius < minRadius ) minRadius = radius;
				}

			if ( 1 == 1 )
			{
				float hour = ( ratio * 360 ) - 90;

				float begin = minRadius * _HourLengthBegin / 100;
				float end   = minRadius * _HourLengthEnd   / 100;

				switch ( _HourType )
				{
				case HandTypes.Line:
					using ( Pen penHour = new Pen( _HourColor, _HourWidth ) )
						DrawLine( g, bounds, penHour, hour, begin, end );
					break;

				case HandTypes.Pie:
					DrawPie( g, bounds, _HourColor, _HourWidth, hour, begin, end );
					break;

				default:
					Debug.Assert( false );
					break;
				}
			}

			if ( 1 == 1 )
			{
				float minute = ( _SpeedRatio * ratio * 360 ) - 90;

				float begin = minRadius * _MinuteLengthBegin / 100;
				float end   = minRadius * _MinuteLengthEnd   / 100;

				switch ( _MinuteType )
				{
				case HandTypes.Line:
					using ( Pen penMinute = new Pen( _MinuteColor, _MinuteWidth ) )
						DrawLine( g, bounds, penMinute, minute, begin, end );
					break;

				case HandTypes.Pie:
					DrawPie( g, bounds, _MinuteColor, _MinuteWidth, minute, begin, end );
					break;

				default:
					Debug.Assert( false );
					break;
				}
			}

		}

		private float CalcRadius( RectangleF r, float angle )
		{
			double radians = angle * Math.PI / 180;

			float a = ( float ) Math.Abs( Math.Cos( radians ) );
			float o = ( float ) Math.Abs( Math.Sin( radians ) );

			float r1 = ( a > 0 ) ? ( r.Width  / 2 ) / a : Single.MaxValue;
			float r2 = ( o > 0 ) ? ( r.Height / 2 ) / o : Single.MaxValue;

			return Math.Min( r1, r2 );
		}

		private float CalcRadius( Graphics g, Region region, float angle )
		{
			RectangleF bounds = region.GetBounds( g );
			float maxRadius = ( float ) Math.Sqrt( Math.Pow( bounds.Width / 2, 2 ) + Math.Pow( bounds.Height / 2, 2 ) );
			PointF centre = new PointF( ( bounds.Left + bounds.Right ) / 2, ( bounds.Top + bounds.Bottom ) / 2 );

			PointF point = centre;
			for ( float radius = 0 ; radius < maxRadius ; radius += 1 )
			{
				PointF p = CalcPointF( bounds, angle, radius );
				if ( ! region.IsVisible( p, g ) ) break;
				point = p;
			}

			float result = ( float ) Math.Sqrt( Math.Pow( point.X - centre.X, 2 ) + Math.Pow( point.Y - centre.Y, 2 ) );

			return result;
		}

		private PointF CalcPointF( RectangleF r, float angle, float radius )
		{
			double radians = angle * Math.PI / 180;

			float xOffset = ( float ) ( radius * Math.Cos( radians ) );
			float yOffset = ( float ) ( radius * Math.Sin( radians ) );

			float xMiddle = ( r.Left + r.Right  ) / 2;
			float yMiddle = ( r.Top  + r.Bottom ) / 2;

			return new PointF( xMiddle + xOffset, yMiddle + yOffset );
		}

		private void DrawLine( Graphics g, RectangleF r, Pen pen, float angle, float start, float end )
		{
			PointF s = CalcPointF( r, angle, start );
			PointF e = CalcPointF( r, angle, end   );

			g.DrawLine( pen, s, e );
		}

		private void DrawPie( Graphics g, RectangleF r, Color color, int sweep, float angle, float start, float end )
		{
			PointF pCentre = CalcPointF( r, angle, end );

			float radius = end - start;
			float diameter = 2 * radius;

			if ( radius <= 0 ) return;

			RectangleF e = new RectangleF( pCentre.X - radius, pCentre.Y - radius, diameter, diameter );

			float startAngle = angle - ( sweep / 2 ) - 180;

			using ( Brush brush = new SolidBrush( color ) )
				g.FillPie( brush, e.X, e.Y, e.Width, e.Height, startAngle, sweep );
		}

	}

//-----------------------------------------------------------------------------
//  PainterSillyscope

	[ ToolboxBitmap( typeof( ResFinder ), ResFinder.DefaultNamespace + ".Bitmaps.PainterSillyscope.bmp" ) ]
	public class PainterSillyscope : PainterBase
	{

		public enum Presets
		{
			None,
			Triangle,
			Square,
			Saw,
			Sine,
			Bezier,
			Circle,
			Heartbeat,
		}

		public enum Shapes
		{
			Line,
			Curve,
			Bezier,
		}


		private const bool _DefaultDrawGrid = true;
		private static readonly Color _DefaultGridLineColor = Color.Silver;
		private const int _DefaultGridLineWidth = 1;
		private const float _DefaultGridSpaceX = 20;
		private const float _DefaultGridSpaceY = 20;

		private static readonly Color _DefaultLineColor = Color.Empty;
		private const int _DefaultLineWidth = 2;

		private const Shapes _DefaultShape = Shapes.Line;

		// Must be 2D
		private static readonly PointF[] _DefaultPointsLine = new PointF[]
			{
				new PointF( 0, 1 ),
				new PointF( 1, 0 ),
				new PointF( 3, 2 ),
				new PointF( 4, 1 ),
			};

		// Must have >= 4 points
		private static readonly PointF[] _DefaultPointsCurve = new PointF[]
			{
				new PointF( 0, 1 ),
				new PointF( 1, 0 ),
				new PointF( 2, 1 ),
				new PointF( 3, 2 ),
				new PointF( 4, 1 ),
				new PointF( 5, 0 ),
				new PointF( 6, 1 ),
		};

		// Must have ( 1 + 3n ) points for Beziers
		private static readonly PointF[] _DefaultPointsBezier = new PointF[]
			{
				new PointF( 0, 1 ),
				new PointF( 0, 0 ),
				new PointF( 9, 2 ),
				new PointF( 9, 1 ),
			};

		private const int _DefaultTension = 50;

		private const int _DefaultHorizontalScale   = 25;
		private const int _DefaultVerticalScale     = 75;
		private const bool _DefaultWindowDraw = false;
		private const float _DefaultWindowScale = 50;



		private Presets _Preset = Presets.None;

		private bool _DrawGrid = _DefaultDrawGrid;
		private Color _GridLineColor = _DefaultGridLineColor;
		private int _GridLineWidth = _DefaultGridLineWidth;
		private float _GridSpaceX = _DefaultGridSpaceX;
		private float _GridSpaceY = _DefaultGridSpaceY;

		private Color _LineColor = _DefaultLineColor;
		private int _LineWidth = _DefaultLineWidth;

		private PointF[] _Points = _DefaultPointsLine;
		private Shapes _Shape = _DefaultShape;
		private int _Tension = _DefaultTension;

		private int _HorizontalScale = _DefaultHorizontalScale;
		private int _VerticalScale   = _DefaultVerticalScale;
		private bool _WindowDraw = _DefaultWindowDraw;
		private float _WindowScale = _DefaultWindowScale;

		[ Category( "1.Presets" ) ]
		[ DefaultValue( Presets.None ) ]
		[ Description( "Preset settings" ) ]
		[ RefreshProperties( RefreshProperties.All ) ]
		[ DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden ) ]
		public Presets Preset
		{
			get { return _Preset; }
			
			set
			{
				_Preset = value;

				SetFromPreset( true );

				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "5.Grid" ) ]
		[ DefaultValue( _DefaultDrawGrid ) ]
		[ Description( "Whether to draw a grid") ]
		public bool DrawGrid
		{
			get { return _DrawGrid; }
			
			set
			{
				_DrawGrid = value;

				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "5.Grid" ) ]
//		[ DefaultValue( _DefaultLineColor ) ]
		[ Description( "The Color used to draw the grid") ]
		public Color GridLineColor
		{
			get { return _GridLineColor; }
			
			set
			{
				_GridLineColor = value;

				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "5.Grid" ) ]
		[ DefaultValue( _DefaultGridLineWidth ) ]
		[ Description( "The width of the grid lines") ]
		public int GridLineWidth
		{
			get { return _GridLineWidth; }
			
			set
			{
				_GridLineWidth = value;

				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "5.Grid" ) ]
		[ DefaultValue( _DefaultGridSpaceX ) ]
		[ Description( "The horizontal space between the grid lines") ]
		public float GridSpaceX
		{
			get { return _GridSpaceX; }
			
			set
			{
				_GridSpaceX = value;

				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "5.Grid" ) ]
		[ DefaultValue( _DefaultGridSpaceX ) ]
		[ Description( "The vertical space between the grid lines") ]
		public float GridSpaceY
		{
			get { return _GridSpaceY; }
			
			set
			{
				_GridSpaceY = value;

				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "2.Line" ) ]
//		[ DefaultValue( _DefaultLineColor ) ]
		[ Description( "The Color used to draw the line") ]
		public Color LineColor
		{
			get { return _LineColor; }

			set
			{
				_LineColor = value;

				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "2.Line" ) ]
		[ DefaultValue( _DefaultLineWidth ) ]
		[ Description( "The width of the line") ]
		public int LineWidth
		{
			get { return _LineWidth; }

			set
			{
				_LineWidth = value;

				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "3.Shape" ) ]
//		[ DefaultValue( _DefaultShape ) ]
		[ Description( "The array of points defining the line" ) ]
		public PointF[] Points
		{
			get { return _Points; }
			
			set
			{
				// Checks for valid points
				GraphicsPath path = GetPath( _Shape, value );

				RectangleF r = path.GetBounds();

				if ( r.Width <= 0 || r.Height <= 0 )
					throw new ArgumentException( "Points must describe a 2D shape" );

				_Points = value;

				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "3.Shape" ) ]
		[ DefaultValue( _DefaultShape ) ]
		[ Description( "The shape of the line" ) ]
		public Shapes Shape
		{
			get { return _Shape; }

			set
			{
				switch ( value )
				{
				case Shapes.Line:

					if ( _Points.Length < 2 )
						_Points = _DefaultPointsLine;

					break;

				case Shapes.Curve:

					if ( _Points.Length < 4 )
						_Points = _DefaultPointsCurve;

					break;

				case Shapes.Bezier:

					if ( _Points.Length < 4 || _Points.Length % 3 != 1 )
						_Points = _DefaultPointsBezier;

					break;

				default:
					Debug.Assert( false );
					return;
				}

				// Checks for valid points
				GraphicsPath path = GetPath( value, _Points );

				_Shape = value;

				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "3.Shape" ) ]
		[ DefaultValue( _DefaultTension ) ]
		[ Description( "The tension of the line. Only used for curve shape" ) ]
		public int Tension
		{
			get { return _Tension; }
			
			set
			{
				if ( value < 0 || value > 100 )
					throw new ArgumentException(
						"Tension must be between 0 and 100" );

				_Tension = value;

				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "4.Scale" ) ]
		[ DefaultValue( _DefaultHorizontalScale ) ]
		[ Description( "The horizontal scale of the line as a percentage of the control width" ) ]
		public int HorizontalScale
		{
			get { return _HorizontalScale; }
			
			set
			{
				_HorizontalScale = value;

				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "4.Scale" ) ]
		[ DefaultValue( _DefaultVerticalScale ) ]
		[ Description( "The vertical scale of the line as a percentage of the control height" ) ]
		public int VerticalScale
		{
			get { return _VerticalScale  ; }
			
			set
			{
				_VerticalScale = value;

				if ( Bar != null ) Bar.Invalidate();
			}
		}


		[ Category( "4.Scale" ) ]
		[ DefaultValue( _DefaultWindowDraw ) ]
		[ Description( "Whether to draw in a window" ) ]
		public bool WindowDraw
		{
			get { return _WindowDraw; }
			
			set
			{
				_WindowDraw = value;

				if ( Bar != null ) Bar.Invalidate();
			}
		}

		[ Category( "4.Scale" ) ]
		[ DefaultValue( _DefaultWindowScale ) ]
		[ Description( "The scale of the window as a percentage of the line extent" ) ]
		public float WindowScale
		{
			get { return _WindowScale; }
			
			set
			{
				_WindowScale = value;

				if ( Bar != null ) Bar.Invalidate();
			}
		}


		public PainterSillyscope() {}

		public PainterSillyscope( BusyBar bar ) : base ( bar )
		{
			OnBarSet();

			// Presets.None
			SetFromPreset( true );
		}

		public PainterSillyscope( BusyBar bar, bool setBarDefaults ) : base ( bar )
		{
			OnBarSet();

			// Presets.None
			SetFromPreset( setBarDefaults );
		}

		protected PainterSillyscope( PainterSillyscope o ) : base( o )
		{
//			OnBarSet();

			CopyThis( o );
		}

		public override void Copy( PainterBase o )
		{
			base.Copy( o );

			if ( ! ( o is PainterSillyscope ) ) Debug.Assert( false );
			else
				CopyThis( ( PainterSillyscope ) o );
		}

		private void CopyThis( PainterSillyscope o )
		{
			_Preset            = o._Preset            ;

			_DrawGrid          = o._DrawGrid          ;
			_GridLineColor     = o._GridLineColor     ;
			_GridLineWidth     = o._GridLineWidth     ;
			_GridSpaceX        = o._GridSpaceX        ;
			_GridSpaceY        = o._GridSpaceY        ;

			_LineColor         = o._LineColor         ;
			_LineWidth         = o._LineWidth         ;

			_Points            = o._Points            ;
			_Shape             = o._Shape             ;
			_Tension           = o._Tension           ;

			_HorizontalScale   = o._HorizontalScale   ;
			_VerticalScale     = o._VerticalScale     ;
			_WindowDraw        = o._WindowDraw        ;
			_WindowScale       = o._WindowScale       ;
		}

		public override IPainter CreateCopy()
		{
			return new PainterSillyscope( this );
		}

		protected override void OnBarSet()
		{
			base.OnBarSet();

			if ( _LineColor  == Color.Empty ) _LineColor  = Bar.ForeColor;
		}

		public override void Reset()
		{
			base.Reset();
		}

		protected override void SetDefaults( bool setBarDefaults )
		{
			base.SetDefaults( setBarDefaults );

			_DrawGrid = _DefaultDrawGrid;
			_GridLineColor = _DefaultGridLineColor;
			_GridLineWidth = _DefaultGridLineWidth;
			_GridSpaceX = _DefaultGridSpaceX;
			_GridSpaceY = _DefaultGridSpaceY;

			_LineColor = _DefaultLineColor;
			_LineWidth = _DefaultLineWidth;

			_Points = _DefaultPointsLine;
			_Shape = _DefaultShape;
			_Tension = _DefaultTension;

			_HorizontalScale = _DefaultHorizontalScale;
			_VerticalScale = _DefaultVerticalScale;
			_WindowDraw = _DefaultWindowDraw;
			_WindowScale = _DefaultWindowScale;

			if ( Bar != null )
			{
				_LineColor = Bar.ForeColor;
			}
		}

		private void SetFromPreset( bool setBarDefaults )
		{
			switch ( _Preset )
			{
			case Presets.None:

				SetDefaults( setBarDefaults );

				break;

			case Presets.Triangle:

				SetDefaults( setBarDefaults );

				if ( Bar != null )
				{
					Bar.BackColor = Color.Black;

					Bar.CornerRadius = 50;
				}

				_GridLineColor = Color.Goldenrod;

				_LineColor = Color.Lime;

				_Points = _DefaultPointsLine;

				_HorizontalScale = 50;

				break;

			case Presets.Square:

				SetDefaults( setBarDefaults );

				if ( Bar != null )
				{
					Bar.BackColor = Color.Black;

					Bar.CornerRadius = 50;
				}

				_GridLineColor = Color.Goldenrod;

				_LineColor = Color.Lime;

				_Points = new PointF[]
					{
						new PointF(  0 , 0 ),
						new PointF(  1 , 0 ),
						new PointF(  1 , 1 ),
						new PointF(  2 , 1 ),
						new PointF(  2 , 0 ),
					};

				_HorizontalScale = 50;

				break;

			case Presets.Saw:

				SetDefaults( setBarDefaults );

				if ( Bar != null )
				{
					Bar.BackColor = Color.Black;

					Bar.CornerRadius = 50;
				}

				_GridLineColor = Color.Goldenrod;

				_LineColor = Color.Lime;

				_Points = new PointF[]
					{
						new PointF(  0 , 1 ),
						new PointF(  3 , 0 ),
						new PointF(  3 , 1 ),
					};

				_HorizontalScale = 50;

				break;

			case Presets.Sine:

				SetDefaults( setBarDefaults );

				if ( Bar != null )
				{
					Bar.BackColor = Color.Black;

					Bar.CornerRadius = 50;
				}

				_GridLineColor = Color.Goldenrod;

				_LineColor = Color.Lime;

				_Points = new PointF[]
					{
						new PointF( -1 ,  0.7f ),
						new PointF(  0 ,  0.0f ),
						new PointF(  1 , -0.7f ),
						new PointF(  2 , -1.0f ),
						new PointF(  3 , -0.7f ),
						new PointF(  4 ,  0.0f ),
						new PointF(  5 ,  0.7f ),
						new PointF(  6 ,  1.0f ),
						new PointF(  7 ,  0.7f ),
						new PointF(  8 ,  0.0f ),
						new PointF(  9 , -0.7f ),
					};

				_Shape = Shapes.Curve;

				_HorizontalScale = 50;

				break;

			case Presets.Bezier:

				SetDefaults( setBarDefaults );

				if ( Bar != null )
				{
					Bar.BackColor = Color.Black;

					Bar.CornerRadius = 50;
				}

				_GridLineColor = Color.Goldenrod;

				_LineColor = Color.Lime;

				_Points = _DefaultPointsBezier;
				_Shape = Shapes.Bezier;

				_HorizontalScale = 50;
				_VerticalScale = 200;

				break;

			case Presets.Circle:

				SetDefaults( setBarDefaults );

				if ( Bar != null )
				{
					Bar.BackColor = Color.Black;

					Bar.Bounce = true;
					Bar.Pin = BusyBar.Pins.Start;
				}

				_LineColor = Color.Lime;

				_Points = new PointF[]
					{
						new PointF( -1 ,  0 ),
						new PointF(  0 , -1 ),
						new PointF(  1 ,  0 ),
						new PointF(  0 ,  1 ),
						new PointF( -1 ,  0 ),
						new PointF(  0 , -1 ),
						new PointF(  1 ,  0 ),
					};

				_Shape = Shapes.Curve;
				_Tension = 80;

//				_HorizontalScale = 50;
				_VerticalScale = 50;
				_WindowDraw = true;

				break;

			case Presets.Heartbeat:

				SetDefaults( setBarDefaults );

				if ( Bar != null )
				{
					Bar.BackColor = Color.Black;

					Bar.Maximum = 200;
					Bar.Pin = BusyBar.Pins.Start;
				}

				_GridSpaceX = 25;
				_GridSpaceY = 16;

				_LineColor = Color.Lime;

				_Points = new PointF[]
					{
						new PointF( -1 ,  0 ),
						new PointF(  0 ,  0 ),
						new PointF(  5 ,  0 ),
						new PointF(  8 , -3 ),
						new PointF( 11 ,  1 ),
						new PointF( 14 ,  0 ),
						new PointF( 19 ,  0 ),
						new PointF( 20 ,  0 ),
					};

				_Shape = Shapes.Curve;

//				_HorizontalScale = 50;
				_WindowDraw = true;

				break;

			default:
				Debug.Assert( false );
				break;
			}
		}

		private GraphicsPath GraphicsPath
		{
			get
			{
				return GetPath( _Shape, _Points );
			}
		}

		private GraphicsPath GetPath( Shapes shape, PointF[] points )
		{
			GraphicsPath path = new GraphicsPath();

			switch ( shape )
			{
			case Shapes.Line:
				path.AddLines( points );
				break;

			case Shapes.Curve:
				path.AddCurve( points, 1, points.Length - 3, _Tension / 100f );
				break;

			case Shapes.Bezier:

				if ( points.Length < 4 || points.Length % 3 != 1 )
					throw new ArgumentException( "For Beziers, the points array must include the starting point, and three extra points for each segment" );
				
				path.AddBeziers( points );

				break;

			default:
				Debug.Assert( false );
				break;
			}

			return path;
		}

		public override void Paint( Graphics g, Region r )
		{
			base.Paint( g, r );

			if ( ! Bar.DrawBar ) return;

			if ( _Points.Length <= 0 ) return;

//			g.ResetClip();

			// Grid
			if ( _DrawGrid )
				BusyBarGrid.Draw(
					g,
					_GridLineColor,
					_GridLineWidth,
					_GridSpaceX,
					_GridSpaceY );

			// Init
			RectangleF bounds = r.GetBounds( g );
			float ratio = ( ( float ) Bar.Value ) / ( Bar.Maximum - Bar.Minimum );

			GraphicsPath path = GraphicsPath;

			// Rotate
			if ( Bar.Vertical )
			{
				Matrix rotate = new Matrix();
				rotate.Rotate( 90, MatrixOrder.Append );
				path.Transform( rotate );
			}

			// Client metrics
			RectangleF rectClient = r.GetBounds( g );
			SizeF sizeClient = rectClient.Size;
			float xClientMiddle = rectClient.Left + ( sizeClient.Width / 2f );
			float yClientMiddle = rectClient.Top + ( sizeClient.Height / 2f );

			// Path metrics
			RectangleF rectPath = path.GetBounds();
			SizeF sizePath = rectPath.Size;

			if ( sizePath.Width <= 0 || sizePath.Height <= 0 ) return;

			// Normalise
			if ( 1 == 1 )
			{
				float xScale = 0;
				float yScale = 0;

				if ( ! Bar.Vertical )
				{
					xScale = sizeClient.Width / sizePath.Width * _HorizontalScale / 100f;
					yScale = sizeClient.Height / sizePath.Height * _VerticalScale / 100f;
				}
				else
				{
					xScale = sizeClient.Width / sizePath.Width * _VerticalScale / 100f;
					yScale = sizeClient.Height / sizePath.Height * _HorizontalScale / 100f;
				}

				Matrix matrixNormalise = new Matrix();
				matrixNormalise.Translate( - rectPath.Left, - rectPath.Top, MatrixOrder.Append );
				matrixNormalise.Scale( xScale, yScale, MatrixOrder.Append );
				path.Transform( matrixNormalise );
			}

			// Normalised metrics
			RectangleF rectNormalisedPath = path.GetBounds();
			SizeF sizeNormalisedPath = rectNormalisedPath.Size;
			float xPeriod = sizeNormalisedPath.Width;
			float yPeriod = sizeNormalisedPath.Height;
			float xNormalisedPathMiddle = rectNormalisedPath.Left + ( sizeNormalisedPath.Width / 2f );
			float yNormalisedPathMiddle = rectNormalisedPath.Top + ( sizeNormalisedPath.Height / 2f );

			if ( ! Bar.Vertical )
			{
				// Translate to ClientRectangle
				if ( 1 == 1 )
				{
					float xClientOffset = rectClient.Left;
					float yClientOffset = yClientMiddle - yNormalisedPathMiddle;

					Matrix moveClient = new Matrix();
					moveClient.Translate( xClientOffset, yClientOffset, MatrixOrder.Append );
					path.Transform( moveClient );
				}

				// Whole periods
				int xIntPeriods = ( int ) Math.Floor( bounds.Width / xPeriod );

				// Offset
				if ( Bar.Pin == BusyBar.Pins.None )
				{
					float xWholeWidth = xIntPeriods * xPeriod;
					float xFudge = xWholeWidth / bounds.Width;

					float xOffset = ( bounds.Width * ratio );
					xOffset *= xFudge;
					xOffset %= xPeriod;
					xOffset -= xPeriod;

					Matrix moveOffset = new Matrix();
					moveOffset.Translate( xOffset, 0, MatrixOrder.Append );
					path.Transform( moveOffset );
				}

				// Clip
				Region regionWindow = null;

				if ( ! _WindowDraw )
				{
					switch ( Bar.Pin )
					{
					case BusyBar.Pins.None:
						break;

					case BusyBar.Pins.Start:
					{
						float xOffset = ( bounds.Width * ratio );

						RectangleF rectWindow = new RectangleF(
							bounds.Left,
							bounds.Top,
							xOffset,
							bounds.Height );

						regionWindow = new Region( rectWindow );

						break;
					}

					case BusyBar.Pins.End:
					{
						float xOffset = ( bounds.Width * ratio );

						RectangleF rectWindow = new RectangleF(
							bounds.Left + xOffset,
							bounds.Top,
							bounds.Width - xOffset,
							bounds.Height );

						regionWindow = new Region( rectWindow );

						break;
					}

					default:
						Debug.Assert( false );
						return;
					}
				}
					// _WindowDraw
				else
				{
					float xOffset = ( bounds.Width * ratio );
					float xWindowWidth = xPeriod * _WindowScale / 100f;
					float xHalfWindowWidth = xWindowWidth / 2f;

					RectangleF rectWindow = new RectangleF(
						xOffset - xHalfWindowWidth,
						bounds.Top,
						xWindowWidth,
						bounds.Height );

					regionWindow = new Region( rectWindow );
				}

				if ( regionWindow != null )
				{
					Region regionWindowClient = ( Region ) g.Clip.Clone();
					regionWindowClient.Intersect( regionWindow );
					g.Clip = regionWindowClient;
				}

				// Paint
				Matrix movePeriod = new Matrix();
				movePeriod.Translate( xPeriod, 0, MatrixOrder.Append );

				using ( Pen pen = new Pen( _LineColor, _LineWidth ) )
				{
					for ( int i = -1 ; i < xIntPeriods + 1 ; i++ )
					{
						g.DrawPath( pen, path );
						path.Transform( movePeriod );
					}
				}
			}
				// Vertical
			else
			{
				// Translate to ClientRectangle
				if ( 1 == 1 )
				{
					float xClientOffset = xClientMiddle - xNormalisedPathMiddle;
					float yClientOffset = rectClient.Top;

					Matrix moveClient = new Matrix();
					moveClient.Translate( xClientOffset, yClientOffset, MatrixOrder.Append );
					path.Transform( moveClient );
				}

				// Whole periods
				int yIntPeriods = ( int ) Math.Floor( bounds.Height / yPeriod );

				// Offset
				if ( Bar.Pin == BusyBar.Pins.None )
				{
					float yWholeWidth = yIntPeriods * yPeriod;
					float yFudge = yWholeWidth / bounds.Height;

					float yOffset = ( bounds.Height * ratio );
					yOffset *= yFudge;
					yOffset %= yPeriod;
					yOffset -= yPeriod;

					Matrix moveOffset = new Matrix();
					moveOffset.Translate( 0, yOffset, MatrixOrder.Append );
					path.Transform( moveOffset );
				}

				// Clip
				Region regionWindow = null;

				if ( ! _WindowDraw )
				{
					switch ( Bar.Pin )
					{
					case BusyBar.Pins.None:
						break;

					case BusyBar.Pins.Start:
					{
						float yOffset = ( bounds.Height * ratio );

						RectangleF rectWindow = new RectangleF(
							bounds.Left,
							bounds.Top,
							bounds.Width,
							yOffset );

						regionWindow = new Region( rectWindow );

						break;
					}

					case BusyBar.Pins.End:
					{
						float yOffset = ( bounds.Height * ratio );

						RectangleF rectWindow = new RectangleF(
							bounds.Left,
							bounds.Top + yOffset,
							bounds.Width,
							bounds.Height - yOffset );

						regionWindow = new Region( rectWindow );

						break;
					}

					default:
						Debug.Assert( false );
						return;
					}
				}
					// _WindowDraw
				else
				{
					float yOffset = ( bounds.Height * ratio );
					float yWindowWidth = yPeriod * _WindowScale / 100f;
					float yHalfWindowWidth = yWindowWidth / 2f;

					RectangleF rectWindow = new RectangleF(
						bounds.Left,
						yOffset - yHalfWindowWidth,
						bounds.Width,
						yWindowWidth );

					regionWindow = new Region( rectWindow );
				}

				if ( regionWindow != null )
				{
					Region regionWindowClient = g.Clip;
					regionWindowClient.Intersect( regionWindow );
					g.Clip = regionWindowClient;
				}

				// Paint
				Matrix movePeriod = new Matrix();
				movePeriod.Translate( 0, yPeriod, MatrixOrder.Append );

				using ( Pen pen = new Pen( _LineColor, _LineWidth ) )
				{
					for ( int i = -1 ; i < yIntPeriods + 1 ; i++ )
					{
						g.DrawPath( pen, path );
						path.Transform( movePeriod );
					}
				}
			}
		}
	}

//-----------------------------------------------------------------------------

}

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
United Kingdom United Kingdom
I discovered C# and .NET 1.0 Beta 1 in late 2000 and loved them immediately.
I have been writing software professionally in C# ever since

In real life, I have spent 3 years travelling abroad,
I have held a UK Private Pilots Licence for 20 years,
and I am a PADI Divemaster.

I now live near idyllic Bournemouth in England.

I can work 'virtually' anywhere!

Comments and Discussions