// System.Windows.Forms.ToolBar.cs
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// Author:
//	Ravindra (rkumar@novell.com)
//	Mike Kestner <mkestner@novell.com>
//	Everaldo Canuto <ecanuto@novell.com>
//
// Copyright (C) 2004-2006  Novell, Inc. (http://www.novell.com)
//

using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Text;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace System.Windows.Forms
{
#if NET_2_0
	[ComVisible (true)]
	[ClassInterface (ClassInterfaceType.AutoDispatch)]
#endif
	[DefaultEvent ("ButtonClick")]
	[DefaultProperty ("Buttons")]
	[Designer ("System.Windows.Forms.Design.ToolBarDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
	public class ToolBar : Control
	{
		#region Instance Variables
		private bool size_specified = false;
		private ToolBarItem current_item;
		internal ToolBarItem[] items;
		internal Size default_size;
		#endregion Instance Variables

		#region Events
		static object ButtonClickEvent = new object ();
		static object ButtonDropDownEvent = new object ();

#if NET_2_0
		[Browsable (true)]
		[EditorBrowsable (EditorBrowsableState.Always)]
		public new event EventHandler AutoSizeChanged {
			add { base.AutoSizeChanged += value; }
			remove { base.AutoSizeChanged -= value; }
		}
#endif

		[Browsable (false)]
		[EditorBrowsable (EditorBrowsableState.Never)]
		public new event EventHandler BackColorChanged {
			add { base.BackColorChanged += value; }
			remove { base.BackColorChanged -= value; }
		}

		[Browsable (false)]
		[EditorBrowsable (EditorBrowsableState.Never)]
		public new event EventHandler BackgroundImageChanged {
			add { base.BackgroundImageChanged += value; }
			remove { base.BackgroundImageChanged -= value; }
		}

#if NET_2_0
		[Browsable (false)]
		[EditorBrowsable (EditorBrowsableState.Never)]
		public new event EventHandler BackgroundImageLayoutChanged {
			add { base.BackgroundImageLayoutChanged += value; }
			remove { base.BackgroundImageLayoutChanged -= value; }
		}
#endif

		public event ToolBarButtonClickEventHandler ButtonClick {
			add { Events.AddHandler (ButtonClickEvent, value); }
			remove {Events.RemoveHandler (ButtonClickEvent, value); }
		}

		public event ToolBarButtonClickEventHandler ButtonDropDown {
			add { Events.AddHandler (ButtonDropDownEvent, value); }
			remove {Events.RemoveHandler (ButtonDropDownEvent, value); }
		}

		[Browsable (false)]
		[EditorBrowsable (EditorBrowsableState.Never)]
		public new event EventHandler ForeColorChanged {
			add { base.ForeColorChanged += value; }
			remove { base.ForeColorChanged -= value; }
		}

		[Browsable (false)]
		[EditorBrowsable (EditorBrowsableState.Never)]
		public new event EventHandler ImeModeChanged {
			add { base.ImeModeChanged += value; }
			remove { base.ImeModeChanged -= value; }
		}

		[Browsable (false)]
		[EditorBrowsable (EditorBrowsableState.Never)]
		public new event PaintEventHandler Paint {
			add { base.Paint += value; }
			remove { base.Paint -= value; }
		}

		[Browsable (false)]
		[EditorBrowsable (EditorBrowsableState.Never)]
		public new event EventHandler RightToLeftChanged {
			add { base.RightToLeftChanged += value; }
			remove { base.RightToLeftChanged -= value; }
		}

		[Browsable (false)]
		[EditorBrowsable (EditorBrowsableState.Never)]
		public new event EventHandler TextChanged {
			add { base.TextChanged += value; }
			remove { base.TextChanged -= value; }
		}
		#endregion Events

		#region Constructor
		public ToolBar ()
		{
			background_color = ThemeEngine.Current.DefaultControlBackColor;
			foreground_color = ThemeEngine.Current.DefaultControlForeColor;
			buttons = new ToolBarButtonCollection (this);
			Dock = DockStyle.Top;
			
			GotFocus += new EventHandler (FocusChanged);
			LostFocus += new EventHandler (FocusChanged);
			MouseDown += new MouseEventHandler (ToolBar_MouseDown);
			MouseHover += new EventHandler (ToolBar_MouseHover);
			MouseLeave += new EventHandler (ToolBar_MouseLeave);
			MouseMove += new MouseEventHandler (ToolBar_MouseMove);
			MouseUp += new MouseEventHandler (ToolBar_MouseUp);
			BackgroundImageChanged += new EventHandler (ToolBar_BackgroundImageChanged);

			TabStop = false;
			
			SetStyle (ControlStyles.UserPaint, false);
			SetStyle (ControlStyles.FixedHeight, true);
			SetStyle (ControlStyles.FixedWidth, false);
		}
		#endregion Constructor

		#region protected Properties
		protected override CreateParams CreateParams {
			get { 
				CreateParams create_params = base.CreateParams;
				
				if (appearance == ToolBarAppearance.Flat) {
					create_params.Style |= (int) ToolBarStyles.TBSTYLE_FLAT;
				}
				
				return create_params;
			}
		}

		protected override ImeMode DefaultImeMode {
			get { return ImeMode.Disable; }
		}

		protected override Size DefaultSize {
			get { return ThemeEngine.Current.ToolBarDefaultSize; }
		}

#if NET_2_0
		[EditorBrowsable (EditorBrowsableState.Never)]
		protected override bool DoubleBuffered {
			get { return base.DoubleBuffered; }
			set { base.DoubleBuffered = value; }
		}
#endif
		#endregion

		ToolBarAppearance appearance = ToolBarAppearance.Normal;

		#region Public Properties
		[DefaultValue (ToolBarAppearance.Normal)]
		[Localizable (true)]
		public ToolBarAppearance Appearance {
			get { return appearance; }
			set {
				if (value == appearance)
					return;

				appearance = value;
				Redraw (true);
			}
		}

		bool autosize = true;

#if NET_2_0
		[Browsable (true)]
		[DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)]
		[EditorBrowsable (EditorBrowsableState.Always)]
#endif
		[DefaultValue (true)]
		[Localizable (true)]
		public 
#if NET_2_0
		override
#else
		new
#endif
		bool AutoSize {
			get { return autosize; }
			set {
				if (value == autosize)
					return;

				autosize = value;
				
				if (IsHandleCreated)
					Redraw (true);
			}
		}

		[Browsable (false)]
		[EditorBrowsable (EditorBrowsableState.Never)]
		public override Color BackColor {
			get { return background_color; }
			set {
				if (value == background_color)
					return;

				background_color = value;
				OnBackColorChanged (EventArgs.Empty);
				Redraw (false);
			}
		}

		[Browsable (false)]
		[EditorBrowsable (EditorBrowsableState.Never)]
		public override Image BackgroundImage {
			get { return base.BackgroundImage; }
			set { base.BackgroundImage = value; }
		}

#if NET_2_0
		[Browsable (false)]
		[EditorBrowsable (EditorBrowsableState.Never)]
		public override ImageLayout BackgroundImageLayout {
			get { return base.BackgroundImageLayout; }
			set { base.BackgroundImageLayout = value; }
		}
#endif

		[DefaultValue (BorderStyle.None)]
		[DispIdAttribute (-504)]
		public BorderStyle BorderStyle {
			get { return InternalBorderStyle; }
			set { InternalBorderStyle = value; }
		}

		ToolBarButtonCollection buttons;

		[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
		[Localizable (true)]
		[MergableProperty (false)]
		public ToolBarButtonCollection Buttons {
			get { return buttons; }
		}

		Size button_size;

		[Localizable (true)]
		[RefreshProperties (RefreshProperties.All)]
		public Size ButtonSize {
			get {
				if (!button_size.IsEmpty)
					return button_size; 
				
				if (buttons.Count == 0)
					return new Size (39, 36);
					
				Size result = CalcButtonSize ();
				if (result.IsEmpty)
					return new Size (24, 22);
				else
					return result;
			}
			set {
				size_specified = value != Size.Empty;
				if (button_size == value)
					return;

				button_size = value;
				Redraw (true);
			}
		}

		bool divider = true;

		[DefaultValue (true)]
		public bool Divider {
			get { return divider; }
			set {
				if (value == divider)
					return;

				divider = value;
				Redraw (false);
			}
		}

		[DefaultValue (DockStyle.Top)]
		[Localizable (true)]
		public override DockStyle Dock {
			get { return base.Dock; }
			set {
				if (base.Dock == value) {
					// Call base anyways so layout_type gets set correctly
					if (value != DockStyle.None)
						base.Dock = value;
					return;
				}
					
				if (Vertical) {
					SetStyle (ControlStyles.FixedWidth, AutoSize);
					SetStyle (ControlStyles.FixedHeight, false);
				} else {
					SetStyle (ControlStyles.FixedHeight, AutoSize);
					SetStyle (ControlStyles.FixedWidth, false);
				}
				
				LayoutToolBar ();
				
				base.Dock = value;
			}
		}

		bool drop_down_arrows = true;

		[DefaultValue (false)]
		[Localizable (true)]
		public bool DropDownArrows {
			get { return drop_down_arrows; }
			set {
				if (value == drop_down_arrows)
					return;

				drop_down_arrows = value;
				Redraw (true);
			}
		}

		[Browsable (false)]
		[EditorBrowsable (EditorBrowsableState.Never)]
		public override Color ForeColor {
			get { return foreground_color; }
			set {
				if (value == foreground_color)
					return;

				foreground_color = value;
				OnForeColorChanged (EventArgs.Empty);
				Redraw (false);
			}
		}

		ImageList image_list;

		[DefaultValue (null)]
		public ImageList ImageList {
			get { return image_list; }
			set { 
				if (image_list == value)
					return;
				image_list = value;
				Redraw (true);
			}
		}

		[Browsable (false)]
		[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
		[EditorBrowsable (EditorBrowsableState.Advanced)]
		public Size ImageSize {
			get {
				if (ImageList == null)
					return Size.Empty;

				return ImageList.ImageSize;
			}
		}

		// XXX this should probably go away and it should call
		// into Control.ImeMode instead.
		new ImeMode ime_mode = ImeMode.Disable;

		[Browsable (false)]
		[EditorBrowsable (EditorBrowsableState.Never)]
		public new ImeMode ImeMode {
			get { return ime_mode; }
			set {
				if (value == ime_mode)
					return;

				ime_mode = value;
				OnImeModeChanged (EventArgs.Empty);
			}
		}

		[Browsable (false)]
		[EditorBrowsable (EditorBrowsableState.Never)]
		public override RightToLeft RightToLeft {
			get { return base.RightToLeft; }
			set {
				if (value == base.RightToLeft)
					return;

				base.RightToLeft = value;
				OnRightToLeftChanged (EventArgs.Empty);
			}
		}

		// Default value is "false" but after make a test in .NET we get "true" result as default.  
		bool show_tooltips = true;

		[DefaultValue (false)]
		[Localizable (true)]
		public bool ShowToolTips {
			get { return show_tooltips; }
			set { show_tooltips = value; }
		}

		[DefaultValue (false)]
		public new bool TabStop {
			get { return base.TabStop; }
			set { base.TabStop = value; }
		}

		[Bindable (false)]
		[Browsable (false)]
		[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
		[EditorBrowsable (EditorBrowsableState.Never)]
		public override string Text {
			get { return base.Text; } 
			set {
				if (value == base.Text)
					return;

				base.Text = value;
				Redraw (true);
			}
		}

		ToolBarTextAlign text_alignment = ToolBarTextAlign.Underneath;

		[DefaultValue (ToolBarTextAlign.Underneath)]
		[Localizable (true)]
		public ToolBarTextAlign TextAlign {
			get { return text_alignment; }
			set {
				if (value == text_alignment)
					return;

				text_alignment = value;
				Redraw (true);
			}
		}

		bool wrappable = true;

		[DefaultValue (true)]
		[Localizable (true)]
		public bool Wrappable {
			get { return wrappable; }
			set {
				if (value == wrappable)
					return;

				wrappable = value;
				Redraw (true);
			}
		}
		#endregion Public Properties

		#region Public Methods
		public override string ToString ()
		{
			int count = this.Buttons.Count;

			if (count == 0)
				return string.Format ("System.Windows.Forms.ToolBar, Buttons.Count: 0");
			else
				return string.Format ("System.Windows.Forms.ToolBar, Buttons.Count: {0}, Buttons[0]: {1}",
						      count, this.Buttons [0].ToString ());
		}
		#endregion Public Methods

		#region Protected Methods
		protected override void CreateHandle ()
		{
			base.CreateHandle ();
			default_size = CalcButtonSize ();
			
			// In win32 the recalculate size only happens for not flat style
			if (appearance != ToolBarAppearance.Flat)
				Redraw (true);
		}

		protected override void Dispose (bool disposing)
		{
			if (disposing)
				ImageList = null;

			base.Dispose (disposing);
		}

		protected virtual void OnButtonClick (ToolBarButtonClickEventArgs e)
		{
			if (e.Button.Style == ToolBarButtonStyle.ToggleButton) {
				if (! e.Button.Pushed)
					e.Button.Pushed = true;
				else
					e.Button.Pushed = false;
			}
			
			current_item.Pressed = false;
			current_item.Invalidate ();
			
			ToolBarButtonClickEventHandler eh = (ToolBarButtonClickEventHandler)(Events [ButtonClickEvent]);
			if (eh != null)
				eh (this, e);
		}

		protected virtual void OnButtonDropDown (ToolBarButtonClickEventArgs e) 
		{
			ToolBarButtonClickEventHandler eh = (ToolBarButtonClickEventHandler)(Events [ButtonDropDownEvent]);
			if (eh != null)
				eh (this, e);

			if (e.Button.DropDownMenu == null)
				return;

			ToolBarItem item = current_item;

			Point loc = new Point (item.Rectangle.X + 1, item.Rectangle.Bottom + 1);
			((ContextMenu) e.Button.DropDownMenu).Show (this, loc);

			item.DDPressed = false;
			item.Hilight = false;
			item.Invalidate ();
		}

		protected override void OnFontChanged (EventArgs e)
		{
			base.OnFontChanged (e);
			Redraw (true);
		}

		protected override void OnHandleCreated (EventArgs e)
		{
			base.OnHandleCreated (e);
		}

		protected override void OnResize (EventArgs e)
		{
			base.OnResize (e);
			LayoutToolBar ();
		}

#if NET_2_0
		protected override void ScaleControl (SizeF factor, BoundsSpecified specified)
		{
			specified &= ~BoundsSpecified.Height;
			
			base.ScaleControl (factor, specified);
		}

		[EditorBrowsable (EditorBrowsableState.Never)]
		protected override void ScaleCore (float dx, float dy)
		{
			dy = 1.0f;
			
			base.ScaleCore (dx, dy);
		}
#endif

		private int requested_size = -1;

		protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
		{
			if (Vertical) {
				if (!AutoSize && (requested_size != width) && ((specified & BoundsSpecified.Width) != BoundsSpecified.None)) 
					requested_size = width;
			} else {
				if (!AutoSize && (requested_size != height) && ((specified & BoundsSpecified.Height) != BoundsSpecified.None)) 
					requested_size = height;
			}
			
			base.SetBoundsCore (x, y, width, height, specified);
		}

		protected override void WndProc (ref Message m)
		{
			base.WndProc (ref m);
		}

		internal override bool InternalPreProcessMessage (ref Message msg)
		{
			if (msg.Msg == (int)Msg.WM_KEYDOWN) {
				Keys key_data = (Keys)msg.WParam.ToInt32();
				if (HandleKeyDown (key_data))
					return true;
			} 
			return base.InternalPreProcessMessage (ref msg);
		}
			
		#endregion Protected Methods

		#region Private Methods
		private void FocusChanged (object sender, EventArgs args)
		{
			if (Appearance != ToolBarAppearance.Flat || Buttons.Count == 0)
				return;

			ToolBarItem prelit = null;
			foreach (ToolBarItem item in items) {
				if (item.Hilight) {
					prelit = item;
					break;
				}
			}

			if (Focused && prelit == null) {
				foreach (ToolBarItem item in items) {
					if (item.Button.Enabled) {
						item.Hilight = true;
						break;
					}
				}
			} else if (prelit != null) {
				prelit.Hilight = false;
			}
		}

		private bool HandleKeyDown (Keys key_data)
		{
			if (Appearance != ToolBarAppearance.Flat || Buttons.Count == 0)
				return false;

			switch (key_data) {
				case Keys.Left:
				case Keys.Up:
					HighlightButton (-1);
					return true;
				case Keys.Right:
				case Keys.Down:
					HighlightButton (1);
					return true;
				default:
					return false;
			}
		}

		void HighlightButton (int offset)
		{
			ArrayList enabled = new ArrayList ();
			int count = 0;
			int start = -1;
			ToolBarItem curr_item = null;
			foreach (ToolBarItem item in items) {
				if (item.Hilight) {
					start = count;
					curr_item = item;
				}

				if (item.Button.Enabled) {
					enabled.Add (item);
					count++;
				}
			}

			int next = (start + offset) % count;
			if (next < 0)
				next = count - 1;

			if (next == start)
				return;

			if (curr_item != null)
				curr_item.Hilight = false;
			(enabled [next] as ToolBarItem).Hilight = true;
		}

		private void ToolBar_BackgroundImageChanged (object sender, EventArgs args)
		{
			Redraw (false, true);
		}

		private void ToolBar_MouseDown (object sender, MouseEventArgs me)
		{
			if ((!Enabled) || ((me.Button & MouseButtons.Left) == 0))
				return;

			Point loc = new Point (me.X, me.Y);

			if (ItemAtPoint (loc) == null)
				return;
			
			// Hide tooltip when left mouse button 
			if ((tip_window != null) && (tip_window.Visible) && ((me.Button & MouseButtons.Left) == MouseButtons.Left)) {
				TipDownTimer.Stop ();
				tip_window.Hide (this);
			}
			
			// draw the pushed button
			foreach (ToolBarItem item in items) {
				if (item.Button.Enabled && item.Rectangle.Contains (loc)) {
					// Mark the DropDown rect as pressed.
					// We don't redraw the dropdown rect.
					if (item.Button.Style == ToolBarButtonStyle.DropDownButton) {
						Rectangle rect = item.Rectangle;
						if (DropDownArrows) {
							rect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
							rect.X = item.Rectangle.Right - rect.Width;
						}
						
						if (rect.Contains (loc)) {
							if (item.Button.DropDownMenu != null) {
								item.DDPressed = true;
								Invalidate (rect);
							}
							break;
						}
					}
					item.Pressed = true;
					item.Inside = true;
					item.Invalidate ();
					break;
				}
			}
		}

		private void ToolBar_MouseUp (object sender, MouseEventArgs me)
		{
			if ((!Enabled) || ((me.Button & MouseButtons.Left) == 0))
				return;

			Point loc = new Point (me.X, me.Y);

			// draw the normal button
			// Make a copy in case the list is modified during enumeration
			ArrayList items = new ArrayList (this.items);
			foreach (ToolBarItem item in items) {
				if (item.Button.Enabled && item.Rectangle.Contains (loc)) {
					if (item.Button.Style == ToolBarButtonStyle.DropDownButton) {
						Rectangle ddRect = item.Rectangle;
						ddRect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
						ddRect.X = item.Rectangle.Right - ddRect.Width;
						if (ddRect.Contains (loc)) {
							current_item = item;
							if (item.DDPressed)
								OnButtonDropDown (new ToolBarButtonClickEventArgs (item.Button));
							continue;
						}
					}
					// Fire a ButtonClick
					current_item = item;
					if ((item.Pressed) && ((me.Button & MouseButtons.Left) == MouseButtons.Left))
						OnButtonClick (new ToolBarButtonClickEventArgs (item.Button));
				} else if (item.Pressed) {
					item.Pressed = false;
					item.Invalidate ();
				}
			}
		}

		private ToolBarItem ItemAtPoint (Point pt)
		{
			foreach (ToolBarItem item in items)
				if (item.Rectangle.Contains (pt)) 
					return item;

			return null;
		}

		ToolTip tip_window = null;
		Timer tipdown_timer = null;

		private void PopDownTip (object o, EventArgs args)
		{
			tip_window.Hide (this);
		}

		private Timer TipDownTimer {
			get {
				if (tipdown_timer == null) {
					tipdown_timer = new Timer ();
					tipdown_timer.Enabled = false;
					tipdown_timer.Interval = 5000;
					tipdown_timer.Tick += new EventHandler (PopDownTip);
				}
				return tipdown_timer;
			}
		}

		private void ToolBar_MouseHover (object sender, EventArgs e)
		{
			if (Capture)
				return;

			if (tip_window == null)
				tip_window = new ToolTip ();

			ToolBarItem item = ItemAtPoint (PointToClient (Control.MousePosition));
			current_item = item;

			if (item == null || item.Button.ToolTipText.Length == 0)
				return;

			tip_window.Present (this, item.Button.ToolTipText);
			TipDownTimer.Start ();
		}

		private void ToolBar_MouseLeave (object sender, EventArgs e)
		{
			if (tipdown_timer != null)
				tipdown_timer.Dispose ();
			tipdown_timer = null;
			if (tip_window != null)
				tip_window.Dispose ();
			tip_window = null;

			if (!Enabled || current_item == null) 
				return;

			current_item.Hilight = false;
			current_item = null;
		}

		private void ToolBar_MouseMove (object sender, MouseEventArgs me)
		{
			if (!Enabled) 
				return;

			if (tip_window != null && tip_window.Visible) {
				TipDownTimer.Stop ();
				TipDownTimer.Start ();
			}

			Point loc = new Point (me.X, me.Y);

			if (Capture) {
				// If the button was pressed and we leave, release the 
				// button press and vice versa
				foreach (ToolBarItem item in items) {
					if (item.Pressed &&
					    (item.Inside != item.Rectangle.Contains (loc))) {
						item.Inside = item.Rectangle.Contains (loc);
						item.Hilight = false;
						break;
					}
				}
				return;
			} 

			if (current_item != null && current_item.Rectangle.Contains (loc)) {
				if (ThemeEngine.Current.ToolBarHasHotElementStyles (this)) {
					if (current_item.Hilight || (!ThemeEngine.Current.ToolBarHasHotCheckedElementStyles && current_item.Button.Pushed) || !current_item.Button.Enabled)
						return;
					current_item.Hilight = true;
				}
			} else {
				if (tip_window != null) {
					if (tip_window.Visible) {
						tip_window.Hide (this);
						TipDownTimer.Stop ();
					}
					current_item = ItemAtPoint (loc);
					if (current_item != null && current_item.Button.ToolTipText.Length > 0) {
						tip_window.Present (this, current_item.Button.ToolTipText);
						TipDownTimer.Start ();
					}
				}

				if (ThemeEngine.Current.ToolBarHasHotElementStyles (this)) {
					foreach (ToolBarItem item in items) {
						if (item.Rectangle.Contains (loc) && item.Button.Enabled) {
							current_item = item;
							if (current_item.Hilight || (!ThemeEngine.Current.ToolBarHasHotCheckedElementStyles && current_item.Button.Pushed))
								continue;
							current_item.Hilight = true;
						}
						else if (item.Hilight) {
							item.Hilight = false;
						}
					}
				}
			}
		}

		internal override void OnPaintInternal (PaintEventArgs pevent)
		{
			if (GetStyle (ControlStyles.UserPaint))
				return;
				
			ThemeEngine.Current.DrawToolBar (pevent.Graphics, pevent.ClipRectangle, this);
			
			// Toolbars do not raise OnPaint unless UserPaint is set
			pevent.Handled = true;
		}

		internal void Redraw (bool recalculate)
		{
			Redraw (recalculate, true);
		}

		internal void Redraw (bool recalculate, bool force)
		{
			bool invalidate = true;
			
			if (recalculate)
				invalidate = LayoutToolBar ();

			if (force || invalidate)
				Invalidate ();
		}

		internal bool SizeSpecified {
			get { return size_specified; }
		}
		
		internal bool Vertical {
			get { return (Dock == DockStyle.Left) || (Dock == DockStyle.Right); }
		}

		internal const int text_padding = 3;

		private Size CalcButtonSize ()
		{
			if (Buttons.Count == 0)
				return Size.Empty;

			string longest_text = Buttons [0].Text;
			for (int i = 1; i < Buttons.Count; i++) {
				if (Buttons[i].Text.Length > longest_text.Length)
					longest_text = Buttons[i].Text;
			}

			Size size = Size.Empty;
			if (longest_text != null && longest_text.Length > 0) {
				SizeF sz = TextRenderer.MeasureString (longest_text, Font);
				if (sz != SizeF.Empty)
					size = new Size ((int) Math.Ceiling (sz.Width) + 2 * text_padding, (int) Math.Ceiling (sz.Height));
			}

			Size img_size = ImageList == null ? new Size (16, 16) : ImageSize;

			Theme theme = ThemeEngine.Current;
			int imgWidth = img_size.Width + 2 * theme.ToolBarImageGripWidth; 
			int imgHeight = img_size.Height + 2 * theme.ToolBarImageGripWidth;

			if (text_alignment == ToolBarTextAlign.Right) {
				size.Width = imgWidth + size.Width;
				size.Height = (size.Height > imgHeight) ? size.Height : imgHeight;
			} else {
				size.Height = imgHeight + size.Height;
				size.Width = (size.Width > imgWidth) ? size.Width : imgWidth;
			}

			size.Width += theme.ToolBarImageGripWidth;
			size.Height += theme.ToolBarImageGripWidth;
			return size;
		}

		// Flat toolbars disregard specified sizes.  Normal toolbars grow the
		// button size to be at least large enough to show the image.
		private Size AdjustedButtonSize {
			get {
				Size size;

				if (default_size.IsEmpty || Appearance == ToolBarAppearance.Normal) 
					size = ButtonSize;
				else
					size = default_size;
				
				if (size_specified) {
					if (Appearance == ToolBarAppearance.Flat)
						size = CalcButtonSize ();
					else {
						int grip = ThemeEngine.Current.ToolBarImageGripWidth;
						if (size.Width < ImageSize.Width + 2 * grip )
							size.Width = ImageSize.Width + 2 * grip;
						if (size.Height < ImageSize.Height + 2 * grip)
							size.Height = ImageSize.Height + 2 * grip;
					}
				}
				return size;
			}
		}

		private bool LayoutToolBar ()
		{
			bool changed = false;
			Theme theme = ThemeEngine.Current;
			int x = theme.ToolBarGripWidth;
			int y = theme.ToolBarGripWidth;

			Size adjusted_size = AdjustedButtonSize;
			
			int calculated_size = (Vertical ? adjusted_size.Width : adjusted_size.Height) + theme.ToolBarGripWidth;
			
			int separator_index = -1;

			items = new ToolBarItem [buttons.Count];
			
			for (int i = 0; i < buttons.Count; i++) {
				ToolBarButton button = buttons [i];
				
				ToolBarItem item = new ToolBarItem (button);
				items [i] = item;

				if (!button.Visible)
					continue;

				if (size_specified && (button.Style != ToolBarButtonStyle.Separator))
					changed = item.Layout (adjusted_size);
				else
					changed = item.Layout (Vertical, calculated_size);
				
				bool is_separator = button.Style == ToolBarButtonStyle.Separator;
				
				if (Vertical) {
					if (y + item.Rectangle.Height < Height || is_separator || !Wrappable) {
						if (item.Location.X != x || item.Location.Y != y)
							changed = true;
						item.Location = new Point (x, y);
						y += item.Rectangle.Height;
						if (is_separator)
							separator_index = i;
					} else if (separator_index > 0) {
						i = separator_index;
						separator_index = -1;
						y = theme.ToolBarGripWidth;
						x += calculated_size; 
					} else {
						y = theme.ToolBarGripWidth;
						x += calculated_size; 
						if (item.Location.X != x || item.Location.Y != y)
							changed = true;
						item.Location = new Point (x, y);
						y += item.Rectangle.Height;
					}
				} else {
					if (x + item.Rectangle.Width < Width || is_separator || !Wrappable) {
						if (item.Location.X != x || item.Location.Y != y)
							changed = true;
						item.Location = new Point (x, y);
						x += item.Rectangle.Width;
						if (is_separator)
							separator_index = i;
					} else if (separator_index > 0) {
						i = separator_index;
						separator_index = -1;
						x = theme.ToolBarGripWidth;
						y += calculated_size; 
					} else {
						x = theme.ToolBarGripWidth;
						y += calculated_size; 
						if (item.Location.X != x || item.Location.Y != y)
							changed = true;
						item.Location = new Point (x, y);
						x += item.Rectangle.Width;
					}
				}
			}
			
			if (Parent == null)
				return changed;
			
			if (Wrappable)
				calculated_size += Vertical ? x : y;
			
			if (IsHandleCreated) {
				if (Vertical)
					Width = calculated_size;
				else
					Height = calculated_size; 
			}
			
			return changed;
		}
 		#endregion Private Methods

		#region subclass
		public class ToolBarButtonCollection : IList, ICollection, IEnumerable
		{
			#region instance variables
			private ArrayList list; // ToolBarButton list
			private ToolBar owner;  // ToolBar associated to Collection
			private bool redraw;    // Flag if needs to redraw after add/remove operations
			#endregion

			#region constructors
			public ToolBarButtonCollection (ToolBar owner)
			{
				this.list   = new ArrayList ();
				this.owner  = owner;
				this.redraw = true;
			}
			#endregion

			#region properties
			[Browsable (false)]
			public int Count {
				get { return list.Count; }
			}

			public bool IsReadOnly {
				get { return list.IsReadOnly; }
			}

			public virtual ToolBarButton this [int index] {
				get { return (ToolBarButton) list [index]; }
				set {
					value.SetParent (owner);
					list [index] = value;
					owner.Redraw (true);
				}
			}

#if NET_2_0
			public virtual ToolBarButton this[string key] {
				get {
					if (string.IsNullOrEmpty (key))
						return null;
						
					foreach (ToolBarButton b in list)
						if (string.Compare (b.Name, key, true) == 0)
							return b;
							
					return null;
				}
			}
#endif

			bool ICollection.IsSynchronized {
				get { return list.IsSynchronized; }
			}

			object ICollection.SyncRoot {
				get { return list.SyncRoot; }
			}

			bool IList.IsFixedSize {
				get { return list.IsFixedSize; }
			}

			object IList.this [int index] {
				get { return this [index]; }
				set {
					if (! (value is ToolBarButton))
						throw new ArgumentException("Not of type ToolBarButton", "value");
					this [index] = (ToolBarButton) value;
				}
			}
			#endregion

			#region methods
			public int Add (string text)
			{
				ToolBarButton button = new ToolBarButton (text);
				return this.Add (button);
			}

			public int Add (ToolBarButton button)
			{
				int result;
				button.SetParent (owner);
				result = list.Add (button);
				if (redraw)
					owner.Redraw (true);
				return result;
			}

			public void AddRange (ToolBarButton [] buttons)
			{
				try {
					redraw = false;
					foreach (ToolBarButton button in buttons)
						Add (button);
				}
				finally {
					redraw = true;
					owner.Redraw (true);
				}
			}

			public void Clear ()
			{
				list.Clear ();
				owner.Redraw (false);
			}

			public bool Contains (ToolBarButton button)
			{
				return list.Contains (button);
			}

#if NET_2_0
			public virtual bool ContainsKey (string key)
			{
				return !(this[key] == null);
			}
#endif

			public IEnumerator GetEnumerator ()
			{
				return list.GetEnumerator ();
			}

			void ICollection.CopyTo (Array dest, int index)
			{
				list.CopyTo (dest, index);
			}

			int IList.Add (object button)
			{
				if (! (button is ToolBarButton)) {
					throw new ArgumentException("Not of type ToolBarButton", "button");
				}

				return this.Add ((ToolBarButton) button);
			}

			bool IList.Contains (object button)
			{
				if (! (button is ToolBarButton)) {
					throw new ArgumentException("Not of type ToolBarButton", "button");
				}

				return this.Contains ((ToolBarButton) button);
			}

			int IList.IndexOf (object button)
			{
				if (! (button is ToolBarButton)) {
					throw new ArgumentException("Not of type ToolBarButton", "button");
				}

				return this.IndexOf ((ToolBarButton) button);
			}

			void IList.Insert (int index, object button)
			{
				if (! (button is ToolBarButton)) {
					throw new ArgumentException("Not of type ToolBarButton", "button");
				}

				this.Insert (index, (ToolBarButton) button);
			}

			void IList.Remove (object button)
			{
				if (! (button is ToolBarButton)) {
					throw new ArgumentException("Not of type ToolBarButton", "button");
				}

				this.Remove ((ToolBarButton) button);
			}

			public int IndexOf (ToolBarButton button)
			{
				return list.IndexOf (button);
			}

#if NET_2_0
			public virtual int IndexOfKey (string key)
			{
				return IndexOf (this[key]);
			}
#endif

			public void Insert (int index, ToolBarButton button)
			{
				list.Insert (index, button);
				owner.Redraw (true);
			}

			public void Remove (ToolBarButton button)
			{
				list.Remove (button);
				owner.Redraw (true);
			}

			public void RemoveAt (int index)
			{
				list.RemoveAt (index);
				owner.Redraw (true);
			}

#if NET_2_0
			public virtual void RemoveByKey (string key)
			{
				Remove (this[key]);
			}
#endif
			#endregion methods
		}
		
		#endregion subclass
	}
	
	
	// Because same button can be added to toolbar multiple times, we need to maintain
	// a list of button information for each positions. 
	internal class ToolBarItem : Component
	{
		#region Instance variables
		
		private ToolBar       toolbar;    // Parent toolbar
		private ToolBarButton button;     // Associated toolBar button 
		private Rectangle     bounds;     // Toolbar button bounds
		private Rectangle     image_rect; // Image button bounds
		private Rectangle     text_rect;  // Text button bounds

		private bool dd_pressed = false;  // to check for a mouse down on dropdown rect
		private bool inside     = false;  // to handle the mouse move event with mouse pressed
		private bool hilight    = false;  // to hilight buttons in flat style
		private bool pressed    = false;  // this is to check for mouse down on a button
		
		#endregion
		
		#region Constructors
		
		public ToolBarItem (ToolBarButton button)
		{
			this.toolbar = button.Parent;
			this.button  = button;
		}
		
		#endregion Constructors
	
		#region Properties

		public ToolBarButton Button {
			get { return this.button; }
		}
		
		public Rectangle Rectangle {
			get { 
				if (!button.Visible || toolbar == null)
					return Rectangle.Empty;

				if (button.Style == ToolBarButtonStyle.DropDownButton && toolbar.DropDownArrows) {
					Rectangle result = bounds;
					result.Width += ThemeEngine.Current.ToolBarDropDownWidth;
					return result;
				}
				 
				return bounds;
			}
			set { this.bounds = value; }
		}

		public Point Location {
			get { return bounds.Location; }
			set { bounds.Location = value; }
		}

		public Rectangle ImageRectangle {
			get {
				Rectangle result = image_rect;
				result.X += bounds.X;
				result.Y += bounds.Y;
				return result; 
			}
		}
		
		public Rectangle TextRectangle {
			get { 
				Rectangle result = text_rect;
				result.X += bounds.X;
				result.Y += bounds.Y;
				return result; 
			}
		}

		private Size TextSize {
			get {
				StringFormat text_format = new StringFormat ();
				text_format.HotkeyPrefix = HotkeyPrefix.Hide;

				SizeF sz = TextRenderer.MeasureString (button.Text, toolbar.Font, SizeF.Empty, text_format);
				if (sz == SizeF.Empty)
					return Size.Empty;
				return new Size ((int) Math.Ceiling (sz.Width) + 2 * ToolBar.text_padding, (int) Math.Ceiling (sz.Height));
			}
		}
		
		public bool Pressed {
			get { return (pressed && inside); }
			set { pressed = value; }
		}

		public bool DDPressed {
			get { return dd_pressed; }
			set { dd_pressed = value; }
		}

		public bool Inside {
			get { return inside; }
			set { inside = value; }
		}

		public bool Hilight {
			get { return hilight; }
			set {
				if (hilight == value)
					return;

				hilight = value;
				Invalidate ();
			}
		}	
		
		#endregion Properties

		#region Methods
		
		public Size CalculateSize ()
		{
			Theme theme = ThemeEngine.Current;

			int ht = toolbar.ButtonSize.Height + 2 * theme.ToolBarGripWidth;

			if (button.Style == ToolBarButtonStyle.Separator)
				return new Size (theme.ToolBarSeparatorWidth, ht);

			Size size;
			if (TextSize.IsEmpty && (button.Image == null))
				size = toolbar.default_size;
			else
				size = TextSize;
			
			Size image_size = (toolbar.ImageSize == Size.Empty) ? new Size (16, 16) : toolbar.ImageSize;

			int image_width = image_size.Width + 2 * theme.ToolBarImageGripWidth; 
			int image_height = image_size.Height + 2 * theme.ToolBarImageGripWidth; 

			if (toolbar.TextAlign == ToolBarTextAlign.Right) {
				size.Width =  image_width + size.Width;
				size.Height = (size.Height > image_height) ? size.Height : image_height;
			} else {
				size.Height = image_height + size.Height;
				size.Width = (size.Width > image_width) ? size.Width : image_width;
			}

			size.Width += theme.ToolBarGripWidth;
			size.Height += theme.ToolBarGripWidth;
			return size;
		}

		
		public bool Layout (bool vertical, int calculated_size)
		{
			if (toolbar == null || !button.Visible)
				return false;

			Size psize = toolbar.ButtonSize;
			Size size = psize;
			if ((!toolbar.SizeSpecified) || (button.Style == ToolBarButtonStyle.Separator)) {
				size = CalculateSize ();

				if (size.Width == 0 || size.Height == 0)
					size = psize;

				if (vertical)
					size.Width = calculated_size;
				else
					size.Height = calculated_size;
			}
			return Layout (size);
		}

		public bool Layout (Size size)
		{
			if (toolbar == null || !button.Visible)
				return false;

			bounds.Size = size;

			Size image_size = (toolbar.ImageSize == Size.Empty) ? new Size (16, 16) : toolbar.ImageSize;
			int grip = ThemeEngine.Current.ToolBarImageGripWidth;

			Rectangle new_image_rect, new_text_rect;
			
			if (toolbar.TextAlign == ToolBarTextAlign.Underneath) {
				new_image_rect = new Rectangle ((bounds.Size.Width - image_size.Width) / 2 - grip, 0, image_size.Width + 2 + grip, image_size.Height + 2 * grip);
				new_text_rect = new Rectangle (0, new_image_rect.Height, bounds.Size.Width, bounds.Size.Height - new_image_rect.Height - 2 * grip);
			} else {
				new_image_rect = new Rectangle (0, 0, image_size.Width + 2 * grip, image_size.Height + 2 * grip);
				new_text_rect = new Rectangle (new_image_rect.Width, 0, bounds.Size.Width - new_image_rect.Width, bounds.Size.Height - 2 * grip);
			}

			bool changed = false;

			if (new_image_rect != image_rect || new_text_rect != text_rect)
				changed = true;

			image_rect = new_image_rect;
			text_rect = new_text_rect;
			
			return changed;
		}
		
		public void Invalidate ()
		{
			if (toolbar != null)
				toolbar.Invalidate (Rectangle);
		}

		#endregion Methods
	}
}
