/*
 * ComboBox.cs - Implementation of the "System.Windows.Forms.ComboBox" class.
 *
 * Copyright (C) 2003  Neil Cawse.
 * Copyright (C) 2003  Southern Storm Software, Pty Ltd.
 * Copyright (C) 2003  Free Software Foundation, Inc.
 * 
 * Contributions from Simon Guindon
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

namespace System.Windows.Forms
{
	using System;
	using System.Collections;
	using System.ComponentModel;
	using System.Drawing;
	using System.Drawing.Design;
	using System.Text;

 
#if CONFIG_COMPONENT_MODEL || CONFIG_EXTENDED_DIAGNOSTICS
	[Designer("System.Windows.Forms.Design.ComboBoxDesigner, System.Design")]
	[DefaultProperty("Items")]
	[DefaultEvent("SelectedIndexChanged")] 
#endif
	public class ComboBox : ListControl
	{
		private DrawMode drawMode;
		private ComboBoxStyle dropDownStyle;
		private int dropDownWidth;
		private bool integralHeight;
		private int itemHeight;
		private ObjectCollection items;
		private int maxDropDownItems;
		private int preferredHeight = 0;
		private int selectedIndex;
		private bool sorted;
		private ButtonState buttonState;
		private TextBox textEntry;
		private PopupControl popup;
		private VScrollBar scrollbar;
		private bool droppedDown;
		private int updateCount;
		private int popupMouseItem;
		private int popupDrawWidth;
		private int actualItemHeight;
		private int[] itemHeights;
		private int totalItemHeight;
 	
		public ComboBox()
		{
			textEntry = new TextBox();
			BackColor = SystemColors.Window;
			BorderStyleInternal = BorderStyle.Fixed3D;
			dropDownStyle = ComboBoxStyle.DropDown;
			integralHeight = true;
			maxDropDownItems = 8;
			dropDownWidth = Width;
			updateCount = 0;
			itemHeight = FontHeight + 2;
			selectedIndex = -1;
			SetStyle(ControlStyles.ResizeRedraw, true);
			textEntry.BorderStyle = BorderStyle.None;
			textEntry.TabStop = false;
			textEntry.LostFocus += new EventHandler(textentry_LostFocus);
			textEntry.GotFocus += new EventHandler(textentry_GotFocus);
			this.Controls.Add(textEntry);
		
			popup = new PopupControl();
			popup.BorderStyleInternal = BorderStyle.FixedSingle;
			popup.BackColor = SystemColors.Window;
			popup.PopDown += new EventHandler(popup_PopDown);
			popup.Paint +=new PaintEventHandler(popup_Paint);
			popup.MouseDown+=new MouseEventHandler(popup_MouseDown);
			popup.MouseMove+=new MouseEventHandler(popup_MouseMove);
			popup.MouseUp+=new MouseEventHandler(popup_MouseUp);

			scrollbar = new VScrollBar();
			scrollbar.Dock = DockStyle.Right;
			scrollbar.BackColor = SystemColors.Control;
			scrollbar.ValueChanged+=new EventHandler(scrollbar_ValueChanged);
			popup.Controls.Add(scrollbar);
		}

		protected override Size DefaultSize
		{
			get
			{
				return new Size(121, PreferredHeight);
			}
		}

		protected override void OnPaint(PaintEventArgs e)
		{
			Draw(e.Graphics);
		}

		private void Draw(Graphics g)
		{
			// TODO: fix this
			// Fill in the piece between the textbox and the bottom
			// The textbox could autosize to a smaller size than we need, so we need to fill this in.
			using (Brush b = Enabled ? new SolidBrush(BackColor) : SystemBrushes.Control)
				g.FillRectangle(b, 0, ClientSize.Height - 2, ClientSize.Width, 2);
			DrawButton(g);
			if (DropDownStyle == ComboBoxStyle.DropDownList)
			{
				Rectangle bounds = new Rectangle(textEntry.Left + 1, textEntry.Top + 1, textEntry.Width - 1, textEntry.Height -1);
				if (Focused)
				{
					g.FillRectangle(SystemBrushes.Highlight, bounds);
					g.DrawString(Text, Font, SystemBrushes.HighlightText, bounds);
				}
				else
				{
					using (Brush back = new SolidBrush(BackColor), fore = new SolidBrush(ForeColor))
					{
						g.FillRectangle(back, bounds);
						g.DrawString(Text, Font, fore, bounds);
					}
				}
			}
		}

		private Size ButtonSize
		{
			get
			{
				return new Size(17, 17);
			}
		}

		private void DrawButton(Graphics g)
		{
			ControlPaint.DrawComboButton(g, ClientSize.Width - ButtonSize.Width, 0, ButtonSize.Width, ButtonSize.Height, buttonState);
		}

#if CONFIG_COMPONENT_MODEL || CONFIG_EXTENDED_DIAGNOSTICS
		[DefaultValue(DrawMode.Normal)]
#endif
#if CONFIG_COMPONENT_MODEL
		[RefreshProperties(RefreshProperties.Repaint)]
#endif
		public DrawMode DrawMode 
		{
			get
			{
				return drawMode;
			}
			set
			{
				drawMode = value;
				GetItemHeights();
				Invalidate();
			}
		}

#if CONFIG_COMPONENT_MODEL || CONFIG_EXTENDED_DIAGNOSTICS
		[DefaultValue(ComboBoxStyle.DropDown)]
#endif
#if CONFIG_COMPONENT_MODEL
		[RefreshProperties(RefreshProperties.Repaint)]
#endif
		public ComboBoxStyle DropDownStyle 
		{
			get
			{
				return dropDownStyle;
			}
			set
			{
				dropDownStyle = value;
				textEntry.Visible = (dropDownStyle != ComboBoxStyle.DropDownList);
				Invalidate();
				OnDropDownStyleChanged(EventArgs.Empty);
			}
		}

		public int DropDownWidth 
		{
			get
			{
				return dropDownWidth;
			}
			set 
			{
				if (value < 1)
					throw new ArgumentException();
				if (value < Width)
					dropDownWidth = Width;
				else
					dropDownWidth = value;
				Invalidate();
			}
		}

#if CONFIG_COMPONENT_MODEL || CONFIG_EXTENDED_DIAGNOSTICS
		[Browsable(false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
#endif
		public bool DroppedDown
		{
			get
			{
				return droppedDown;
			}
			set
			{
				if (value == droppedDown ||
						Items.Count == 0)
					return;
				droppedDown = value;
				if (value)
				{
					//TODO: not working
					textEntry.SelectAll();
					actualItemHeight = itemHeight;
					if (drawMode == DrawMode.Normal)
						actualItemHeight = Font.Height + 2;

					buttonState = ButtonState.Pushed;
					using (Graphics g = CreateGraphics())
						DrawButton(g);
					scrollbar.Maximum = Items.Count - 1;
					scrollbar.LargeChange = maxDropDownItems;
					scrollbar.Value = (selectedIndex==-1) ? 0 :  selectedIndex;
					if (Items.Count < MaxDropDownItems)
						popup.Height = Items.Count * actualItemHeight;
					else
						popup.Height = maxDropDownItems * actualItemHeight;
					popupMouseItem = selectedIndex;
					popup.Width = DropDownWidth;
					popupDrawWidth = popup.ClientSize.Width - scrollbar.Width;
					popup.Location = Parent.PointToScreen(new Point(Left, Bottom));
					popup.Visible = true;
				}
				else
				{
					buttonState = ButtonState.Normal;
					using (Graphics g = CreateGraphics())
						DrawButton(g);
					popup.Visible = false;
				}
			}
		}

		protected override void OnEnabledChanged(EventArgs e)
		{
			textEntry.Enabled = Enabled;
			if (Enabled)
				buttonState = ButtonState.Normal;
			else
			{
				buttonState = ButtonState.Inactive;
				//Text = "";
			}
			base.OnEnabledChanged(e);
		}

		public override bool Focused 
		{
			get
			{
				return base.Focused;
			}
		}

#if CONFIG_COMPONENT_MODEL || CONFIG_EXTENDED_DIAGNOSTICS
		[DefaultValue(true)]
#endif
#if CONFIG_COMPONENT_MODEL
		[Localizable(true)]
#endif
		public bool IntegralHeight 
		{
			get
			{
				return integralHeight;
			}
			set
			{
				integralHeight = value;
				Invalidate();
			}
		}

#if CONFIG_COMPONENT_MODEL
		[Localizable(true)]
#endif
		public int ItemHeight 
		{
			get
			{
				return itemHeight;
			}
			set
			{
				if (value == itemHeight)
					return;
				itemHeight = value;
				GetItemHeights();
				Invalidate();
			}
		}

		private void GetItemHeights()
		{
			if (this.DrawMode == DrawMode.OwnerDrawVariable)
			{
				itemHeights = new int[Items.Count];
				using (Graphics g = CreateGraphics())
				{
					for (int i = 0; i < Items.Count; i++)
					{
						MeasureItemEventArgs args = new MeasureItemEventArgs(g, i, itemHeight);
						this.OnMeasureItem(args);
						itemHeights[i] = args.ItemHeight;
						totalItemHeight += args.ItemHeight;
					}
				}
			}
			else
				itemHeights = null;
		}

#if (CONFIG_COMPONENT_MODEL || CONFIG_EXTENDED_DIAGNOSTICS) && CONFIG_COMPONENT_MODEL_DESIGN
		[Editor("System.Windows.Forms.Design.ListControlStringCollectionEditor, System.Design", typeof(UITypeEditor))]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
#endif
#if CONFIG_COMPONENT_MODEL
		[Localizable(true)]
#endif
		public ObjectCollection Items 
		{
			get
			{
				if (items == null)
					items = new ObjectCollection(this);
				return items;
			}
		}

#if CONFIG_COMPONENT_MODEL || CONFIG_EXTENDED_DIAGNOSTICS
		[DefaultValue(8)]
#endif
#if CONFIG_COMPONENT_MODEL
		[Localizable(true)]
#endif
		public int MaxDropDownItems 
		{
			get { return maxDropDownItems; }
			set { maxDropDownItems = value; }
		}

#if CONFIG_COMPONENT_MODEL || CONFIG_EXTENDED_DIAGNOSTICS
		[DefaultValue(0)]
#endif
#if CONFIG_COMPONENT_MODEL
		[Localizable(true)]
#endif
		public int MaxLength 
		{
			get
			{
				return textEntry.MaxLength;
			}
			set
			{
				textEntry.MaxLength = value;
			}
		}

#if CONFIG_COMPONENT_MODEL || CONFIG_EXTENDED_DIAGNOSTICS
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		[Browsable(false)]
#endif
		public int PreferredHeight 
		{
			get
			{
				if (preferredHeight == 0)
					preferredHeight = FontHeight + SystemInformation.BorderSize.Height * 4 + 3;
				return preferredHeight;
			}
		}

#if CONFIG_COMPONENT_MODEL || CONFIG_EXTENDED_DIAGNOSTICS
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		[Browsable(false)]
#endif
		public override int SelectedIndex 
		{
			get
			{
				return selectedIndex;
			}
			set
			{
				int count = 0;
				if (Items != null)
					count = Items.Count;
				if (value < -1 || value >= count)
					throw new ArgumentOutOfRangeException();
				selectedIndex = value;
				SetText();
				if (IsHandleCreated)
					base.OnTextChanged(EventArgs.Empty);
				OnSelectedItemChanged(EventArgs.Empty);
				base.OnSelectedIndexChanged(EventArgs.Empty);
			}
		}

		// When the selection changes, change the textbox text.
		private void SetText()
		{
			if (selectedIndex == -1)
				textEntry.Text = "";
			else
				textEntry.Text = GetItemText(Items[selectedIndex]);
		}

#if CONFIG_COMPONENT_MODEL || CONFIG_EXTENDED_DIAGNOSTICS
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		[Browsable(false)]
#endif
#if CONFIG_COMPONENT_MODEL
		[Bindable(true)]
#endif
		public object SelectedItem 
		{
			get
			{
				return Items[selectedIndex];
			}
			set
			{
				SelectedIndex = Items.IndexOf(value);
			}
		}

#if CONFIG_COMPONENT_MODEL || CONFIG_EXTENDED_DIAGNOSTICS
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		[Browsable(false)]
#endif
		public string SelectedText 
		{
			get
			{
				return textEntry.SelectedText;
			}
			set 
			{
				if (DropDownStyle == ComboBoxStyle.Simple)
					return;
				textEntry.SelectedText = value; 
			}
		}

#if CONFIG_COMPONENT_MODEL || CONFIG_EXTENDED_DIAGNOSTICS
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		[Browsable(false)]
#endif
		public int SelectionLength 
		{
			get
			{
				return textEntry.SelectionLength;
			}
			set
			{
				textEntry.SelectionLength = value;
			}
		}

#if CONFIG_COMPONENT_MODEL || CONFIG_EXTENDED_DIAGNOSTICS
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		[Browsable(false)]
#endif
		public int SelectionStart
		{
			get
			{
				return textEntry.SelectionStart;
			}
			set
			{
				textEntry.SelectionStart = value;
			}
		}

#if CONFIG_COMPONENT_MODEL || CONFIG_EXTENDED_DIAGNOSTICS
		[DefaultValue(false)]
#endif
		public bool Sorted 
		{
			get
			{
				return sorted;
			}
			set
			{
				if (sorted == value)
					return;
				sorted = value;
				Items.Sort();
				SelectedIndex = -1;
			}
		}

#if CONFIG_COMPONENT_MODEL
		[Localizable(true)]
		[Bindable(true)]
#endif
		public override string Text 
		{
			get
			{
				return textEntry.Text;
			}
			set
			{
				textEntry.Text = value;
				if (value == null)
				{
					SelectedIndex = -1;
					return; 
				}
				
				for (int i = 0; i < Items.Count; i++)
				{
					if (string.Compare(value, Items[i].ToString()) == 0)
					{
						SelectedIndex = i;
						return; 
					}

				}
			}
		}

		public void BeginUpdate()
		{
			updateCount++;
		}

		public void EndUpdate()
		{
			updateCount--;
			if (updateCount <= 0)
				Invalidate();
		}

		public int GetItemHeight(int index)
		{
			return ItemHeight;
		}

		public void Select(int start, int length)
		{
			textEntry.Select(start, length);
		}

		public void SelectAll()
		{
			textEntry.SelectAll();
		}

		protected override CreateParams CreateParams 
		{
			get
			{
				return base.CreateParams;
			}
		}

		// Non Microsoft.
		protected override void OnEnter(EventArgs e)
		{
			base.OnEnter (e);
			if (DropDownStyle == ComboBoxStyle.DropDownList)
				Invalidate();
		}

		protected override void OnLeave(EventArgs e)
		{
			base.OnLeave (e);
			if (DropDownStyle == ComboBoxStyle.DropDownList)
				Invalidate();
		}


		protected virtual void AddItemsCore(object[] value)
		{
			if (value == null | value.Length == 0)
				return;
			Items.AddRange(value);
		}

		protected override bool IsInputKey(Keys keyData)
		{
			Keys key = keyData & (Keys.Alt | Keys.KeyCode);
			if (this.DroppedDown && (key == Keys.Enter || key == Keys.Right))
				return true; 
			return base.IsInputKey(keyData);
		}

		protected override void OnMouseDown(MouseEventArgs e)
		{
			base.OnMouseDown(e);
			if (e.X >= Width - ButtonSize.Width | DropDownStyle == ComboBoxStyle.DropDownList)
				DroppedDown = !DroppedDown;
		}

		private void popup_PopDown(object sender, EventArgs e)
		{
			DroppedDown = false;
		}

		[TODO]
		protected override void OnDataSourceChanged(EventArgs e)
		{
			base.OnDataSourceChanged(e);
		}

		[TODO]
		protected override void OnDisplayMemberChanged(EventArgs e)
		{
			base.OnDisplayMemberChanged(e);
		}

		protected virtual void OnDrawItem(DrawItemEventArgs e)
		{
			// Invoke the event handler.
			DrawItemEventHandler handler = (DrawItemEventHandler)(GetHandler(EventId.DrawItem));
			if(handler != null)
				handler(this, e);
		}

		protected virtual void OnDropDown(EventArgs e)
		{
			// Invoke the event handler.
			EventHandler handler = (EventHandler)(GetHandler(EventId.DropDown));
			if(handler != null)
				handler(this, e);
		}

		protected virtual void OnDropDownStyleChanged(EventArgs e)
		{
			// Invoke the event handler.
			EventHandler handler = (EventHandler)(GetHandler(EventId.DropDownStyleChanged));
			if(handler != null)
				handler(this, e);
		}

		protected virtual void OnMeasureItem(MeasureItemEventArgs e)
		{
			// Invoke the event handler.
			MeasureItemEventHandler handler = (MeasureItemEventHandler)(GetHandler(EventId.MeasureItem));
			if(handler != null)
				handler(this, e);
		}

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

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

		protected override void OnSelectedIndexChanged(EventArgs e)
		{
			base.OnSelectedIndexChanged(e);
			// Invoke the event handler.
			EventHandler handler = (EventHandler)(GetHandler(EventId.SelectedIndexChanged));
			if(handler != null)
				handler(this, e);
		}

		protected virtual void OnSelectedItemChanged(EventArgs e)
		{
			// Invoke the event handler.
			EventHandler handler = (EventHandler)(GetHandler(EventId.SelectedItemChanged));
			if(handler != null)
				handler(this, e);
		}

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

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

		// This event is raised when a new item is selected and that change to that item is completed.
		protected virtual void OnSelectionChangeCommitted(EventArgs e)
		{
			// Invoke the event handler.
			EventHandler handler = (EventHandler)(GetHandler(EventId.SelectionChangeCommitted));
			if(handler != null)
				handler(this, e);
		}

		protected override void OnFontChanged(EventArgs e)
		{
			base.OnFontChanged (e);
			GetItemHeights();
			Invalidate();
		}

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

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

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

		[TODO]
		protected override void RefreshItem(int index)
		{
		}

		protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
		{
			if (DropDownStyle == ComboBoxStyle.DropDown || DropDownStyle == ComboBoxStyle.DropDownList)
				height = PreferredHeight;
			base.SetBoundsCore(x, y, width, height, specified);	
			textEntry.Size = new Size(ClientSize.Width - ButtonSize.Width, ClientSize.Height + 5);
			dropDownWidth = width;
		}

		protected override void SetItemsCore(IList list)
		{
			Items.Clear();
			Items.AddRange(list);
		}

		protected override void SetItemCore(int index, object value)
		{
			Items[index] = value;
		}

		public override Color BackColor
		{
			get
			{
				return base.BackColor;
			}
			set
			{
				base.BackColor = value;
				textEntry.backColor = value;
			}
		}

		public override Color ForeColor
		{
			get
			{
				return base.ForeColor;
			}
			set
			{
				base.ForeColor = value;
			}
		}

		public int FindString(string s)
		{
			return FindStringInternal(s, Items, -1, false); 
		} 

		public int FindString(string s, int startIndex)
		{
			return FindStringInternal(s, Items, startIndex, false); 
		}

		public int FindStringExact(string s)
		{
			return FindStringInternal(s, Items, -1, true);
		} 

		public int FindStringExact(string s, int startIndex)
		{
			return FindStringInternal(s, Items, startIndex, true); 
		} 

		public event DrawItemEventHandler DrawItem
		{
			add
			{
				AddHandler(EventId.DrawItem, value);
			}
			remove
			{
				RemoveHandler(EventId.DrawItem, value);
			}
		}

		public event EventHandler DropDown
		{
			add
			{
				AddHandler(EventId.DropDown, value);
			}
			remove
			{
				RemoveHandler(EventId.DropDown, value);
			}
		}
		public event EventHandler DropDownStyleChanged
		{
			add
			{
				AddHandler(EventId.DropDownStyleChanged, value);
			}
			remove
			{
				RemoveHandler(EventId.DropDownStyleChanged, value);
			}
		}

		public event MeasureItemEventHandler MeasureItem
		{
			add
			{
				AddHandler(EventId.MeasureItem, value);
				GetItemHeights();
			}
			remove
			{
				RemoveHandler(EventId.MeasureItem, value);
				GetItemHeights();
			}
		}

		public event EventHandler SelectionChangeCommitted
		{
			add
			{
				AddHandler(EventId.SelectionChangeCommitted, value);
			}
			remove
			{
				RemoveHandler(EventId.SelectionChangeCommitted, value);
			}
		}

		public override string ToString()
		{
			return base.ToString () + ", Items.Count: " + ((Items == null) ? 0 : Items.Count).ToString();
		}

#if CONFIG_COMPONENT_MODEL || CONFIG_EXTENDED_DIAGNOSTICS
		[Browsable(false)]
#endif
#if CONFIG_COMPONENT_MODEL
		[EditorBrowsable(EditorBrowsableState.Never)]
#endif
		public override Image BackgroundImage
		{
			get
			{
				return base.BackgroundImage;
			}
			set
			{
				base.BackgroundImage = value;
			}
		}


		private void popup_Paint(Object sender, PaintEventArgs e)
		{
			PopupDraw(e.Graphics, -1);
		}

		// Draw the items in the popup. Pos is the item to draw or -1 for all
		private void PopupDraw(Graphics g, int pos)
		{
			using (Brush foreBrush = new SolidBrush(ForeColor), 
					   backBrush = new SolidBrush(BackColor))
			{
				int y = 0;
				g.SetClip(new Rectangle(0, 0, popupDrawWidth, popup.Height));
				for (int i = scrollbar.Value; i < Items.Count; i++)
				{
					if (pos == -1 | i == pos)
					{
						Rectangle layout = new Rectangle(0, y, popupDrawWidth, actualItemHeight);
						if (DrawMode == DrawMode.Normal)
						{
							if (popupMouseItem == i)
							{
								g.FillRectangle(SystemBrushes.Highlight, layout); 
								g.DrawString(Items[i].ToString(), Font, SystemBrushes.HighlightText, 0, y);
							}
							else
							{
								g.FillRectangle(backBrush, layout); 
								g.DrawString(Items[i].ToString(), Font, foreBrush, 0, y);
							}
						}
						else
						{
							if (DrawMode == DrawMode.OwnerDrawVariable)
								layout = new Rectangle(0, y, popupDrawWidth, itemHeights[i]);
							DrawItemState state = DrawItemState.NoAccelerator | DrawItemState.NoFocusRect;
							if (popupMouseItem == i)
								state |= DrawItemState.Selected;
							DrawItemEventArgs drawItemEventArgs = new DrawItemEventArgs(g, Font, layout, i, state);
							OnDrawItem(drawItemEventArgs);
						}
					}
					if (DrawMode == DrawMode.OwnerDrawVariable)
						y += itemHeights[i];
					else
						y += actualItemHeight;
					if (y > popup.Height)
						break;
				}
			}
		}

		private void textentry_LostFocus(object sender, EventArgs e)
		{
			OnLostFocus(e);
		}

		private void textentry_GotFocus(object sender, EventArgs e)
		{
			OnGotFocus(e);
		}
	
		private void scrollbar_ValueChanged(object sender, EventArgs e)
		{
			using (Graphics g = popup.CreateGraphics())
				PopupDraw(g, -1);
		}

		private void popup_MouseDown(Object sender, MouseEventArgs e)
		{
			ChangeHighlighting(e.X, e.Y);
		}

		private void popup_MouseUp(Object sender, MouseEventArgs e)
		{
			if (e.Y > 0 & e.X < popupDrawWidth)
			{
				int itemFromY = ItemFromY(e.Y);
				if (itemFromY < Items.Count)
					SelectedIndex = itemFromY;
				DroppedDown = false;
				if (DropDownStyle == ComboBoxStyle.DropDownList)
					Invalidate();
				else
				{
					textEntry.Focus();
					SelectAll();
				}
			}
		}

		private void popup_MouseMove(Object sender, MouseEventArgs e)
		{
			ChangeHighlighting(e.X, e.Y);
		}

		private void ChangeHighlighting(int x, int y)
		{
			if (x > popupDrawWidth || y < 0)
				return;
			int newItem = ItemFromY(y);
			if (newItem != popupMouseItem)
			{
				int oldItem = popupMouseItem;
				popupMouseItem = newItem;
				using (Graphics g = popup.CreateGraphics())
				{
					// Clear the highlighting on the old.
					PopupDraw(g, oldItem);
					// Highlight the new.
					PopupDraw(g, popupMouseItem);
				}
			}
		}

		private int ItemFromY(int y)
		{
			if (DrawMode != DrawMode.OwnerDrawVariable)
				return y / actualItemHeight + scrollbar.Value;
			int itemY = 0;
			for (int i = scrollbar.Value; i < Items.Count; i++)
			{
				itemY += itemHeights[i];
				if (y < itemY)
					return i;
			}
			return -1;
		}


#if CONFIG_COMPACT_FORMS
 	// Process a message.
 	protected override void WndProc(ref Message m)
 	{
 		base.WndProc(ref m);
 	}
#endif // CONFIG_COMPACT_FORMS

		public class ObjectCollection: IList, ICollection, IEnumerable
		{
			private ComboBox owner;
			private ArrayList list;

			public ObjectCollection(ComboBox owner)
			{
				this.owner = owner;
			}

			private IComparer comparer;
			private IComparer Comparer
			{
				get
				{
					if (comparer == null)
						comparer = new ItemComparer(owner);
					return comparer;
				}
			}

			private ArrayList List
			{
				get
				{
					if (list == null)
						list = new ArrayList();
					return list;
				}
			}

			public virtual int Count
			{
				get
				{
					return List.Count;
				}
			}

			public virtual bool IsReadOnly
			{
				get
				{
					return false;
				}
			}

			public virtual object this[int index]
			{
				get
				{
					return List[index];
				}

				set
				{
					List[index] = value;
				}
			}

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

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

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

			public int Add(object item)
			{
				int i = List.Add(item);
				if (owner.sorted)
				{
					List.Sort(Comparer);
					i = List.IndexOf(item);
				}
				return i;
			}

			int IList.Add(object item)
			{
				return Add(item);
			}

			public void AddRange(object[] items)
			{
				AddRange(items as IList);
			}

			internal void AddRange(IList items)
			{
				List.AddRange(items);
				if (owner.sorted)
					List.Sort(Comparer);
			}

			public virtual void Clear()
			{
				owner.selectedIndex = -1;
				List.Clear();
			}

			public virtual bool Contains(object value)
			{
				return IndexOf(value) != -1;
			}

			public void CopyTo(object[] dest, int arrayIndex)
			{
				List.CopyTo(dest, arrayIndex);
			}

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

			public virtual IEnumerator GetEnumerator()
			{
				return List.GetEnumerator();
			}

			public virtual int IndexOf(object value)
			{
				return List.IndexOf(value);
			}

			public virtual void Insert(int index, object item)
			{
				if (owner.sorted)
					Add(item);
				else
					List.Insert(index, item);
			}

			public virtual void RemoveAt(int index)
			{
				List.RemoveAt(index);
				if (index < owner.selectedIndex)
					owner.selectedIndex--;
			}

			public virtual void Remove(object value)
			{
				int i = List.IndexOf(value);
				if (i != -1)
					RemoveAt(i);
			}

			internal void Sort()
			{
				List.Sort(Comparer);
			}

			private class ItemComparer: IComparer
			{
				private ComboBox owner;

				public ItemComparer(ComboBox owner)
				{
					this.owner = owner;
				}

				public virtual int Compare(object item1, object item2)
				{
					if (item1 == null)
					{
						if (item2 == null)
							return 0;
						else
							return -1;
					}
					if (item2 == null)
						return 1;
					string s1 = owner.GetItemText(item1);
					string s2 = owner.GetItemText(item2);
					return Application.CurrentCulture.CompareInfo.Compare(s1, s2);
				}
			}
		}
	}; // class ComboBox

}; // namespace System.Windows.Forms
