In Test/System.Windows.Forms:
[mcs.git] / class / Managed.Windows.Forms / System.Windows.Forms / ComboBox.cs
blobab9c786163b82a1e5433b51866111f2f8ce81c9b
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:
8 //
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-2006 Novell, Inc.
22 // Authors:
23 // Jordi Mas i Hernandez, jordi@ximian.com
24 // Mike Kestner <mkestner@novell.com>
25 // Daniel Nauck (dna(at)mono-project(dot)de)
27 using System;
28 using System.Collections;
29 using System.ComponentModel;
30 using System.ComponentModel.Design;
31 using System.ComponentModel.Design.Serialization;
32 using System.Drawing;
33 using System.Globalization;
34 using System.Reflection;
35 using System.Runtime.InteropServices;
37 namespace System.Windows.Forms
39 [DefaultProperty("Items")]
40 [DefaultEvent("SelectedIndexChanged")]
41 [Designer ("System.Windows.Forms.Design.ComboBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
42 #if NET_2_0
43 [DefaultBindingProperty ("Text")]
44 [ClassInterface (ClassInterfaceType.AutoDispatch)]
45 [ComVisible(true)]
46 #endif
47 public class ComboBox : ListControl
49 private DrawMode draw_mode = DrawMode.Normal;
50 private ComboBoxStyle dropdown_style;
51 private int dropdown_width = -1;
52 private int selected_index = -1;
53 private ObjectCollection items;
54 private bool suspend_ctrlupdate;
55 private int maxdrop_items = 8;
56 private bool integral_height = true;
57 private bool sorted;
58 private int max_length;
59 private ComboListBox listbox_ctrl;
60 private ComboTextBox textbox_ctrl;
61 private bool process_textchanged_event = true;
62 private bool item_height_specified;
63 private int item_height;
64 private int requested_height = -1;
65 private Hashtable item_heights;
66 private bool show_dropdown_button;
67 private ButtonState button_state = ButtonState.Normal;
68 private bool dropped_down;
69 private Rectangle text_area;
70 private Rectangle button_area;
71 private Rectangle listbox_area;
72 private const int button_width = 16;
73 #if NET_2_0
74 private AutoCompleteStringCollection auto_complete_custom_source = null;
75 private AutoCompleteMode auto_complete_mode = AutoCompleteMode.None;
76 private AutoCompleteSource auto_complete_source = AutoCompleteSource.None;
77 private int drop_down_height;
78 private FlatStyle flat_style;
79 #endif
81 [ComVisible(true)]
82 public class ChildAccessibleObject : AccessibleObject {
84 public ChildAccessibleObject (ComboBox owner, IntPtr handle)
85 : base (owner)
89 public override string Name {
90 get {
91 return base.Name;
96 public ComboBox ()
98 items = new ObjectCollection (this);
99 DropDownStyle = ComboBoxStyle.DropDown;
100 item_height = FontHeight + 2;
101 BackColor = ThemeEngine.Current.ColorWindow;
102 border_style = BorderStyle.None;
104 #if NET_2_0
105 drop_down_height = 106;
106 flat_style = FlatStyle.Standard;
107 #endif
109 /* Events */
110 MouseDown += new MouseEventHandler (OnMouseDownCB);
111 MouseUp += new MouseEventHandler (OnMouseUpCB);
112 MouseMove += new MouseEventHandler (OnMouseMoveCB);
113 MouseWheel += new MouseEventHandler (OnMouseWheelCB);
114 KeyDown +=new KeyEventHandler(OnKeyDownCB);
117 #region events
119 [Browsable (false)]
120 [EditorBrowsable (EditorBrowsableState.Never)]
121 public new event EventHandler BackgroundImageChanged {
122 add { base.BackgroundImageChanged += value; }
123 remove { base.BackgroundImageChanged -= value; }
126 #if NET_2_0
128 [Browsable (false)]
129 [EditorBrowsable (EditorBrowsableState.Never)]
130 public new event EventHandler BackgroundImageLayoutChanged
132 add { base.BackgroundImageLayoutChanged += value; }
133 remove { base.BackgroundImageLayoutChanged -= value; }
136 [Browsable (false)]
137 [EditorBrowsable (EditorBrowsableState.Never)]
138 public new event EventHandler DoubleClick
140 add { base.DoubleClick += value; }
141 remove { base.DoubleClick -= value; }
143 #endif
145 static object DrawItemEvent = new object ();
146 static object DropDownEvent = new object ();
147 static object DropDownStyleChangedEvent = new object ();
148 static object MeasureItemEvent = new object ();
149 static object SelectedIndexChangedEvent = new object ();
150 static object SelectionChangeCommittedEvent = new object ();
151 #if NET_2_0
152 static object DropDownClosedEvent = new object ();
153 static object TextUpdateEvent = new object ();
154 #endif
156 public event DrawItemEventHandler DrawItem {
157 add { Events.AddHandler (DrawItemEvent, value); }
158 remove { Events.RemoveHandler (DrawItemEvent, value); }
161 public event EventHandler DropDown {
162 add { Events.AddHandler (DropDownEvent, value); }
163 remove { Events.RemoveHandler (DropDownEvent, value); }
165 #if NET_2_0
166 public event EventHandler DropDownClosed
168 add { Events.AddHandler (DropDownClosedEvent, value); }
169 remove { Events.RemoveHandler (DropDownClosedEvent, value); }
171 #endif
173 public event EventHandler DropDownStyleChanged {
174 add { Events.AddHandler (DropDownStyleChangedEvent, value); }
175 remove { Events.RemoveHandler (DropDownStyleChangedEvent, value); }
178 public event MeasureItemEventHandler MeasureItem {
179 add { Events.AddHandler (MeasureItemEvent, value); }
180 remove { Events.RemoveHandler (MeasureItemEvent, value); }
182 #if NET_2_0
183 [Browsable (false)]
184 [EditorBrowsable (EditorBrowsableState.Never)]
185 public new event EventHandler PaddingChanged
187 add { base.PaddingChanged += value; }
188 remove { base.PaddingChanged -= value; }
190 #endif
192 [Browsable (false)]
193 [EditorBrowsable (EditorBrowsableState.Never)]
194 public new event PaintEventHandler Paint {
195 add { base.Paint += value; }
196 remove { base.Paint -= value; }
199 public event EventHandler SelectedIndexChanged {
200 add { Events.AddHandler (SelectedIndexChangedEvent, value); }
201 remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
204 public event EventHandler SelectionChangeCommitted {
205 add { Events.AddHandler (SelectionChangeCommittedEvent, value); }
206 remove { Events.RemoveHandler (SelectionChangeCommittedEvent, value); }
208 #if NET_2_0
209 public event EventHandler TextUpdate
211 add { Events.AddHandler (TextUpdateEvent, value); }
212 remove { Events.RemoveHandler (TextUpdateEvent, value); }
214 #endif
216 #endregion Events
218 #region Public Properties
219 #if NET_2_0
220 [MonoTODO("AutoCompletion algorithm is currently not implemented.")]
221 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
222 [Browsable (true)]
223 [EditorBrowsable (EditorBrowsableState.Always)]
224 [Localizable (true)]
225 [Editor ("System.Windows.Forms.Design.ListControlStringCollectionEditor, " + Consts.AssemblySystem_Design,
226 "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
227 public AutoCompleteStringCollection AutoCompleteCustomSource {
228 get {
229 if(auto_complete_custom_source == null) {
230 auto_complete_custom_source = new AutoCompleteStringCollection ();
231 auto_complete_custom_source.CollectionChanged += new CollectionChangeEventHandler (OnAutoCompleteCustomSourceChanged);
233 return auto_complete_custom_source;
235 set {
236 if(auto_complete_custom_source == value)
237 return;
239 if(auto_complete_custom_source != null) //remove eventhandler from old collection
240 auto_complete_custom_source.CollectionChanged -= new CollectionChangeEventHandler (OnAutoCompleteCustomSourceChanged);
242 auto_complete_custom_source = value;
244 if(auto_complete_custom_source != null)
245 auto_complete_custom_source.CollectionChanged += new CollectionChangeEventHandler (OnAutoCompleteCustomSourceChanged);
249 [MonoTODO("AutoCompletion algorithm is currently not implemented.")]
250 [Browsable (true)]
251 [EditorBrowsable (EditorBrowsableState.Always)]
252 [DefaultValue (AutoCompleteMode.None)]
253 public AutoCompleteMode AutoCompleteMode {
254 get { return auto_complete_mode; }
255 set {
256 if(auto_complete_mode == value)
257 return;
259 if((value < AutoCompleteMode.None) || (value > AutoCompleteMode.SuggestAppend))
260 throw new InvalidEnumArgumentException (Locale.GetText ("Enum argument value '{0}' is not valid for AutoCompleteMode", value));
262 auto_complete_mode = value;
266 [MonoTODO("AutoCompletion algorithm is currently not implemented.")]
267 [Browsable (true)]
268 [EditorBrowsable (EditorBrowsableState.Always)]
269 [DefaultValue (AutoCompleteSource.None)]
270 public AutoCompleteSource AutoCompleteSource {
271 get { return auto_complete_source; }
272 set {
273 if(auto_complete_source == value)
274 return;
276 if(!Enum.IsDefined (typeof (AutoCompleteSource), value))
277 throw new InvalidEnumArgumentException (Locale.GetText ("Enum argument value '{0}' is not valid for AutoCompleteSource", value));
279 auto_complete_source = value;
282 #endif
283 public override Color BackColor {
284 get { return base.BackColor; }
285 set {
286 if (base.BackColor == value)
287 return;
288 base.BackColor = value;
289 Refresh ();
293 [Browsable (false)]
294 [EditorBrowsable (EditorBrowsableState.Never)]
295 public override Image BackgroundImage {
296 get { return base.BackgroundImage; }
297 set {
298 if (base.BackgroundImage == value)
299 return;
300 base.BackgroundImage = value;
301 Refresh ();
305 #if NET_2_0
306 [Browsable (false)]
307 [EditorBrowsable (EditorBrowsableState.Never)]
308 public override ImageLayout BackgroundImageLayout {
309 get { return base.BackgroundImageLayout; }
310 set { base.BackgroundImageLayout = value; }
312 #endif
314 protected override CreateParams CreateParams {
315 get { return base.CreateParams;}
318 #if NET_2_0
319 [DefaultValue ((string)null)]
320 [AttributeProvider (typeof (IListSource))]
321 [RefreshProperties (RefreshProperties.Repaint)]
322 public new object DataSource {
323 get { return base.DataSource; }
324 set { base.DataSource = value; }
326 #endif
328 protected override Size DefaultSize {
329 get { return new Size (121, 21); }
332 [RefreshProperties(RefreshProperties.Repaint)]
333 [DefaultValue (DrawMode.Normal)]
334 public DrawMode DrawMode {
335 get { return draw_mode; }
336 set {
337 if (!Enum.IsDefined (typeof (DrawMode), value))
338 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for DrawMode", value));
340 if (draw_mode == value)
341 return;
343 if (draw_mode == DrawMode.OwnerDrawVariable)
344 item_heights = null;
345 draw_mode = value;
346 if (draw_mode == DrawMode.OwnerDrawVariable)
347 item_heights = new Hashtable ();
348 Refresh ();
352 #if NET_2_0
353 [Browsable (true)]
354 [DefaultValue (106)]
355 [EditorBrowsable (EditorBrowsableState.Always)]
356 public int DropDownHeight {
357 get {
358 return drop_down_height;
360 set {
361 if (value < 1)
362 throw new ArgumentOutOfRangeException ("DropDownHeight", "DropDownHeight must be greater than 0.");
364 drop_down_height = value;
365 IntegralHeight = false;
368 #endif
370 [DefaultValue (ComboBoxStyle.DropDown)]
371 [RefreshProperties(RefreshProperties.Repaint)]
372 public ComboBoxStyle DropDownStyle {
373 get { return dropdown_style; }
374 set {
375 if (!Enum.IsDefined (typeof (ComboBoxStyle), value))
376 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for ComboBoxStyle", value));
378 if (dropdown_style == value)
379 return;
381 SuspendLayout ();
383 if (dropdown_style == ComboBoxStyle.Simple) {
384 if (listbox_ctrl != null) {
385 Controls.RemoveImplicit (listbox_ctrl);
386 listbox_ctrl.Dispose ();
387 listbox_ctrl = null;
391 dropdown_style = value;
393 if (dropdown_style == ComboBoxStyle.DropDownList && textbox_ctrl != null) {
394 Controls.RemoveImplicit (textbox_ctrl);
395 textbox_ctrl.Dispose ();
396 textbox_ctrl = null;
399 if (dropdown_style == ComboBoxStyle.Simple) {
400 show_dropdown_button = false;
402 CreateComboListBox ();
404 if (IsHandleCreated) {
405 Controls.AddImplicit (listbox_ctrl);
406 listbox_ctrl.Visible = true;
408 } else {
409 show_dropdown_button = true;
410 button_state = ButtonState.Normal;
413 if (dropdown_style != ComboBoxStyle.DropDownList && textbox_ctrl == null) {
414 textbox_ctrl = new ComboTextBox (this);
415 object selected_item = SelectedItem;
416 if (selected_item != null)
417 textbox_ctrl.Text = GetItemText (selected_item);
418 textbox_ctrl.BorderStyle = BorderStyle.None;
419 textbox_ctrl.TextChanged += new EventHandler (OnTextChangedEdit);
420 textbox_ctrl.Click += new EventHandler (OnTextBoxClick);
422 if (IsHandleCreated == true)
423 Controls.AddImplicit (textbox_ctrl);
426 ResumeLayout ();
427 OnDropDownStyleChanged (EventArgs.Empty);
429 LayoutComboBox ();
430 UpdateComboBoxBounds ();
431 Refresh ();
435 public int DropDownWidth {
436 get {
437 if (dropdown_width == -1)
438 return Width;
440 return dropdown_width;
442 set {
443 if (dropdown_width == value)
444 return;
446 if (value < 1)
447 #if NET_2_0
448 throw new ArgumentOutOfRangeException ("DropDownWidth",
449 "The DropDownWidth value is less than one.");
450 #else
451 throw new ArgumentException ("The DropDownWidth value is less than one.");
452 #endif
454 dropdown_width = value;
458 [Browsable (false)]
459 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
460 public bool DroppedDown {
461 get {
462 if (dropdown_style == ComboBoxStyle.Simple)
463 return true;
465 return dropped_down;
467 set {
468 if (dropdown_style == ComboBoxStyle.Simple || dropped_down == value)
469 return;
471 if (value)
472 DropDownListBox ();
473 else
474 listbox_ctrl.Hide ();
478 #if NET_2_0
479 [DefaultValue (FlatStyle.Standard)]
480 [Localizable (true)]
481 public FlatStyle FlatStyle {
482 get { return flat_style; }
483 set {
484 if (!Enum.IsDefined (typeof (FlatStyle), value))
485 throw new InvalidEnumArgumentException ("FlatStyle", (int) value, typeof (FlatStyle));
487 flat_style = value;
488 LayoutComboBox ();
489 Invalidate ();
492 #endif
494 public override bool Focused {
495 get { return base.Focused; }
498 public override Color ForeColor {
499 get { return base.ForeColor; }
500 set {
501 if (base.ForeColor == value)
502 return;
503 base.ForeColor = value;
504 Refresh ();
508 [DefaultValue (true)]
509 [Localizable (true)]
510 public bool IntegralHeight {
511 get { return integral_height; }
512 set {
513 if (integral_height == value)
514 return;
515 integral_height = value;
516 UpdateComboBoxBounds ();
517 Refresh ();
521 [Localizable (true)]
522 public int ItemHeight {
523 get {
524 if (item_height == -1) {
525 SizeF sz = DeviceContext.MeasureString ("The quick brown Fox", Font);
526 item_height = (int) sz.Height;
528 return item_height;
530 set {
531 if (value < 1)
532 #if NET_2_0
533 throw new ArgumentOutOfRangeException ("ItemHeight",
534 "The item height value is less than one.");
535 #else
536 throw new ArgumentException ("The item height value is less than one.");
537 #endif
539 item_height_specified = true;
540 item_height = value;
541 if (IntegralHeight)
542 UpdateComboBoxBounds ();
543 LayoutComboBox ();
544 Refresh ();
548 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
549 [Localizable (true)]
550 [Editor ("System.Windows.Forms.Design.ListControlStringCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
551 #if NET_2_0
552 [MergableProperty (false)]
553 #endif
554 public ComboBox.ObjectCollection Items {
555 get { return items; }
558 [DefaultValue (8)]
559 [Localizable (true)]
560 public int MaxDropDownItems {
561 get { return maxdrop_items; }
562 set {
563 if (maxdrop_items == value)
564 return;
565 maxdrop_items = value;
569 #if NET_2_0
570 public override Size MaximumSize {
571 get { return base.MaximumSize; }
572 set {
573 base.MaximumSize = new Size (value.Width, 0);
576 #endif
578 [DefaultValue (0)]
579 [Localizable (true)]
580 public int MaxLength {
581 get { return max_length; }
582 set {
583 if (max_length == value)
584 return;
586 max_length = value;
588 if (dropdown_style != ComboBoxStyle.DropDownList) {
589 if (value < 0) {
590 value = 0;
592 textbox_ctrl.MaxLength = value;
597 #if NET_2_0
598 public override Size MinimumSize {
599 get { return base.MinimumSize; }
600 set {
601 base.MinimumSize = new Size (value.Width, 0);
605 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
606 [EditorBrowsable (EditorBrowsableState.Never)]
607 [Browsable (false)]
608 public new Padding Padding {
609 get { return base.Padding; }
610 set { base.Padding = value; }
612 #endif
614 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
615 [Browsable (false)]
616 public int PreferredHeight {
617 get {
618 return ItemHeight + 5;
622 [Browsable (false)]
623 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
624 public override int SelectedIndex {
625 get { return selected_index; }
626 set {
627 if (selected_index == value)
628 return;
630 if (value <= -2 || value >= Items.Count)
631 throw new ArgumentOutOfRangeException ("Index of out range");
632 selected_index = value;
634 if (dropdown_style != ComboBoxStyle.DropDownList) {
635 if (value == -1)
636 SetControlText("");
637 else
638 SetControlText (GetItemText (Items [value]));
641 if (DropDownStyle == ComboBoxStyle.DropDownList)
642 Invalidate ();
644 if (listbox_ctrl != null)
645 listbox_ctrl.HighlightedIndex = value;
647 OnSelectedValueChanged (new EventArgs ());
648 OnSelectedIndexChanged (new EventArgs ());
649 OnSelectedItemChanged (new EventArgs ());
653 [Browsable (false)]
654 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
655 [Bindable(true)]
656 public object SelectedItem {
657 get { return selected_index == -1 ? null : Items [selected_index]; }
658 set {
659 object item = selected_index == -1 ? null : Items [selected_index];
660 if (item == value)
661 return;
662 SelectedIndex = Items.IndexOf (value);
666 [Browsable (false)]
667 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
668 public string SelectedText {
669 get {
670 if (dropdown_style == ComboBoxStyle.DropDownList)
671 return "";
673 return textbox_ctrl.SelectedText;
675 set {
676 if (dropdown_style == ComboBoxStyle.DropDownList)
677 return;
678 textbox_ctrl.SelectedText = value;
682 [Browsable (false)]
683 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
684 public int SelectionLength {
685 get {
686 if (dropdown_style == ComboBoxStyle.DropDownList)
687 return 0;
689 int result = textbox_ctrl.SelectionLength;
690 return result == -1 ? 0 : result;
692 set {
693 if (dropdown_style == ComboBoxStyle.DropDownList)
694 return;
695 if (textbox_ctrl.SelectionLength == value)
696 return;
697 textbox_ctrl.SelectionLength = value;
701 [Browsable (false)]
702 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
703 public int SelectionStart {
704 get {
705 if (dropdown_style == ComboBoxStyle.DropDownList)
706 return 0;
707 return textbox_ctrl.SelectionStart;
709 set {
710 if (dropdown_style == ComboBoxStyle.DropDownList)
711 return;
712 if (textbox_ctrl.SelectionStart == value)
713 return;
714 textbox_ctrl.SelectionStart = value;
718 [DefaultValue (false)]
719 public bool Sorted {
720 get { return sorted; }
721 set {
722 if (sorted == value)
723 return;
724 sorted = value;
725 SelectedIndex = -1;
726 if (sorted) {
727 Items.Sort ();
728 LayoutComboBox ();
733 [Bindable (true)]
734 [Localizable (true)]
735 public override string Text {
736 get {
737 if (dropdown_style != ComboBoxStyle.DropDownList) {
738 if (textbox_ctrl != null) {
739 return textbox_ctrl.Text;
743 if (SelectedItem != null)
744 return GetItemText (SelectedItem);
746 return base.Text;
748 set {
749 if (value == null) {
750 if (SelectedIndex == -1) {
751 if (dropdown_style != ComboBoxStyle.DropDownList)
752 SetControlText ("");
753 } else {
754 SelectedIndex = -1;
756 return;
759 // do nothing if value exactly matches text of selected item
760 if (SelectedItem != null && string.Compare (value, GetItemText (SelectedItem), false, CultureInfo.CurrentCulture) == 0)
761 return;
763 // find exact match using case-sensitive comparison, and if does
764 // not result in any match then use case-insensitive comparison
765 int index = FindStringExact (value, -1, false);
766 if (index == -1) {
767 index = FindStringExact (value, -1, true);
769 if (index != -1) {
770 SelectedIndex = index;
771 return;
774 if (dropdown_style != ComboBoxStyle.DropDownList)
775 textbox_ctrl.Text = GetItemText (value);
779 #endregion Public Properties
781 #region Public Methods
782 #if NET_2_0
783 [Obsolete ("This method has been deprecated")]
784 #endif
785 protected virtual void AddItemsCore (object[] value)
790 public void BeginUpdate ()
792 suspend_ctrlupdate = true;
795 #if NET_2_0
796 protected override AccessibleObject CreateAccessibilityInstance ()
798 return base.CreateAccessibilityInstance ();
801 protected override void CreateHandle ()
803 base.CreateHandle ();
805 #endif
807 protected override void Dispose (bool disposing)
809 if (disposing) {
810 if (listbox_ctrl != null) {
811 listbox_ctrl.Dispose ();
812 Controls.RemoveImplicit (listbox_ctrl);
813 listbox_ctrl = null;
816 if (textbox_ctrl != null) {
817 Controls.RemoveImplicit (textbox_ctrl);
818 textbox_ctrl.Dispose ();
819 textbox_ctrl = null;
823 base.Dispose (disposing);
826 public void EndUpdate ()
828 suspend_ctrlupdate = false;
829 UpdatedItems ();
830 Refresh ();
833 public int FindString (string s)
835 return FindString (s, -1);
838 public int FindString (string s, int startIndex)
840 if (s == null || Items.Count == 0)
841 return -1;
843 #if NET_2_0
844 if (startIndex < -1 || startIndex >= Items.Count)
845 #else
846 if (startIndex < -1 || startIndex >= Items.Count - 1)
847 #endif
848 throw new ArgumentOutOfRangeException ("startIndex");
850 int i = startIndex;
851 #if NET_2_0
852 if (i == (Items.Count - 1))
853 i = -1;
854 #endif
855 do {
856 i++;
857 if (string.Compare (s, 0, GetItemText (Items [i]), 0, s.Length, true) == 0)
858 return i;
859 if (i == (Items.Count - 1))
860 i = -1;
861 } while (i != startIndex);
863 return -1;
866 public int FindStringExact (string s)
868 return FindStringExact (s, -1);
871 public int FindStringExact (string s, int startIndex)
873 return FindStringExact (s, startIndex, true);
876 private int FindStringExact (string s, int startIndex, bool ignoreCase)
878 if (s == null || Items.Count == 0)
879 return -1;
881 #if NET_2_0
882 if (startIndex < -1 || startIndex >= Items.Count)
883 #else
884 if (startIndex < -1 || startIndex >= Items.Count - 1)
885 #endif
886 throw new ArgumentOutOfRangeException ("startIndex");
888 int i = startIndex;
889 #if NET_2_0
890 if (i == (Items.Count - 1))
891 i = -1;
892 #endif
893 do {
894 i++;
895 if (string.Compare (s, GetItemText (Items [i]), ignoreCase, CultureInfo.CurrentCulture) == 0)
896 return i;
897 if (i == (Items.Count - 1))
898 i = -1;
899 } while (i != startIndex);
901 return -1;
904 public int GetItemHeight (int index)
906 if (DrawMode == DrawMode.OwnerDrawVariable && IsHandleCreated) {
908 if (index < 0 || index >= Items.Count )
909 throw new ArgumentOutOfRangeException ("The item height value is less than zero");
911 object item = Items [index];
912 if (item_heights.Contains (item))
913 return (int) item_heights [item];
915 MeasureItemEventArgs args = new MeasureItemEventArgs (DeviceContext, index, ItemHeight);
916 OnMeasureItem (args);
917 item_heights [item] = args.ItemHeight;
918 return args.ItemHeight;
921 return ItemHeight;
924 protected override bool IsInputKey (Keys keyData)
926 switch (keyData) {
927 case Keys.Up:
928 case Keys.Down:
929 case Keys.Left:
930 case Keys.Right:
931 case Keys.PageUp:
932 case Keys.PageDown:
933 return true;
935 default:
936 return false;
940 protected override void OnBackColorChanged (EventArgs e)
942 base.OnBackColorChanged (e);
945 protected override void OnDataSourceChanged (EventArgs e)
947 base.OnDataSourceChanged (e);
948 BindDataItems ();
950 if (DataSource == null || DataManager == null) {
951 SelectedIndex = -1;
953 else {
954 SelectedIndex = DataManager.Position;
958 protected override void OnDisplayMemberChanged (EventArgs e)
960 base.OnDisplayMemberChanged (e);
962 if (DataManager == null || !IsHandleCreated)
963 return;
965 BindDataItems ();
966 SelectedIndex = DataManager.Position;
969 protected virtual void OnDrawItem (DrawItemEventArgs e)
971 switch (DrawMode) {
972 case DrawMode.OwnerDrawFixed:
973 case DrawMode.OwnerDrawVariable:
974 DrawItemEventHandler eh = (DrawItemEventHandler)(Events [DrawItemEvent]);
975 if (eh != null)
976 eh (this, e);
977 break;
978 default:
979 ThemeEngine.Current.DrawComboBoxItem (this, e);
980 break;
984 protected virtual void OnDropDown (EventArgs e)
986 EventHandler eh = (EventHandler)(Events [DropDownEvent]);
987 if (eh != null)
988 eh (this, e);
991 #if NET_2_0
992 protected virtual void OnDropDownClosed (EventArgs e)
994 EventHandler eh = (EventHandler) Events [DropDownClosedEvent];
995 if (eh != null)
996 eh (this, e);
998 #endif
1000 protected virtual void OnDropDownStyleChanged (EventArgs e)
1002 EventHandler eh = (EventHandler)(Events [DropDownStyleChangedEvent]);
1003 if (eh != null)
1004 eh (this, e);
1007 protected override void OnFontChanged (EventArgs e)
1009 base.OnFontChanged (e);
1011 if (textbox_ctrl != null)
1012 textbox_ctrl.Font = Font;
1014 if (!item_height_specified) {
1015 SizeF sz = DeviceContext.MeasureString ("The quick brown Fox", Font);
1016 item_height = (int) sz.Height;
1019 if (IntegralHeight)
1020 UpdateComboBoxBounds ();
1022 LayoutComboBox ();
1025 protected override void OnForeColorChanged (EventArgs e)
1027 base.OnForeColorChanged (e);
1030 [EditorBrowsable(EditorBrowsableState.Advanced)]
1031 protected override void OnGotFocus (EventArgs e)
1033 if (dropdown_style == ComboBoxStyle.DropDownList) {
1034 // We draw DDL styles manually, so they require a
1035 // refresh to have their selection drawn
1036 Invalidate ();
1039 if (textbox_ctrl != null) {
1040 textbox_ctrl.SetSelectable (false);
1041 textbox_ctrl.ShowSelection = true;
1042 textbox_ctrl.ActivateCaret (true);
1043 textbox_ctrl.SelectAll ();
1046 base.OnGotFocus (e);
1049 [EditorBrowsable(EditorBrowsableState.Advanced)]
1050 protected override void OnLostFocus (EventArgs e)
1052 if (dropdown_style == ComboBoxStyle.DropDownList) {
1053 // We draw DDL styles manually, so they require a
1054 // refresh to have their selection drawn
1055 Invalidate ();
1058 if (listbox_ctrl != null && dropped_down) {
1059 listbox_ctrl.HideWindow ();
1062 if (textbox_ctrl != null) {
1063 textbox_ctrl.SetSelectable (true);
1064 textbox_ctrl.ActivateCaret (false);
1065 textbox_ctrl.ShowSelection = false;
1068 base.OnLostFocus (e);
1071 protected override void OnHandleCreated (EventArgs e)
1073 base.OnHandleCreated (e);
1075 if (listbox_ctrl != null) {
1076 Controls.AddImplicit (listbox_ctrl);
1077 listbox_ctrl.Visible = true;
1080 if (textbox_ctrl != null)
1081 Controls.AddImplicit (textbox_ctrl);
1083 LayoutComboBox ();
1086 protected override void OnHandleDestroyed (EventArgs e)
1088 base.OnHandleDestroyed (e);
1091 protected override void OnKeyPress (KeyPressEventArgs e)
1093 // int index = FindStringCaseInsensitive (e.KeyChar.ToString (), SelectedIndex);
1094 //if (index != -1)
1095 // SelectedIndex = index;
1097 base.OnKeyPress (e);
1100 protected virtual void OnMeasureItem (MeasureItemEventArgs e)
1102 MeasureItemEventHandler eh = (MeasureItemEventHandler)(Events [MeasureItemEvent]);
1103 if (eh != null)
1104 eh (this, e);
1107 protected override void OnParentBackColorChanged (EventArgs e)
1109 base.OnParentBackColorChanged (e);
1112 protected override void OnResize (EventArgs e)
1114 LayoutComboBox ();
1115 if (listbox_ctrl != null)
1116 listbox_ctrl.CalcListBoxArea ();
1119 protected override void OnSelectedIndexChanged (EventArgs e)
1121 base.OnSelectedIndexChanged (e);
1123 EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]);
1124 if (eh != null)
1125 eh (this, e);
1128 protected virtual void OnSelectedItemChanged (EventArgs e)
1132 protected override void OnSelectedValueChanged (EventArgs e)
1134 base.OnSelectedValueChanged (e);
1137 protected virtual void OnSelectionChangeCommitted (EventArgs e)
1139 EventHandler eh = (EventHandler)(Events [SelectionChangeCommittedEvent]);
1140 if (eh != null)
1141 eh (this, e);
1144 protected override void RefreshItem (int index)
1146 if (index < 0 || index >= Items.Count)
1147 throw new ArgumentOutOfRangeException ("Index of out range");
1149 if (draw_mode == DrawMode.OwnerDrawVariable)
1150 item_heights.Remove (Items [index]);
1153 #if NET_2_0
1154 public override void ResetText ()
1156 Text = String.Empty;
1159 protected override bool ProcessKeyEventArgs (ref Message m)
1161 return base.ProcessKeyEventArgs (ref m);
1164 [EditorBrowsable (EditorBrowsableState.Advanced)]
1165 protected override void OnKeyDown (KeyEventArgs e)
1167 base.OnKeyDown (e);
1170 [EditorBrowsable (EditorBrowsableState.Advanced)]
1171 protected override void OnValidating (CancelEventArgs e)
1173 base.OnValidating (e);
1176 [EditorBrowsable (EditorBrowsableState.Advanced)]
1177 protected override void OnTextChanged (EventArgs e)
1179 base.OnTextChanged (e);
1182 #if NET_2_0
1183 protected virtual void OnTextUpdate (EventArgs e)
1185 EventHandler eh = (EventHandler) Events [TextUpdateEvent];
1186 if (eh != null)
1187 eh (this, e);
1189 #endif
1190 protected override void OnMouseLeave (EventArgs e)
1192 #if NET_2_0
1193 if (flat_style == FlatStyle.Popup)
1194 Invalidate ();
1195 #endif
1196 base.OnMouseLeave (e);
1199 protected override void OnMouseEnter (EventArgs e)
1201 #if NET_2_0
1202 if (flat_style == FlatStyle.Popup)
1203 Invalidate ();
1204 #endif
1205 base.OnMouseEnter (e);
1207 #endif
1209 public void Select (int start, int length)
1211 if (start < 0)
1212 throw new ArgumentException ("Start cannot be less than zero");
1214 if (length < 0)
1215 throw new ArgumentException ("length cannot be less than zero");
1217 if (dropdown_style == ComboBoxStyle.DropDownList)
1218 return;
1220 textbox_ctrl.Select (start, length);
1223 public void SelectAll ()
1225 if (dropdown_style == ComboBoxStyle.DropDownList)
1226 return;
1228 if (textbox_ctrl != null) {
1229 textbox_ctrl.ShowSelection = true;
1230 textbox_ctrl.SelectAll ();
1234 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
1236 if ((specified & BoundsSpecified.Height) != 0) {
1237 requested_height = height;
1239 if (DropDownStyle == ComboBoxStyle.Simple && height > PreferredHeight) {
1240 if (IntegralHeight) {
1241 int border = ThemeEngine.Current.Border3DSize.Height;
1242 int lb_height = height - PreferredHeight - 2;
1243 if (lb_height - 2 * border > ItemHeight) {
1244 int partial = (lb_height - 2 * border) % ItemHeight;
1245 height -= partial;
1246 } else
1247 height = PreferredHeight;
1249 } else
1250 height = PreferredHeight;
1253 base.SetBoundsCore (x, y, width, height, specified);
1256 protected override void SetItemCore (int index, object value)
1258 if (index < 0 || index >= Items.Count)
1259 return;
1261 Items[index] = value;
1264 protected override void SetItemsCore (IList value)
1266 BeginUpdate ();
1267 try {
1268 Items.Clear ();
1269 Items.AddRange (value);
1270 } finally {
1271 EndUpdate ();
1275 public override string ToString ()
1277 return base.ToString () + ", Items.Count:" + Items.Count;
1280 protected override void WndProc (ref Message m)
1282 switch ((Msg) m.Msg) {
1283 case Msg.WM_KEYUP:
1284 case Msg.WM_KEYDOWN:
1285 Keys keys = (Keys) m.WParam.ToInt32 ();
1286 if (keys == Keys.Up || keys == Keys.Down)
1287 break;
1288 goto case Msg.WM_CHAR;
1289 case Msg.WM_CHAR:
1290 if (textbox_ctrl != null)
1291 XplatUI.SendMessage (textbox_ctrl.Handle, (Msg) m.Msg, m.WParam, m.LParam);
1292 break;
1293 case Msg.WM_MOUSELEAVE:
1294 Point location = PointToClient (Control.MousePosition);
1295 if (ClientRectangle.Contains (location))
1296 return;
1297 break;
1298 default:
1299 break;
1301 base.WndProc (ref m);
1304 #endregion Public Methods
1306 #region Private Methods
1307 #if NET_2_0
1308 void OnAutoCompleteCustomSourceChanged(object sender, CollectionChangeEventArgs e) {
1309 if(auto_complete_source == AutoCompleteSource.CustomSource) {
1310 //FIXME: handle add, remove and refresh events in AutoComplete algorithm.
1313 #endif
1315 internal override bool InternalCapture {
1316 get { return Capture; }
1317 set {}
1320 void LayoutComboBox ()
1322 int border = ThemeEngine.Current.Border3DSize.Width;
1324 text_area = ClientRectangle;
1325 text_area.Height = PreferredHeight;
1327 listbox_area = ClientRectangle;
1328 listbox_area.Y = text_area.Bottom + 3;
1329 listbox_area.Height -= (text_area.Height + 2);
1331 Rectangle prev_button_area = button_area;
1333 if (DropDownStyle == ComboBoxStyle.Simple)
1334 button_area = Rectangle.Empty;
1335 else {
1336 button_area = text_area;
1337 button_area.X = text_area.Right - button_width - border;
1338 button_area.Y = text_area.Y + border;
1339 button_area.Width = button_width;
1340 button_area.Height = text_area.Height - 2 * border;
1341 #if NET_2_0
1342 if (flat_style == FlatStyle.Popup || flat_style == FlatStyle.Flat) {
1343 button_area.Inflate (1, 1);
1344 button_area.X += 2;
1345 button_area.Width -= 2;
1347 #endif
1350 if (button_area != prev_button_area) {
1351 prev_button_area.Y -= border;
1352 prev_button_area.Width += border;
1353 prev_button_area.Height += 2 * border;
1354 Invalidate (prev_button_area);
1355 Invalidate (button_area);
1358 if (textbox_ctrl != null) {
1359 textbox_ctrl.Location = new Point (text_area.X + border, text_area.Y + border);
1360 textbox_ctrl.Width = text_area.Width - button_area.Width - border * 2;
1361 textbox_ctrl.Height = text_area.Height - border * 2;
1364 if (listbox_ctrl != null && dropdown_style == ComboBoxStyle.Simple) {
1365 listbox_ctrl.Location = listbox_area.Location;
1366 listbox_ctrl.CalcListBoxArea ();
1370 private void CreateComboListBox ()
1372 listbox_ctrl = new ComboListBox (this);
1373 listbox_ctrl.HighlightedIndex = SelectedIndex;
1376 internal void Draw (Rectangle clip, Graphics dc)
1378 Theme theme = ThemeEngine.Current;
1379 FlatStyle style = FlatStyle.Standard;
1380 bool is_flat = false;
1382 #if NET_2_0
1383 style = this.FlatStyle;
1384 is_flat = style == FlatStyle.Flat || style == FlatStyle.Popup;
1385 #endif
1387 if (DropDownStyle == ComboBoxStyle.Simple)
1388 dc.FillRectangle (theme.ResPool.GetSolidBrush (Parent.BackColor), ClientRectangle);
1390 if (style == FlatStyle.Popup && (is_entered || Focused)) {
1391 Rectangle area = text_area;
1392 area.Height -= 1;
1393 area.Width -= 1;
1394 dc.DrawRectangle (theme.ResPool.GetPen (SystemColors.ControlDark), area);
1395 dc.DrawLine (theme.ResPool.GetPen (SystemColors.ControlDark), button_area.X - 1, button_area.Top, button_area.X - 1, button_area.Bottom);
1397 if (!is_flat && clip.IntersectsWith (text_area))
1398 ControlPaint.DrawBorder3D (dc, text_area, Border3DStyle.Sunken);
1400 int border = theme.Border3DSize.Width;
1402 // No edit control, we paint the edit ourselves
1403 if (dropdown_style == ComboBoxStyle.DropDownList) {
1404 DrawItemState state = DrawItemState.None;
1405 Rectangle item_rect = text_area;
1406 item_rect.X += border;
1407 item_rect.Y += border;
1408 item_rect.Width -= (button_area.Width + 2 * border);
1409 item_rect.Height -= 2 * border;
1411 if (Focused) {
1412 state = DrawItemState.Selected;
1413 state |= DrawItemState.Focus;
1416 state |= DrawItemState.ComboBoxEdit;
1417 OnDrawItem (new DrawItemEventArgs (dc, Font, item_rect, SelectedIndex, state, ForeColor, BackColor));
1420 if (show_dropdown_button) {
1421 dc.FillRectangle (theme.ResPool.GetSolidBrush (theme.ColorControl), button_area);
1423 if (!is_enabled)
1424 button_state = ButtonState.Inactive;
1426 if (is_flat) {
1427 theme.DrawFlatStyleComboButton (dc, button_area, button_state);
1428 } else {
1429 theme.CPDrawComboButton (dc, button_area, button_state);
1434 internal void DropDownListBox ()
1436 if (DropDownStyle == ComboBoxStyle.Simple)
1437 return;
1439 if (listbox_ctrl == null)
1440 CreateComboListBox ();
1442 listbox_ctrl.Location = PointToScreen (new Point (text_area.X, text_area.Y + text_area.Height));
1444 if (listbox_ctrl.ShowWindow ())
1445 dropped_down = true;
1447 button_state = ButtonState.Pushed;
1448 if (dropdown_style == ComboBoxStyle.DropDownList)
1449 Invalidate (text_area);
1452 internal void DropDownListBoxFinished ()
1454 if (DropDownStyle == ComboBoxStyle.Simple)
1455 return;
1457 button_state = ButtonState.Normal;
1458 Invalidate (button_area);
1459 dropped_down = false;
1460 #if NET_2_0
1461 OnDropDownClosed (EventArgs.Empty);
1462 #endif
1465 private int FindStringCaseInsensitive (string search)
1467 if (search.Length == 0) {
1468 return -1;
1471 for (int i = 0; i < Items.Count; i++)
1473 if (String.Compare (GetItemText (Items[i]), 0, search, 0, search.Length, true) == 0)
1474 return i;
1477 return -1;
1480 internal int FindStringCaseInsensitive (string search, int start_index)
1482 if (search.Length == 0) {
1483 return -1;
1486 for (int i = 0; i < Items.Count; i++) {
1487 int index = (i + start_index) % Items.Count;
1488 if (String.Compare (GetItemText (Items [index]), 0, search, 0, search.Length, true) == 0)
1489 return index;
1492 return -1;
1495 private void OnKeyDownCB(object sender, KeyEventArgs e)
1497 if (Items.Count == 0)
1498 return;
1500 switch (e.KeyCode)
1502 case Keys.Up:
1503 SelectedIndex = Math.Max(SelectedIndex-1, 0);
1504 break;
1506 case Keys.Down:
1507 SelectedIndex = Math.Min(SelectedIndex+1, Items.Count-1);
1508 break;
1510 case Keys.PageUp:
1511 if (listbox_ctrl != null)
1512 SelectedIndex = Math.Max(SelectedIndex- (listbox_ctrl.page_size-1), 0);
1513 break;
1515 case Keys.PageDown:
1516 if (listbox_ctrl != null)
1517 SelectedIndex = Math.Min(SelectedIndex+(listbox_ctrl.page_size-1), Items.Count-1);
1518 break;
1520 default:
1521 break;
1525 void OnMouseDownCB (object sender, MouseEventArgs e)
1527 Rectangle area;
1528 if (DropDownStyle == ComboBoxStyle.DropDownList)
1529 area = ClientRectangle;
1530 else
1531 area = button_area;
1533 if (area.Contains (e.X, e.Y)) {
1534 DropDownListBox ();
1535 Invalidate (button_area);
1536 Update ();
1538 Capture = true;
1541 void OnMouseMoveCB (object sender, MouseEventArgs e)
1543 if (DropDownStyle == ComboBoxStyle.Simple)
1544 return;
1546 if (listbox_ctrl != null && listbox_ctrl.Visible) {
1547 Point location = listbox_ctrl.PointToClient (Control.MousePosition);
1548 if (listbox_ctrl.ClientRectangle.Contains (location))
1549 listbox_ctrl.Capture = true;
1553 void OnMouseUpCB (object sender, MouseEventArgs e)
1555 Capture = false;
1556 OnClick (EventArgs.Empty);
1558 if (dropped_down)
1559 listbox_ctrl.Capture = true;
1562 private void OnMouseWheelCB (object sender, MouseEventArgs me)
1564 if (Items.Count == 0)
1565 return;
1567 if (listbox_ctrl != null && listbox_ctrl.Visible) {
1568 int lines = me.Delta / 120 * SystemInformation.MouseWheelScrollLines;
1569 listbox_ctrl.Scroll (-lines);
1570 } else {
1571 int lines = me.Delta / 120;
1572 int index = SelectedIndex - lines;
1573 if (index < 0)
1574 index = 0;
1575 else if (index >= Items.Count)
1576 index = Items.Count - 1;
1577 SelectedIndex = index;
1581 internal override void OnPaintInternal (PaintEventArgs pevent)
1583 if (suspend_ctrlupdate)
1584 return;
1586 Draw (ClientRectangle, pevent.Graphics);
1589 private void OnTextBoxClick (object sender, EventArgs e)
1591 OnClick (e);
1594 private void OnTextChangedEdit (object sender, EventArgs e)
1596 if (process_textchanged_event == false)
1597 return;
1599 OnTextChanged (EventArgs.Empty);
1601 int item = FindStringCaseInsensitive (textbox_ctrl.Text);
1603 if (item == -1)
1604 return;
1606 // TODO: THIS IS BROKEN-ISH
1607 // I don't think we should hilight, and setting the top item does weirdness
1608 // when there is no scrollbar
1610 if (listbox_ctrl != null) {
1611 listbox_ctrl.SetTopItem (item);
1612 listbox_ctrl.HighlightedIndex = item;
1615 base.Text = textbox_ctrl.Text;
1618 internal void SetControlText (string s)
1620 process_textchanged_event = false;
1621 textbox_ctrl.Text = s;
1622 process_textchanged_event = true;
1625 void UpdateComboBoxBounds ()
1627 if (requested_height == -1)
1628 return;
1630 // Save the requested height since set bounds can destroy it
1631 int save_height = requested_height;
1632 SetBounds (0, 0, 0, requested_height, BoundsSpecified.Height);
1633 requested_height = save_height;
1636 private void UpdatedItems ()
1638 if (listbox_ctrl != null) {
1639 listbox_ctrl.UpdateLastVisibleItem ();
1640 listbox_ctrl.CalcListBoxArea ();
1641 listbox_ctrl.Refresh ();
1645 #endregion Private Methods
1647 [ListBindableAttribute (false)]
1648 public class ObjectCollection : IList, ICollection, IEnumerable
1651 private ComboBox owner;
1652 internal ArrayList object_items = new ArrayList ();
1654 public ObjectCollection (ComboBox owner)
1656 this.owner = owner;
1659 #region Public Properties
1660 public int Count {
1661 get { return object_items.Count; }
1664 public bool IsReadOnly {
1665 get { return false; }
1668 [Browsable (false)]
1669 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
1670 public virtual object this [int index] {
1671 get {
1672 if (index < 0 || index >= Count)
1673 throw new ArgumentOutOfRangeException ("Index of out range");
1675 return object_items[index];
1677 set {
1678 if (index < 0 || index >= Count)
1679 throw new ArgumentOutOfRangeException ("Index of out range");
1680 if (value == null)
1681 throw new ArgumentNullException ("value");
1683 object_items[index] = value;
1684 if (owner.listbox_ctrl != null)
1685 owner.listbox_ctrl.InvalidateItem (index);
1686 if (index == owner.SelectedIndex) {
1687 if (owner.textbox_ctrl == null)
1688 owner.Refresh ();
1689 else
1690 owner.textbox_ctrl.SelectedText = value.ToString ();
1695 bool ICollection.IsSynchronized {
1696 get { return false; }
1699 object ICollection.SyncRoot {
1700 get { return this; }
1703 bool IList.IsFixedSize {
1704 get { return false; }
1707 #endregion Public Properties
1709 #region Public Methods
1710 public int Add (object item)
1712 int idx;
1714 idx = AddItem (item);
1715 owner.UpdatedItems ();
1716 return idx;
1719 public void AddRange (object[] items)
1721 if (items == null)
1722 throw new ArgumentNullException ("items");
1724 foreach (object mi in items)
1725 AddItem (mi);
1727 owner.UpdatedItems ();
1730 public void Clear ()
1732 owner.selected_index = -1;
1733 object_items.Clear ();
1734 owner.UpdatedItems ();
1735 owner.Refresh ();
1738 public bool Contains (object value)
1740 if (value == null)
1741 throw new ArgumentNullException ("value");
1743 return object_items.Contains (value);
1746 public void CopyTo (object[] dest, int arrayIndex)
1748 object_items.CopyTo (dest, arrayIndex);
1751 void ICollection.CopyTo (Array dest, int index)
1753 object_items.CopyTo (dest, index);
1756 public IEnumerator GetEnumerator ()
1758 return object_items.GetEnumerator ();
1761 int IList.Add (object item)
1763 return Add (item);
1766 public int IndexOf (object value)
1768 if (value == null)
1769 throw new ArgumentNullException ("value");
1771 return object_items.IndexOf (value);
1774 public void Insert (int index, object item)
1776 if (index < 0 || index > Count)
1777 throw new ArgumentOutOfRangeException ("Index of out range");
1778 if (item == null)
1779 throw new ArgumentNullException ("item");
1781 owner.BeginUpdate ();
1783 if (owner.Sorted)
1784 AddItem (item);
1785 else
1786 object_items.Insert (index, item);
1788 owner.EndUpdate (); // Calls UpdatedItems
1791 public void Remove (object value)
1793 if (value == null)
1794 return;
1796 if (IndexOf (value) == owner.SelectedIndex)
1797 owner.SelectedIndex = -1;
1799 RemoveAt (IndexOf (value));
1802 public void RemoveAt (int index)
1804 if (index < 0 || index >= Count)
1805 throw new ArgumentOutOfRangeException ("Index of out range");
1807 if (index == owner.SelectedIndex)
1808 owner.SelectedIndex = -1;
1810 object_items.RemoveAt (index);
1811 owner.UpdatedItems ();
1813 #endregion Public Methods
1815 #region Private Methods
1816 private int AddItem (object item)
1818 if (item == null)
1819 throw new ArgumentNullException ("item");
1821 if (owner.Sorted) {
1822 int index = 0;
1823 foreach (object o in object_items) {
1824 if (String.Compare (item.ToString (), o.ToString ()) < 0) {
1825 object_items.Insert (index, item);
1826 return index;
1828 index++;
1831 object_items.Add (item);
1832 return object_items.Count - 1;
1835 internal void AddRange (IList items)
1837 foreach (object mi in items)
1838 AddItem (mi);
1840 owner.UpdatedItems ();
1843 internal void Sort ()
1845 object_items.Sort ();
1848 #endregion Private Methods
1851 internal class ComboTextBox : TextBox {
1853 private ComboBox owner;
1855 public ComboTextBox (ComboBox owner)
1857 this.owner = owner;
1858 ShowSelection = false;
1861 internal void SetSelectable (bool selectable)
1863 SetStyle (ControlStyles.Selectable, selectable);
1866 internal void ActivateCaret (bool active)
1868 if (active)
1869 document.CaretHasFocus ();
1870 else
1871 document.CaretLostFocus ();
1874 #if NET_2_0
1875 internal override void OnTextUpdate ()
1877 base.OnTextUpdate ();
1878 owner.OnTextUpdate (EventArgs.Empty);
1880 #endif
1882 protected override void OnGotFocus (EventArgs e)
1884 owner.Select (false, true);
1887 protected override void OnLostFocus (EventArgs e)
1889 owner.Select (false, true);
1893 internal class ComboListBox : Control
1895 private ComboBox owner;
1896 private VScrollBarLB vscrollbar_ctrl;
1897 private int top_item; /* First item that we show the in the current page */
1898 private int last_item; /* Last visible item */
1899 internal int page_size; /* Number of listbox items per page */
1900 private Rectangle textarea_drawable; /* Rectangle of the drawable text area */
1902 internal enum ItemNavigation
1904 First,
1905 Last,
1906 Next,
1907 Previous,
1908 NextPage,
1909 PreviousPage,
1912 class VScrollBarLB : VScrollBar
1914 public VScrollBarLB ()
1918 internal override bool InternalCapture {
1919 get { return Capture; }
1920 set { }
1923 public void FireMouseDown (MouseEventArgs e)
1925 if (!Visible)
1926 return;
1928 e = TranslateEvent (e);
1929 OnMouseDown (e);
1932 public void FireMouseUp (MouseEventArgs e)
1934 if (!Visible)
1935 return;
1937 e = TranslateEvent (e);
1938 OnMouseUp (e);
1941 public void FireMouseMove (MouseEventArgs e)
1943 if (!Visible)
1944 return;
1946 e = TranslateEvent (e);
1947 OnMouseMove (e);
1950 MouseEventArgs TranslateEvent (MouseEventArgs e)
1952 Point loc = PointToClient (Control.MousePosition);
1953 return new MouseEventArgs (e.Button, e.Clicks, loc.X, loc.Y, e.Delta);
1957 public ComboListBox (ComboBox owner)
1959 this.owner = owner;
1960 top_item = 0;
1961 last_item = 0;
1962 page_size = 0;
1964 MouseWheel += new MouseEventHandler (OnMouseWheelCLB);
1966 SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
1967 SetStyle (ControlStyles.ResizeRedraw | ControlStyles.Opaque, true);
1969 this.is_visible = false;
1971 if (owner.DropDownStyle == ComboBoxStyle.Simple)
1972 InternalBorderStyle = BorderStyle.Fixed3D;
1973 else
1974 InternalBorderStyle = BorderStyle.FixedSingle;
1977 protected override CreateParams CreateParams
1979 get {
1980 CreateParams cp = base.CreateParams;
1981 if (owner == null || owner.DropDownStyle == ComboBoxStyle.Simple)
1982 return cp;
1984 cp.Style ^= (int) WindowStyles.WS_CHILD;
1985 cp.Style |= (int) WindowStyles.WS_POPUP;
1986 cp.ExStyle |= (int) WindowExStyles.WS_EX_TOOLWINDOW | (int) WindowExStyles.WS_EX_TOPMOST;
1987 return cp;
1991 protected override void Select (bool directed, bool forward)
1993 // Do nothing, we never want to be selected
1996 internal override bool InternalCapture {
1997 get {
1998 return Capture;
2001 set {
2005 internal override bool ActivateOnShow { get { return false; } }
2006 #region Private Methods
2008 // Calcs the listbox area
2009 internal void CalcListBoxArea ()
2011 int width, height;
2012 bool show_scrollbar = false;
2014 if (owner.DropDownStyle == ComboBoxStyle.Simple) {
2015 Rectangle area = owner.listbox_area;
2016 width = area.Width;
2017 height = area.Height;
2019 else { // DropDown or DropDownList
2021 width = owner.DropDownWidth;
2022 int count = (owner.Items.Count <= owner.MaxDropDownItems) ? owner.Items.Count : owner.MaxDropDownItems;
2024 if (owner.DrawMode == DrawMode.OwnerDrawVariable) {
2025 height = 0;
2026 for (int i = 0; i < count; i++) {
2027 height += owner.GetItemHeight (i);
2030 } else {
2031 #if NET_2_0
2032 height = owner.DropDownHeight;
2033 #else
2034 height = owner.ItemHeight * count;
2035 #endif
2039 page_size = height / owner.ItemHeight;
2041 if (owner.Items.Count <= owner.MaxDropDownItems) {
2042 if (vscrollbar_ctrl != null)
2043 vscrollbar_ctrl.Visible = false;
2044 } else {
2045 /* Need vertical scrollbar */
2046 if (vscrollbar_ctrl == null) {
2047 vscrollbar_ctrl = new VScrollBarLB ();
2048 vscrollbar_ctrl.Minimum = 0;
2049 vscrollbar_ctrl.SmallChange = 1;
2050 vscrollbar_ctrl.LargeChange = 1;
2051 vscrollbar_ctrl.Maximum = 0;
2052 vscrollbar_ctrl.ValueChanged += new EventHandler (VerticalScrollEvent);
2053 Controls.AddImplicit (vscrollbar_ctrl);
2056 vscrollbar_ctrl.Dock = DockStyle.Right;
2058 vscrollbar_ctrl.Maximum = owner.Items.Count - 2;
2059 int large = (owner.DropDownStyle == ComboBoxStyle.Simple ? page_size : owner.maxdrop_items) - 1;
2060 if (large < 0)
2061 large = 0;
2062 vscrollbar_ctrl.LargeChange = large;
2063 show_scrollbar = vscrollbar_ctrl.Visible = true;
2065 int hli = HighlightedIndex;
2066 if (hli > 0) {
2067 hli = Math.Min (hli, vscrollbar_ctrl.Maximum);
2068 vscrollbar_ctrl.Value = hli;
2072 Size = new Size (width, height);
2073 textarea_drawable = ClientRectangle;
2074 textarea_drawable.Width = width;
2075 textarea_drawable.Height = height;
2077 if (vscrollbar_ctrl != null && show_scrollbar)
2078 textarea_drawable.Width -= vscrollbar_ctrl.Width;
2080 last_item = LastVisibleItem ();
2083 private void Draw (Rectangle clip, Graphics dc)
2085 dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (owner.BackColor), clip);
2087 if (owner.Items.Count > 0) {
2089 for (int i = top_item; i <= last_item; i++) {
2090 Rectangle item_rect = GetItemDisplayRectangle (i, top_item);
2092 if (!clip.IntersectsWith (item_rect))
2093 continue;
2095 DrawItemState state = DrawItemState.None;
2097 if (i == HighlightedIndex) {
2098 state |= DrawItemState.Selected;
2100 if (owner.DropDownStyle == ComboBoxStyle.DropDownList) {
2101 state |= DrawItemState.Focus;
2105 owner.OnDrawItem (new DrawItemEventArgs (dc, owner.Font, item_rect,
2106 i, state, owner.ForeColor, owner.BackColor));
2111 int highlighted_index = -1;
2113 public int HighlightedIndex {
2114 get { return highlighted_index; }
2115 set {
2116 if (highlighted_index == value)
2117 return;
2119 if (highlighted_index != -1 && highlighted_index < this.owner.Items.Count)
2120 Invalidate (GetItemDisplayRectangle (highlighted_index, top_item));
2121 highlighted_index = value;
2122 if (highlighted_index != -1)
2123 Invalidate (GetItemDisplayRectangle (highlighted_index, top_item));
2127 private Rectangle GetItemDisplayRectangle (int index, int top_index)
2129 if (index < 0 || index >= owner.Items.Count)
2130 throw new ArgumentOutOfRangeException ("GetItemRectangle index out of range.");
2132 Rectangle item_rect = new Rectangle ();
2133 int height = owner.GetItemHeight (index);
2135 item_rect.X = 0;
2136 item_rect.Width = textarea_drawable.Width;
2137 if (owner.DrawMode == DrawMode.OwnerDrawVariable) {
2138 item_rect.Y = 0;
2139 for (int i = top_index; i < index; i++)
2140 item_rect.Y += owner.GetItemHeight (i);
2141 } else
2142 item_rect.Y = height * (index - top_index);
2144 item_rect.Height = height;
2145 return item_rect;
2148 public void HideWindow ()
2150 if (owner.DropDownStyle == ComboBoxStyle.Simple)
2151 return;
2153 Capture = false;
2154 Hide ();
2155 owner.DropDownListBoxFinished ();
2158 private int IndexFromPointDisplayRectangle (int x, int y)
2160 for (int i = top_item; i <= last_item; i++) {
2161 if (GetItemDisplayRectangle (i, top_item).Contains (x, y) == true)
2162 return i;
2165 return -1;
2168 public void InvalidateItem (int index)
2170 if (Visible)
2171 Invalidate (GetItemDisplayRectangle (index, top_item));
2174 private int LastVisibleItem ()
2176 Rectangle item_rect;
2177 int top_y = textarea_drawable.Y + textarea_drawable.Height;
2178 int i = 0;
2180 for (i = top_item; i < owner.Items.Count; i++) {
2181 item_rect = GetItemDisplayRectangle (i, top_item);
2182 if (item_rect.Y + item_rect.Height > top_y) {
2183 return i;
2186 return i - 1;
2189 public void SetTopItem (int item)
2191 if (top_item == item)
2192 return;
2193 top_item = item;
2194 UpdateLastVisibleItem ();
2195 Invalidate ();
2198 bool scrollbar_grabbed = false;
2200 bool InScrollBar {
2201 get {
2202 if (vscrollbar_ctrl == null || !vscrollbar_ctrl.is_visible)
2203 return false;
2205 return vscrollbar_ctrl.Bounds.Contains (PointToClient (Control.MousePosition));
2209 protected override void OnMouseDown (MouseEventArgs e)
2211 if (InScrollBar) {
2212 vscrollbar_ctrl.FireMouseDown (e);
2213 scrollbar_grabbed = true;
2217 protected override void OnMouseMove (MouseEventArgs e)
2219 if (owner.DropDownStyle == ComboBoxStyle.Simple)
2220 return;
2222 if (scrollbar_grabbed || (!Capture && InScrollBar)) {
2223 vscrollbar_ctrl.FireMouseMove (e);
2224 return;
2227 Point pt = PointToClient (Control.MousePosition);
2228 int index = IndexFromPointDisplayRectangle (pt.X, pt.Y);
2230 if (index != -1)
2231 HighlightedIndex = index;
2234 protected override void OnMouseUp (MouseEventArgs e)
2236 int index = IndexFromPointDisplayRectangle (e.X, e.Y);
2238 if (scrollbar_grabbed) {
2239 vscrollbar_ctrl.FireMouseUp (e);
2240 scrollbar_grabbed = false;
2241 if (index != -1)
2242 HighlightedIndex = index;
2243 return;
2246 if (index == -1) {
2247 HideWindow ();
2248 return;
2251 owner.SelectedIndex = index;
2252 owner.OnSelectionChangeCommitted (new EventArgs ());
2253 HideWindow ();
2256 internal override void OnPaintInternal (PaintEventArgs pevent)
2258 Draw (pevent.ClipRectangle,pevent.Graphics);
2261 public bool ShowWindow ()
2263 if (owner.DropDownStyle == ComboBoxStyle.Simple && owner.Items.Count == 0)
2264 return false;
2266 HighlightedIndex = owner.SelectedIndex;
2268 CalcListBoxArea ();
2269 Show ();
2271 Refresh ();
2272 owner.OnDropDown (EventArgs.Empty);
2273 return true;
2276 public void UpdateLastVisibleItem ()
2278 last_item = LastVisibleItem ();
2281 public void Scroll (int delta)
2283 if (delta == 0 || vscrollbar_ctrl == null || !vscrollbar_ctrl.Visible)
2284 return;
2286 int max = owner.Items.Count - page_size;
2288 int val = vscrollbar_ctrl.Value + delta;
2289 if (val > max)
2290 val = max;
2291 else if (val < vscrollbar_ctrl.Minimum)
2292 val = vscrollbar_ctrl.Minimum;
2293 vscrollbar_ctrl.Value = val;
2296 private void OnMouseWheelCLB (object sender, MouseEventArgs me)
2298 if (owner.Items.Count == 0)
2299 return;
2301 int lines = me.Delta / 120 * SystemInformation.MouseWheelScrollLines;
2302 Scroll (-lines);
2305 // Value Changed
2306 private void VerticalScrollEvent (object sender, EventArgs e)
2308 if (top_item == vscrollbar_ctrl.Value)
2309 return;
2311 top_item = vscrollbar_ctrl.Value;
2312 UpdateLastVisibleItem ();
2313 Invalidate ();
2316 protected override void WndProc(ref Message m) {
2317 if (m.Msg == (int)Msg.WM_SETFOCUS) {
2318 if (m.WParam != IntPtr.Zero) {
2319 XplatUI.SetFocus(m.WParam);
2322 base.WndProc (ref m);
2325 #endregion Private Methods