1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2004 Novell, Inc.
23 // Jordi Mas i Hernandez, jordi@ximian.com
31 using System.Collections;
32 using System.ComponentModel;
33 using System.Reflection;
35 namespace System.Windows.Forms
38 public class ComboBox : ListControl
40 private DrawMode draw_mode;
41 private ComboBoxStyle dropdown_style;
42 private int dropdown_width;
43 private int preferred_height;
44 private int selected_index;
45 private object selected_item;
46 internal ObjectCollection items = null;
47 private bool suspend_ctrlupdate;
48 private int maxdrop_items;
49 private bool integral_height;
51 internal ComboBoxInfo combobox_info;
52 private readonly int def_button_width = 16;
54 private int max_length;
55 private ComboListBox listbox_ctrl;
56 private StringFormat string_format;
57 private TextBox textbox_ctrl;
58 private bool process_textchanged_event;
60 internal class ComboBoxInfo
62 internal int item_height; /* Item's height */
63 internal Rectangle textarea; /* Rectangle of the editable text area */
64 internal Rectangle textarea_drawable; /* Rectangle of the editable text area - decorations - button if present*/
65 internal Rectangle button_rect;
66 internal bool show_button; /* Is the DropDown button shown? */
67 internal ButtonState button_status; /* Drop button status */
68 internal Size listbox_size;
69 internal Rectangle listbox_area; /* ListBox area in Simple combox, not used in the rest */
70 internal bool droppeddown; /* Is the associated ListBox dropped down? */
72 public ComboBoxInfo ()
74 button_status = ButtonState.Normal;
81 internal class ComboBoxItem
85 public ComboBoxItem (int index)
93 items = new ObjectCollection (this);
96 combobox_info = new ComboBoxInfo ();
97 DropDownStyle = ComboBoxStyle.DropDown;
98 BackColor = ThemeEngine.Current.ColorWindow;
99 draw_mode = DrawMode.Normal;
101 selected_item = null;
103 combobox_info.item_height = FontHeight + 2;
104 suspend_ctrlupdate = false;
108 integral_height = true;
109 process_textchanged_event = true;
111 string_format = new StringFormat ();
115 MouseDown += new MouseEventHandler (OnMouseDownCB);
116 MouseUp += new MouseEventHandler (OnMouseUpCB);
120 public new event EventHandler BackgroundImageChanged;
121 public event DrawItemEventHandler DrawItem;
122 public event EventHandler DropDown;
123 public event EventHandler DropDownStyleChanged;
124 public event MeasureItemEventHandler MeasureItem;
125 public new event PaintEventHandler Paint;
126 public event EventHandler SelectedIndexChanged;
127 public event EventHandler SelectionChangeCommitted;
130 #region Public Properties
131 public override Color BackColor {
132 get { return base.BackColor; }
134 if (base.BackColor == value)
137 base.BackColor = value;
142 public override Image BackgroundImage {
143 get { return base.BackgroundImage; }
145 if (base.BackgroundImage == value)
148 base.BackgroundImage = value;
150 if (BackgroundImageChanged != null)
151 BackgroundImageChanged (this, EventArgs.Empty);
157 protected override CreateParams CreateParams {
158 get { return base.CreateParams;}
161 protected override Size DefaultSize {
162 get { return new Size (121, PreferredHeight); }
165 public DrawMode DrawMode {
166 get { return draw_mode; }
169 if (!Enum.IsDefined (typeof (DrawMode), value))
170 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for DrawMode", value));
172 if (draw_mode == value)
180 public ComboBoxStyle DropDownStyle {
181 get { return dropdown_style; }
184 if (!Enum.IsDefined (typeof (ComboBoxStyle), value))
185 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for ComboBoxStyle", value));
187 if (dropdown_style == value)
190 if (dropdown_style == ComboBoxStyle.Simple) {
191 if (listbox_ctrl != null) {
192 listbox_ctrl.Dispose ();
193 Controls.Remove (listbox_ctrl);
198 if (dropdown_style != ComboBoxStyle.DropDownList && value == ComboBoxStyle.DropDownList) {
199 if (textbox_ctrl != null) {
200 Controls.Remove (textbox_ctrl);
201 textbox_ctrl.Dispose ();
207 dropdown_style = value;
209 if (dropdown_style == ComboBoxStyle.Simple) {
210 CBoxInfo.show_button = false;
211 CreateComboListBox ();
212 Controls.Add (listbox_ctrl);
215 CBoxInfo.show_button = true;
216 CBoxInfo.button_status = ButtonState.Normal;
219 if (dropdown_style != ComboBoxStyle.DropDownList && textbox_ctrl == null) {
220 textbox_ctrl = new TextBox ();
221 textbox_ctrl.TextChanged += new EventHandler (OnTextChangedEdit);
222 Controls.Add (textbox_ctrl);
225 if (DropDownStyleChanged != null)
226 DropDownStyleChanged (this, EventArgs.Empty);
233 public int DropDownWidth {
235 if (dropdown_width == -1)
238 return dropdown_width;
241 if (dropdown_width == value)
245 throw new ArgumentException ("The DropDownWidth value is less than one");
247 dropdown_width = value;
251 public bool DroppedDown {
253 if (dropdown_style == ComboBoxStyle.Simple)
256 return CBoxInfo.droppeddown;
259 if (dropdown_style == ComboBoxStyle.Simple)
267 listbox_ctrl.Hide ();
270 if (DropDown != null)
271 DropDown (this, EventArgs.Empty);
275 public override bool Focused {
276 get { return base.Focused; }
279 public override Color ForeColor {
280 get { return base.ForeColor; }
282 if (base.ForeColor == value)
285 base.ForeColor = value;
290 public bool IntegralHeight {
291 get { return integral_height; }
293 if (integral_height == value)
296 integral_height = value;
301 public virtual int ItemHeight {
302 get { return combobox_info.item_height; }
305 throw new ArgumentOutOfRangeException ("The item height value is less than zero");
307 combobox_info.item_height = value;
313 public ComboBox.ObjectCollection Items {
314 get { return items; }
317 public int MaxDropDownItems {
318 get { return maxdrop_items; }
320 if (maxdrop_items == value)
323 maxdrop_items = value;
327 public int MaxLength {
328 get { return max_length; }
330 if (max_length == value)
335 if (dropdown_style != ComboBoxStyle.DropDownList) {
341 textbox_ctrl.MaxLength = value;
346 public int PreferredHeight {
347 get { return preferred_height; }
350 public override int SelectedIndex {
351 get { return selected_index; }
353 if (value < -2 || value >= Items.Count)
354 throw new ArgumentOutOfRangeException ("Index of out range");
356 if (selected_index == value)
359 selected_index = value;
361 if (dropdown_style != ComboBoxStyle.DropDownList) {
362 SetControlText (Items[selected_index].ToString ());
365 OnSelectedIndexChanged (new EventArgs ());
370 public object SelectedItem {
372 if (selected_index !=-1 && Items !=null && Items.Count > 0)
373 return Items[selected_index];
378 if (selected_item == value)
381 int index = Items.IndexOf (value);
386 selected_index = index;
388 if (dropdown_style != ComboBoxStyle.DropDownList) {
389 SetControlText (Items[selected_index].ToString ());
392 OnSelectedItemChanged (new EventArgs ());
397 public string SelectedText {
399 if (dropdown_style == ComboBoxStyle.DropDownList)
402 return textbox_ctrl.Text;
405 if (dropdown_style == ComboBoxStyle.DropDownList)
408 if (textbox_ctrl.Text == value)
411 textbox_ctrl.SelectedText = value;
415 public int SelectionLength {
417 if (dropdown_style == ComboBoxStyle.DropDownList)
420 return textbox_ctrl.SelectionLength;
423 if (dropdown_style == ComboBoxStyle.DropDownList)
426 if (textbox_ctrl.SelectionLength == value)
429 textbox_ctrl.SelectionLength = value;
433 public int SelectionStart {
435 if (dropdown_style == ComboBoxStyle.DropDownList)
438 return textbox_ctrl.SelectionStart;
441 if (dropdown_style == ComboBoxStyle.DropDownList)
444 if (textbox_ctrl.SelectionStart == value)
447 textbox_ctrl.SelectionStart = value;
452 get { return sorted; }
462 public override string Text {
464 if (SelectedItem != null)
465 return SelectedItem.ToString ();
475 int index = FindString (value);
482 if (dropdown_style != ComboBoxStyle.DropDownList) {
483 textbox_ctrl.Text = value.ToString ();
488 #endregion Public Properties
490 #region Private Properties
491 internal ComboBoxInfo CBoxInfo {
492 get { return combobox_info; }
495 #endregion Private Properties
497 #region Public Methods
498 protected virtual void AddItemsCore (object[] value)
503 public void BeginUpdate ()
505 suspend_ctrlupdate = true;
508 protected override void Dispose (bool disposing)
510 if (disposing == true) {
511 if (listbox_ctrl != null) {
512 listbox_ctrl.Dispose ();
513 Controls.Remove (listbox_ctrl);
517 if (textbox_ctrl != null) {
518 Controls.Remove (textbox_ctrl);
519 textbox_ctrl.Dispose ();
524 base.Dispose (disposing);
527 public void EndUpdate ()
529 suspend_ctrlupdate = false;
533 public int FindString (string s)
535 return FindString (s, 0);
538 public int FindString (string s, int startIndex)
540 for (int i = startIndex; i < Items.Count; i++) {
541 if ((Items[i].ToString ()).StartsWith (s))
548 public int FindStringExact (string s)
550 return FindStringExact (s, 0);
553 public int FindStringExact (string s, int startIndex)
555 for (int i = startIndex; i < Items.Count; i++) {
556 if ((Items[i].ToString ()).Equals (s))
563 public int GetItemHeight (int index)
565 if (index < 0 || index >= Items.Count )
566 throw new ArgumentOutOfRangeException ("The item height value is less than zero");
568 if (DrawMode == DrawMode.OwnerDrawVariable && IsHandleCreated == true) {
569 MeasureItemEventArgs args = new MeasureItemEventArgs (DeviceContext, index, ItemHeight);
571 OnMeasureItem (args);
572 return args.ItemHeight;
579 protected override bool IsInputKey (Keys keyData)
593 protected override void OnBackColorChanged (EventArgs e)
595 base.OnBackColorChanged (e);
598 protected override void OnDataSourceChanged (EventArgs e)
600 base.OnDataSourceChanged (e);
603 protected override void OnDisplayMemberChanged (EventArgs e)
605 base.OnDisplayMemberChanged (e);
608 protected virtual void OnDrawItem (DrawItemEventArgs e)
610 if (DrawItem != null && (DrawMode == DrawMode.OwnerDrawFixed || DrawMode == DrawMode.OwnerDrawVariable)) {
615 Rectangle text_draw = e.Bounds;
617 if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) {
619 e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush
620 (ThemeEngine.Current.ColorHilight), text_draw);
623 e.Graphics.DrawString (Items[e.Index].ToString (), e.Font,
624 ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorHilightText),
625 text_draw, string_format);
628 // It seems to be a bug in CPDrawFocusRectangle
629 //ThemeEngine.Current.CPDrawFocusRectangle (e.Graphics, e.Bounds,
630 // ThemeEngine.Current.ColorHilightText, BackColor);
633 e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush
634 (e.BackColor), e.Bounds);
637 e.Graphics.DrawString (Items[e.Index].ToString (), e.Font,
638 ThemeEngine.Current.ResPool.GetSolidBrush (e.ForeColor),
639 text_draw, string_format);
644 protected virtual void OnDropDown (EventArgs e)
646 if (DropDown != null)
650 protected virtual void OnDropDownStyleChanged (EventArgs e)
652 if (DropDownStyleChanged != null)
653 DropDownStyleChanged (this, e);
656 protected override void OnFontChanged (EventArgs e)
658 base.OnFontChanged (e);
660 if (textbox_ctrl != null) {
661 textbox_ctrl.Font = Font;
664 combobox_info.item_height = FontHeight + 2;
668 protected override void OnForeColorChanged (EventArgs e)
670 base.OnForeColorChanged (e);
673 protected override void OnHandleCreated (EventArgs e)
675 base.OnHandleCreated (e);
679 protected override void OnHandleDestroyed (EventArgs e)
681 base.OnHandleDestroyed (e);
684 protected override void OnKeyPress (KeyPressEventArgs e)
689 protected virtual void OnMeasureItem (MeasureItemEventArgs e)
691 if (MeasureItem != null)
692 MeasureItem (this, e);
695 protected override void OnParentBackColorChanged (EventArgs e)
697 base.OnParentBackColorChanged (e);
700 protected override void OnResize (EventArgs e)
706 protected override void OnSelectedIndexChanged (EventArgs e)
708 base.OnSelectedIndexChanged (e);
710 if (SelectedIndexChanged != null)
711 SelectedIndexChanged (this, e);
714 protected virtual void OnSelectedItemChanged (EventArgs e)
719 protected override void OnSelectedValueChanged (EventArgs e)
721 base.OnSelectedValueChanged (e);
724 protected virtual void OnSelectionChangeCommitted (EventArgs e)
729 protected override void RefreshItem (int index)
734 public void Select (int start, int lenght)
737 throw new ArgumentException ("Start cannot be less than zero");
740 throw new ArgumentException ("Start cannot be less than zero");
742 if (dropdown_style == ComboBoxStyle.DropDownList)
745 textbox_ctrl.Select (start, lenght);
748 public void SelectAll ()
750 if (dropdown_style == ComboBoxStyle.DropDownList)
753 textbox_ctrl.SelectAll ();
756 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
758 base.SetBoundsCore (x, y, width, height, specified);
761 protected override void SetItemCore (int index, object value)
763 if (index < 0 || index >= Items.Count)
766 Items[index] = value;
769 protected override void SetItemsCore (IList value)
774 public override string ToString ()
776 return base.ToString () + ", Items.Count:" + Items.Count;
779 protected override void WndProc (ref Message m)
782 switch ((Msg) m.Msg) {
785 PaintEventArgs paint_event;
786 paint_event = XplatUI.PaintEventStart (Handle);
787 OnPaintCB (paint_event);
788 XplatUI.PaintEventEnd (Handle);
792 case Msg.WM_ERASEBKGND:
793 m.Result = (IntPtr) 1;
800 base.WndProc (ref m);
804 #endregion Public Methods
806 #region Private Methods
808 // Calcs the text area size
809 internal void CalcTextArea ()
811 combobox_info.textarea = ClientRectangle;
814 combobox_info.textarea.Height = ItemHeight + ThemeEngine.Current.DrawComboBoxEditDecorationTop () +
815 ThemeEngine.Current.DrawComboBoxEditDecorationBottom () + 2;
816 // TODO: Does the +2 change at different font resolutions?
818 /* Edit area - minus decorations (text drawable area) */
819 combobox_info.textarea_drawable = combobox_info.textarea;
820 combobox_info.textarea_drawable.Y += ThemeEngine.Current.DrawComboBoxEditDecorationTop ();
821 combobox_info.textarea_drawable.X += ThemeEngine.Current.DrawComboBoxEditDecorationLeft ();
822 combobox_info.textarea_drawable.Height -= ThemeEngine.Current.DrawComboBoxEditDecorationBottom ();
823 combobox_info.textarea_drawable.Height -= ThemeEngine.Current.DrawComboBoxEditDecorationTop();
824 combobox_info.textarea_drawable.Width -= ThemeEngine.Current.DrawComboBoxEditDecorationRight ();
825 combobox_info.textarea_drawable.Width -= ThemeEngine.Current.DrawComboBoxEditDecorationLeft ();
827 /* Non-drawable area */
828 Region area = new Region (ClientRectangle);
829 area.Exclude (combobox_info.textarea);
830 RectangleF bounds = area.GetBounds (DeviceContext);
831 combobox_info.listbox_area = new Rectangle ((int)bounds.X, (int)bounds.Y,
832 (int)bounds.Width, (int)bounds.Height);
834 if (CBoxInfo.show_button) {
835 combobox_info.textarea_drawable.Width -= def_button_width;
837 combobox_info.button_rect = new Rectangle (combobox_info.textarea_drawable.X + combobox_info.textarea_drawable.Width,
838 combobox_info.textarea_drawable.Y, def_button_width, combobox_info.textarea_drawable.Height);
842 if (dropdown_style != ComboBoxStyle.DropDownList) { /* There is an edit control*/
843 if (textbox_ctrl != null) {
844 textbox_ctrl.Location = new Point (combobox_info.textarea_drawable.X, combobox_info.textarea_drawable.Y);
845 textbox_ctrl.Size = new Size (combobox_info.textarea_drawable.Width, combobox_info.textarea_drawable.Height);
849 if (listbox_ctrl != null && dropdown_style == ComboBoxStyle.Simple) {
850 listbox_ctrl.Location = new Point (combobox_info.textarea.X, combobox_info.textarea.Y +
851 combobox_info.textarea.Height);
852 listbox_ctrl.CalcListBoxArea ();
856 private void CreateComboListBox ()
858 listbox_ctrl = new ComboListBox (this);
861 internal void Draw (Rectangle clip)
863 // No edit control, we paint the edit ourselfs
864 if (dropdown_style == ComboBoxStyle.DropDownList) {
866 Rectangle item_rect = combobox_info.textarea;
868 OnDrawItem (new DrawItemEventArgs (DeviceContext, Font, item_rect,
869 selected_index, DrawItemState.Selected,
870 ForeColor, BackColor));
873 if (clip.IntersectsWith (combobox_info.listbox_area) == true) {
874 DeviceContext.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (Parent.BackColor),
875 combobox_info.listbox_area);
878 if (CBoxInfo.show_button) {
879 DeviceContext.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorButtonFace),
880 combobox_info.button_rect);
882 ThemeEngine.Current.CPDrawComboButton (DeviceContext,
883 combobox_info.button_rect, combobox_info.button_status);
886 ThemeEngine.Current.DrawComboBoxEditDecorations (DeviceContext, this, combobox_info.textarea);
889 internal void DropDownListBox ()
891 combobox_info.button_status = ButtonState.Pushed;
893 if (combobox_info.button_status == ButtonState.Pushed) {
894 if (listbox_ctrl == null) {
895 CreateComboListBox ();
898 listbox_ctrl.Location = PointToScreen (new Point (combobox_info.textarea.X, combobox_info.textarea.Y +
899 combobox_info.textarea.Height));
901 listbox_ctrl.ShowWindow ();
904 CBoxInfo.droppeddown = true;
907 internal void DropDownListBoxFinished ()
909 combobox_info.button_status = ButtonState.Normal;
910 Invalidate (combobox_info.button_rect);
911 CBoxInfo.droppeddown = false;
914 private int FindStringCaseInsensitive (string search)
916 for (int i = 0; i < Items.Count; i++)
\r
919 if (String.Compare (Items[i].ToString (), 0, search, 0, search.Length, true) == 0)
927 internal virtual void OnMouseDownCB (object sender, MouseEventArgs e)
930 if (clicked == false && combobox_info.button_rect.Contains (e.X, e.Y)) {
934 if (combobox_info.button_status == ButtonState.Normal) {
938 Invalidate (combobox_info.button_rect);
942 internal virtual void OnMouseUpCB (object sender, MouseEventArgs e)
945 if (clicked == true && combobox_info.button_rect.Contains (e.X, e.Y)) {
951 private void OnPaintCB (PaintEventArgs pevent)
953 if (Width <= 0 || Height <= 0 || Visible == false || suspend_ctrlupdate == true)
956 /* Copies memory drawing buffer to screen*/
957 Draw (ClientRectangle);
958 pevent.Graphics.DrawImage (ImageBuffer, ClientRectangle, ClientRectangle, GraphicsUnit.Pixel);
961 Paint (this, pevent);
964 private void OnTextChangedEdit (object sender, EventArgs e)
966 if (process_textchanged_event == false)
969 int item = FindStringCaseInsensitive (textbox_ctrl.Text);
974 listbox_ctrl.SetTopItem (item);
975 listbox_ctrl.SetHighLightedItem (item);
979 internal void SetControlText (string s)
981 process_textchanged_event = false;
982 textbox_ctrl.Text = s;
983 process_textchanged_event = true;
986 private void UpdatedItems ()
988 if (dropdown_style != ComboBoxStyle.Simple)
991 listbox_ctrl.UpdateLastVisibleItem ();
992 listbox_ctrl.Refresh ();
995 #endregion Private Methods
999 ComboBox.ObjectCollection
1001 public class ObjectCollection : IList, ICollection, IEnumerable
1004 private ComboBox owner;
1005 internal ArrayList object_items = new ArrayList ();
1006 internal ArrayList listbox_items = new ArrayList ();
1008 public ObjectCollection (ComboBox owner)
1014 #region Public Properties
1015 public virtual int Count {
1016 get { return object_items.Count; }
1019 public virtual bool IsReadOnly {
1020 get { return false; }
1023 public virtual object this [int index] {
1025 if (index < 0 || index >= Count)
1026 throw new ArgumentOutOfRangeException ("Index of out range");
1028 return object_items[index];
1031 if (index < 0 || index >= Count)
1032 throw new ArgumentOutOfRangeException ("Index of out range");
1034 object_items[index] = value;
1038 bool ICollection.IsSynchronized {
1039 get { return false; }
1042 object ICollection.SyncRoot {
1043 get { return this; }
1046 bool IList.IsFixedSize {
1047 get { return false; }
1050 #endregion Public Properties
1052 #region Public Methods
1053 public int Add (object item)
1057 idx = AddItem (item);
1058 owner.UpdatedItems ();
1062 public void AddRange (object[] items)
1064 foreach (object mi in items)
1067 owner.UpdatedItems ();
1070 public virtual void Clear ()
1072 object_items.Clear ();
1073 listbox_items.Clear ();
1074 owner.UpdatedItems ();
1077 public virtual bool Contains (object obj)
1079 return object_items.Contains (obj);
1082 public void CopyTo (object[] dest, int arrayIndex)
1084 object_items.CopyTo (dest, arrayIndex);
1087 void ICollection.CopyTo (Array dest, int index)
1089 object_items.CopyTo (dest, index);
1092 public virtual IEnumerator GetEnumerator ()
1094 return object_items.GetEnumerator ();
1097 int IList.Add (object item)
1102 public virtual int IndexOf (object value)
1104 return object_items.IndexOf (value);
1107 public virtual void Insert (int index, object item)
1109 throw new NotImplementedException ();
1112 public virtual void Remove (object value)
1114 RemoveAt (IndexOf (value));
1117 public virtual void RemoveAt (int index)
1119 if (index < 0 || index >= Count)
1120 throw new ArgumentOutOfRangeException ("Index of out range");
1122 object_items.RemoveAt (index);
1123 listbox_items.RemoveAt (index);
1124 owner.UpdatedItems ();
1126 #endregion Public Methods
1128 #region Private Methods
1129 private int AddItem (object item)
1131 int cnt = object_items.Count;
1132 object_items.Add (item);
1133 listbox_items.Add (new ComboBox.ComboBoxItem (cnt));
1137 internal ComboBox.ComboBoxItem GetComboBoxItem (int index)
1139 if (index < 0 || index >= Count)
1140 throw new ArgumentOutOfRangeException ("Index of out range");
1142 return (ComboBox.ComboBoxItem) listbox_items[index];
1145 internal void SetComboBoxItem (ComboBox.ComboBoxItem item, int index)
1147 if (index < 0 || index >= Count)
1148 throw new ArgumentOutOfRangeException ("Index of out range");
1150 listbox_items[index] = item;
1153 #endregion Private Methods
1159 internal class ComboListBox : Control
1161 private ComboBox owner;
1162 private bool need_vscrollbar;
1163 private VScrollBar vscrollbar_ctrl;
1164 private int top_item; /* First item that we show the in the current page */
1165 private int last_item; /* Last visible item */
1166 private int highlighted_item; /* Item that is currently selected */
1167 internal int page_size; /* Number of listbox items per page */
1168 private Rectangle textarea_drawable; /* Rectangle of the drawable text area */
1170 internal enum ItemNavigation
1180 public ComboListBox (ComboBox owner) : base ()
1183 need_vscrollbar = false;
1187 highlighted_item = -1;
1189 MouseDown += new MouseEventHandler (OnMouseDownPUW);
1190 MouseMove += new MouseEventHandler (OnMouseMovePUW);
1191 KeyDown += new KeyEventHandler (OnKeyDownPUW);
1192 Paint += new PaintEventHandler (OnPaintPUW);
1193 SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
1194 SetStyle (ControlStyles.ResizeRedraw | ControlStyles.Opaque, true);
1196 /* Vertical scrollbar */
1197 vscrollbar_ctrl = new VScrollBar ();
1198 vscrollbar_ctrl.Minimum = 0;
1199 vscrollbar_ctrl.SmallChange = 1;
1200 vscrollbar_ctrl.LargeChange = 1;
1201 vscrollbar_ctrl.Maximum = 0;
1202 vscrollbar_ctrl.ValueChanged += new EventHandler (VerticalScrollEvent);
1203 vscrollbar_ctrl.Visible = false;
1206 protected override CreateParams CreateParams
1209 CreateParams cp = base.CreateParams;
1210 if (owner != null && owner.DropDownStyle != ComboBoxStyle.Simple) {
1211 cp.Style = unchecked ((int)(WindowStyles.WS_POPUP | WindowStyles.WS_VISIBLE | WindowStyles.WS_CLIPSIBLINGS | WindowStyles.WS_CLIPCHILDREN));
1212 cp.ExStyle |= (int)WindowStyles.WS_EX_TOOLWINDOW;
1218 #region Private Methods
1220 protected override void CreateHandle ()
1222 base.CreateHandle ();
1223 Controls.Add (vscrollbar_ctrl);
1226 // Calcs the listbox area
1227 internal void CalcListBoxArea ()
1230 int item_height = owner.ItemHeight;
1232 if (owner.DropDownStyle == ComboBoxStyle.Simple) {
1233 width = owner.CBoxInfo.listbox_area.Width;
1234 height = owner.CBoxInfo.listbox_area.Height;
1236 if (owner.IntegralHeight == true) {
1237 int remaining = (height -
1238 ThemeEngine.Current.DrawComboListBoxDecorationBottom (owner.DropDownStyle) -
1239 ThemeEngine.Current.DrawComboListBoxDecorationTop (owner.DropDownStyle)) %
1242 if (remaining > 0) {
1243 height -= remaining;
1247 else { // DropDown or DropDownList
1249 width = owner.DropDownWidth;
1250 int count = (owner.Items.Count <= owner.MaxDropDownItems) ? owner.Items.Count : owner.MaxDropDownItems;
1252 if (owner.DrawMode == DrawMode.OwnerDrawVariable) {
1254 for (int i = 0; i < count; i++) {
1255 height += owner.GetItemHeight (i);
1259 height = (item_height - 2) * count;
1263 height += ThemeEngine.Current.DrawComboListBoxDecorationBottom (owner.DropDownStyle);
1264 height += ThemeEngine.Current.DrawComboListBoxDecorationTop (owner.DropDownStyle);
1268 if (owner.Items.Count <= owner.MaxDropDownItems) {
1269 need_vscrollbar = false;
1272 need_vscrollbar = true;
1273 vscrollbar_ctrl.Height = height - ThemeEngine.Current.DrawComboListBoxDecorationBottom (owner.DropDownStyle) -
1274 ThemeEngine.Current.DrawComboListBoxDecorationTop (owner.DropDownStyle);
1276 vscrollbar_ctrl.Location = new Point (width - vscrollbar_ctrl.Width - ThemeEngine.Current.DrawComboListBoxDecorationRight (owner.DropDownStyle),
1277 ThemeEngine.Current.DrawComboListBoxDecorationTop (owner.DropDownStyle));
1279 vscrollbar_ctrl.Maximum = owner.Items.Count - owner.MaxDropDownItems;
1282 if (vscrollbar_ctrl.Visible != need_vscrollbar)
1283 vscrollbar_ctrl.Visible = need_vscrollbar;
1285 Size = new Size (width, height);
1286 textarea_drawable = ClientRectangle;
1287 textarea_drawable.Width = width;
1288 textarea_drawable.Height = height;
1290 // Exclude decorations
1291 textarea_drawable.X += ThemeEngine.Current.DrawComboListBoxDecorationLeft (owner.DropDownStyle);
1292 textarea_drawable.Y += ThemeEngine.Current.DrawComboListBoxDecorationTop (owner.DropDownStyle);
1293 textarea_drawable.Width -= ThemeEngine.Current.DrawComboListBoxDecorationRight (owner.DropDownStyle);
1294 textarea_drawable.Width -= ThemeEngine.Current.DrawComboListBoxDecorationLeft (owner.DropDownStyle);
1295 textarea_drawable.Height -= ThemeEngine.Current.DrawComboListBoxDecorationBottom (owner.DropDownStyle);
1296 textarea_drawable.Height -= ThemeEngine.Current.DrawComboListBoxDecorationTop (owner.DropDownStyle);
1298 if (need_vscrollbar)
1299 textarea_drawable.Width -= vscrollbar_ctrl.Width;
1301 last_item = LastVisibleItem ();
1302 page_size = textarea_drawable.Height / (item_height - 2);
1304 Console.WriteLine ("ComboListBox.CalcListBoxArea {0} page_size {1}, dh: {2}, itemh {3}", textarea_drawable,
1305 page_size, textarea_drawable.Height, (item_height - 2));
1307 Console.WriteLine ("CalcTextArea Items:{0}", owner.Items.Count);
1310 private void Draw (Rectangle clip)
1312 DeviceContext.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush
1313 (owner.BackColor), ClientRectangle);
1315 if (owner.Items.Count > 0) {
1316 Rectangle item_rect;
1317 DrawItemState state = DrawItemState.None;
1319 for (int i = top_item; i <= last_item; i++) {
1320 item_rect = GetItemDisplayRectangle (i, top_item);
1322 if (clip.IntersectsWith (item_rect) == false)
1326 state = DrawItemState.None;
1328 if (i == highlighted_item)
1329 state |= DrawItemState.Selected;
1331 owner.OnDrawItem (new DrawItemEventArgs (DeviceContext, owner.Font, item_rect,
1332 i, state, owner.ForeColor, owner.BackColor));
1336 ThemeEngine.Current.DrawComboListBoxDecorations (DeviceContext, owner, ClientRectangle);
1339 private Rectangle GetItemDisplayRectangle (int index, int first_displayble)
1341 if (index < 0 || index >= owner.Items.Count)
1342 throw new ArgumentOutOfRangeException ("GetItemRectangle index out of range.");
1344 Rectangle item_rect = new Rectangle ();
1345 int height = owner.GetItemHeight (index);
1347 item_rect.X = ThemeEngine.Current.DrawComboListBoxDecorationRight (owner.DropDownStyle);
1348 item_rect.Width = textarea_drawable.Width;
1349 item_rect.Y = 2 + ((height - 2) * (index - first_displayble));
1350 item_rect.Height = height;
1354 public void HideWindow ()
1356 if (owner.DropDownStyle == ComboBoxStyle.Simple)
1359 owner.DropDownListBoxFinished ();
1363 private int IndexFromPointDisplayRectangle (int x, int y)
1365 for (int i = top_item; i <= last_item; i++) {
1366 if (GetItemDisplayRectangle (i, top_item).Contains (x, y) == true)
1373 protected override bool IsInputKey (Keys keyData)
1375 return owner.IsInputKey (keyData);
1378 private int LastVisibleItem ()
1380 Rectangle item_rect;
1381 int top_y = textarea_drawable.Y + textarea_drawable.Height;
1384 for (i = top_item; i < owner.Items.Count; i++) {
1385 item_rect = GetItemDisplayRectangle (i, top_item);
1386 if (item_rect.Y + item_rect.Height > top_y) {
1393 private void NavigateItemVisually (ItemNavigation navigation)
1397 switch (navigation) {
1398 case ItemNavigation.Next: {
1399 if (highlighted_item + 1 < owner.Items.Count) {
1401 if (highlighted_item + 1 > last_item) {
1403 vscrollbar_ctrl.Value = top_item;
1405 item = highlighted_item + 1;
1410 case ItemNavigation.Previous: {
1411 if (highlighted_item > 0) {
1413 if (highlighted_item - 1 < top_item) {
1415 vscrollbar_ctrl.Value = top_item;
1417 item = highlighted_item - 1;
1422 case ItemNavigation.NextPage: {
1423 if (highlighted_item + page_size - 1 > owner.Items.Count) {
1424 top_item = owner.Items.Count - page_size;
1425 vscrollbar_ctrl.Value = top_item;
1426 item = owner.Items.Count - 1;
1429 if (highlighted_item + page_size - 1 > last_item) {
1430 top_item = highlighted_item;
1431 vscrollbar_ctrl.Value = highlighted_item;
1434 item = highlighted_item + page_size - 1;
1439 case ItemNavigation.PreviousPage: {
1441 /* Go to the first item*/
1442 if (highlighted_item - (page_size - 1) <= 0) {
1445 vscrollbar_ctrl.Value = top_item;
1448 else { /* One page back */
1449 if (highlighted_item - (page_size - 1) < top_item) {
1450 top_item = highlighted_item - (page_size - 1);
1451 vscrollbar_ctrl.Value = top_item;
1454 item = highlighted_item - (page_size - 1);
1465 SetHighLightedItem (item);
1467 if (owner.DropDownStyle == ComboBoxStyle.Simple) {
1468 owner.SetControlText (owner.Items[item].ToString ());
1473 private void OnKeyDownPUW (object sender, KeyEventArgs e)
1475 switch (e.KeyCode) {
1477 NavigateItemVisually (ItemNavigation.Previous);
1481 NavigateItemVisually (ItemNavigation.Next);
1485 NavigateItemVisually (ItemNavigation.PreviousPage);
1489 NavigateItemVisually (ItemNavigation.NextPage);
1497 public void SetHighLightedItem (int index)
1499 Rectangle invalidate;
1501 if (highlighted_item == index)
1505 if (highlighted_item != -1) {
1506 invalidate = GetItemDisplayRectangle (highlighted_item, top_item);
1507 if (ClientRectangle.Contains (invalidate))
1508 Invalidate (invalidate);
1511 highlighted_item = index;
1514 invalidate = GetItemDisplayRectangle (highlighted_item, top_item);
1515 if (ClientRectangle.Contains (invalidate))
1516 Invalidate (invalidate);
1520 public void SetTopItem (int item)
1523 UpdateLastVisibleItem ();
1527 private void OnMouseDownPUW (object sender, MouseEventArgs e)
1529 /* Click outside the client area destroys the popup */
1530 if (ClientRectangle.Contains (e.X, e.Y) == false) {
1535 /* Click on an element */
1536 int index = IndexFromPointDisplayRectangle (e.X, e.Y);
1537 if (index == -1) return;
1539 owner.SelectedIndex = index;
1540 SetHighLightedItem (index);
1544 private void OnMouseMovePUW (object sender, MouseEventArgs e)
1546 if (owner.DropDownStyle == ComboBoxStyle.Simple)
1549 int index = IndexFromPointDisplayRectangle (e.X, e.Y);
1552 SetHighLightedItem (index);
1555 private void OnPaintPUW (Object o, PaintEventArgs pevent)
1557 if (Width <= 0 || Height <= 0 || Visible == false)
1560 Draw (pevent.ClipRectangle);
1561 pevent.Graphics.DrawImage (ImageBuffer, pevent.ClipRectangle, pevent.ClipRectangle, GraphicsUnit.Pixel);
1564 public void ShowWindow ()
1570 if (owner.DropDown != null)
1571 owner.DropDown (owner, EventArgs.Empty);
1574 public void UpdateLastVisibleItem ()
1576 last_item = LastVisibleItem ();
1580 private void VerticalScrollEvent (object sender, EventArgs e)
1582 top_item = vscrollbar_ctrl.Value;
1583 UpdateLastVisibleItem ();
1587 #endregion Private Methods