New test.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ComboBox.cs
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.
11 //
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.
19 //
20 // Copyright (c) 2004-2006 Novell, Inc.
21 //
22 // Authors:
23 //      Jordi Mas i Hernandez, jordi@ximian.com
24 //      Mike Kestner  <mkestner@novell.com>
25 //
26 // NOT COMPLETE
27
28 using System;
29 using System.Drawing;
30 using System.Collections;
31 using System.ComponentModel;
32 using System.Reflection;
33 using System.ComponentModel.Design;
34 using System.ComponentModel.Design.Serialization;
35 using System.Runtime.InteropServices;
36
37
38 namespace System.Windows.Forms
39 {
40
41         [DefaultProperty("Items")]
42         [DefaultEvent("SelectedIndexChanged")]
43         [Designer ("System.Windows.Forms.Design.ComboBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
44         public class ComboBox : ListControl
45         {
46                 private DrawMode draw_mode = DrawMode.Normal;
47                 private ComboBoxStyle dropdown_style = (ComboBoxStyle)(-1);
48                 private int dropdown_width = -1;                
49                 private int selected_index = -1;
50                 internal ObjectCollection items = null;
51                 private bool suspend_ctrlupdate;
52                 private int maxdrop_items = 8;                  
53                 private bool integral_height = true;
54                 private bool sorted;
55                 private int max_length;
56                 private ComboListBox listbox_ctrl;              
57                 private ComboTextBox textbox_ctrl;
58                 private bool process_textchanged_event = true;
59                 private bool item_height_specified = false;
60                 private int item_height;
61                 private int requested_height = -1;
62                 private Hashtable item_heights;
63                 private bool show_dropdown_button = false;
64                 private ButtonState button_state = ButtonState.Normal;
65                 private bool dropped_down;
66                 private Rectangle text_area;
67                 private Rectangle button_area;
68                 private Rectangle listbox_area;
69                 private const int button_width = 16;
70
71                 [ComVisible(true)]
72                 public class ChildAccessibleObject : AccessibleObject {
73                         private ComboBox        owner;
74                         private IntPtr          handle;
75
76                         public ChildAccessibleObject (ComboBox owner, IntPtr handle) {
77                                 this.owner = owner;
78                                 this.handle = handle;
79                         }
80
81                         public override string Name {
82                                 get {
83                                         return base.Name;
84                                 }
85                         }
86                 }
87
88                 public ComboBox ()
89                 {
90                         items = new ObjectCollection (this);
91                         DropDownStyle = ComboBoxStyle.DropDown;
92                         item_height = FontHeight + 2;
93                         BackColor = ThemeEngine.Current.ColorWindow;
94                         border_style = BorderStyle.None;
95
96                         /* Events */
97                         MouseDown += new MouseEventHandler (OnMouseDownCB);
98                         MouseUp += new MouseEventHandler (OnMouseUpCB);
99                         MouseMove += new MouseEventHandler (OnMouseMoveCB);
100                         MouseWheel += new MouseEventHandler (OnMouseWheelCB);                           
101                         KeyDown +=new KeyEventHandler(OnKeyDownCB);
102                 }
103
104                 #region events
105                 
106                 [Browsable (false)]
107                 [EditorBrowsable (EditorBrowsableState.Never)]
108                 public new event EventHandler BackgroundImageChanged {
109                         add { base.BackgroundImageChanged += value; }
110                         remove { base.BackgroundImageChanged -= value; }
111                 }
112                 
113                 public event DrawItemEventHandler DrawItem;             
114                 public event EventHandler DropDown;             
115                 public event EventHandler DropDownStyleChanged;         
116                 public event MeasureItemEventHandler MeasureItem;
117                 
118                 [Browsable (false)]
119                 [EditorBrowsable (EditorBrowsableState.Never)]
120                 public new event PaintEventHandler Paint {
121                         add { base.Paint += value; }
122                         remove { base.Paint -= value; }
123                 }
124                 
125                 public event EventHandler SelectedIndexChanged;         
126                 public event EventHandler SelectionChangeCommitted;
127                 #endregion Events
128
129                 #region Public Properties
130                 public override Color BackColor {
131                         get { return base.BackColor; }
132                         set {
133                                 if (base.BackColor == value)
134                                         return;
135
136                                 base.BackColor = value;
137                                 Refresh ();
138                         }
139                 }
140
141                 [Browsable (false)]
142                 [EditorBrowsable (EditorBrowsableState.Never)]
143                 public override Image BackgroundImage {
144                         get { return base.BackgroundImage; }
145                         set {
146                                 if (base.BackgroundImage == value)
147                                         return;
148
149                                 base.BackgroundImage = value;
150                                 Refresh ();
151                         }
152                 }
153
154                 protected override CreateParams CreateParams {
155                         get { return base.CreateParams;}
156                 }
157
158                 protected override Size DefaultSize {
159                         get { return new Size (121, 21); }
160                 }
161
162                 [RefreshProperties(RefreshProperties.Repaint)]
163                 [DefaultValue (DrawMode.Normal)]
164                 public DrawMode DrawMode {
165                         get { return draw_mode; }
166
167                         set {
168                                 if (!Enum.IsDefined (typeof (DrawMode), value))
169                                         throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for DrawMode", value));
170
171                                 if (draw_mode == value)
172                                         return;
173
174                                 if (draw_mode == DrawMode.OwnerDrawVariable)
175                                         item_heights = null;
176                                 draw_mode = value;
177                                 if (draw_mode == DrawMode.OwnerDrawVariable)
178                                         item_heights = new Hashtable ();
179                                 Refresh ();
180                         }
181                 }
182
183                 [DefaultValue (ComboBoxStyle.DropDown)]
184                 [RefreshProperties(RefreshProperties.Repaint)]
185                 public ComboBoxStyle DropDownStyle {
186                         get { return dropdown_style; }
187
188                         set {
189                 
190                                 if (!Enum.IsDefined (typeof (ComboBoxStyle), value))
191                                         throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for ComboBoxStyle", value));
192
193                                 if (dropdown_style == value)
194                                         return;                                 
195                                                                         
196                                 if (dropdown_style == ComboBoxStyle.Simple) {
197                                         if (listbox_ctrl != null) {                                             
198                                                 Controls.RemoveImplicit (listbox_ctrl);
199                                                 listbox_ctrl.Dispose ();                                                
200                                                 listbox_ctrl = null;
201                                         }
202                                 }
203
204                                 dropdown_style = value;                                 
205                                 
206                                 if (dropdown_style == ComboBoxStyle.DropDownList && textbox_ctrl != null) {
207                                         Controls.RemoveImplicit (textbox_ctrl);
208                                         textbox_ctrl.Dispose ();                                                
209                                         textbox_ctrl = null;                                            
210                                 }                               
211
212                                 if (dropdown_style == ComboBoxStyle.Simple) {
213                                         show_dropdown_button = false;                                   
214                                         
215                                         CreateComboListBox ();
216
217                                         if (IsHandleCreated)
218                                                 Controls.AddImplicit (listbox_ctrl);
219                                 } else {
220                                         show_dropdown_button = true;
221                                         button_state = ButtonState.Normal;
222                                 }                               
223         
224                                 if (dropdown_style != ComboBoxStyle.DropDownList && textbox_ctrl == null) {
225                                         textbox_ctrl = new ComboTextBox (this);
226                                         object selected_item = SelectedItem;
227                                         if (selected_item != null)
228                                                 textbox_ctrl.Text = GetItemText (selected_item);
229                                         textbox_ctrl.BorderStyle = BorderStyle.None;
230                                         textbox_ctrl.TextChanged += new EventHandler (OnTextChangedEdit);
231                                         textbox_ctrl.Click += new EventHandler (OnTextBoxClick);
232
233                                         if (IsHandleCreated == true) {
234                                                 Controls.AddImplicit (textbox_ctrl);
235                                         }
236                                 }
237                                 
238                                 OnDropDownStyleChanged (EventArgs.Empty);
239                                 
240                                 Layout ();
241                                 UpdateBounds ();
242                                 Refresh ();
243                         }
244                 }
245
246                 public int DropDownWidth {
247                         get { 
248                                 if (dropdown_width == -1)
249                                         return Width;
250                                         
251                                 return dropdown_width; 
252                         }
253                         set {
254                                 if (dropdown_width == value)
255                                         return;
256                                         
257                                 if (value < 1)
258                                         throw new ArgumentException ("The DropDownWidth value is less than one");
259
260                                 dropdown_width = value;                         
261                         }
262                 }
263                 
264                 [Browsable (false)]
265                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]              
266                 public bool DroppedDown {
267                         get { 
268                                 if (dropdown_style == ComboBoxStyle.Simple)                             
269                                         return true;
270                                 
271                                 return dropped_down;
272                         }
273                         set {
274                                 if (dropdown_style == ComboBoxStyle.Simple || dropped_down == value)
275                                         return;
276                                         
277                                 if (value) 
278                                         DropDownListBox ();
279                                 else
280                                         listbox_ctrl.Hide ();
281                         }
282                 }               
283
284                 public override bool Focused {
285                         get { return base.Focused; }
286                 }
287
288                 public override Color ForeColor {
289                         get { return base.ForeColor; }
290                         set {
291                                 if (base.ForeColor == value)
292                                         return;
293
294                                 base.ForeColor = value;
295                                 Refresh ();
296                         }
297                 }
298
299                 [DefaultValue (true)]
300                 [Localizable (true)]            
301                 public bool IntegralHeight {
302                         get { return integral_height; }
303                         set {
304                                 if (integral_height == value)
305                                         return;
306
307                                 integral_height = value;
308                                 UpdateBounds ();
309                                 Refresh ();
310                         }
311                 }
312
313                 [Localizable (true)]
314                 public int ItemHeight {
315                         get {
316                                 if (item_height == -1) {
317                                         SizeF sz = DeviceContext.MeasureString ("The quick brown Fox", Font);
318                                         item_height = (int) sz.Height;
319                                 }
320                                 return item_height;
321                         }
322                         set {
323                                 if (value < 0)
324                                         throw new ArgumentException ("The item height value is less than zero");
325
326                                 item_height_specified = true;
327                                 item_height = value;
328                                 if (IntegralHeight)
329                                         UpdateBounds ();
330                                 Layout ();
331                                 Refresh ();
332                         }
333                 }
334
335                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
336                 [Localizable (true)]
337                 [Editor ("System.Windows.Forms.Design.ListControlStringCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]                
338                 public ComboBox.ObjectCollection Items {
339                         get { return items; }
340                 }
341
342                 [DefaultValue (8)]
343                 [Localizable (true)]
344                 public int MaxDropDownItems {
345                         get { return maxdrop_items; }
346                         set {
347                                 if (maxdrop_items == value)
348                                         return;
349
350                                 maxdrop_items = value;
351                         }
352                 }
353
354                 [DefaultValue (0)]
355                 [Localizable (true)]
356                 public int MaxLength {
357                         get { return max_length; }
358                         set {
359                                 if (max_length == value)
360                                         return;
361
362                                 max_length = value;
363                                 
364                                 if (dropdown_style != ComboBoxStyle.DropDownList) {
365                                         
366                                         if (value < 0) {
367                                                 value = 0;
368                                         }
369                                         
370                                         textbox_ctrl.MaxLength = value;
371                                 }                       
372                         }
373                 }
374
375                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
376                 [Browsable (false)]             
377                 public int PreferredHeight {
378                         get {
379                                 return ItemHeight + 5;
380                         }
381                 }
382
383                 [Browsable (false)]
384                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
385                 public override int SelectedIndex {
386                         get { return selected_index; }
387                         set {
388                                 if (value <= -2 || value >= Items.Count)
389                                         throw new ArgumentOutOfRangeException ("Index of out range");
390                                 selected_index = value;
391
392                                 if (dropdown_style != ComboBoxStyle.DropDownList) {
393                                         if (value == -1)
394                                                 SetControlText("");
395                                         else
396                                                 SetControlText (GetItemText (Items [value]));
397                                 }
398
399                                 OnSelectedValueChanged (new EventArgs ());
400                                 OnSelectedIndexChanged  (new EventArgs ());
401                                 OnSelectedItemChanged (new EventArgs ());
402                                 if (DropDownStyle == ComboBoxStyle.DropDownList)
403                                         Invalidate ();
404
405                                 if (listbox_ctrl != null)
406                                         listbox_ctrl.HighlightedIndex = value;
407                         }
408                 }
409
410                 [Browsable (false)]
411                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
412                 [Bindable(true)]
413                 public object SelectedItem {
414                         get { return selected_index == -1 ? null : Items [selected_index]; }
415                         set {                           
416                                 object item = selected_index == -1 ? null : Items [selected_index];
417                                 if (item == value)
418                                         return;
419
420                                 SelectedIndex = Items.IndexOf (value);
421                         }
422                 }
423                 
424                 [Browsable (false)]
425                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
426                 public string SelectedText {
427                         get {
428                                 if (dropdown_style == ComboBoxStyle.DropDownList)
429                                         return "";
430                                         
431                                 return textbox_ctrl.SelectedText;
432                         }
433                         set {
434                                 if (dropdown_style == ComboBoxStyle.DropDownList)
435                                         return;
436                                 
437                                 textbox_ctrl.SelectedText = value;
438                         }
439                 }
440
441                 [Browsable (false)]
442                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
443                 public int SelectionLength {
444                         get {
445                                 if (dropdown_style == ComboBoxStyle.DropDownList) 
446                                         return 0;
447                                 
448                                 return textbox_ctrl.SelectionLength;
449                         }
450                         set {
451                                 if (dropdown_style == ComboBoxStyle.DropDownList) 
452                                         return;
453                                         
454                                 if (textbox_ctrl.SelectionLength == value)
455                                         return;
456                                         
457                                 textbox_ctrl.SelectionLength = value;
458                         }
459                 }
460
461                 [Browsable (false)]
462                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
463                 public int SelectionStart {
464                         get { 
465                                 if (dropdown_style == ComboBoxStyle.DropDownList) 
466                                         return 0;                                       
467                                 
468                                 return textbox_ctrl.SelectionStart;                             
469                         }
470                         set {
471                                 if (dropdown_style == ComboBoxStyle.DropDownList) 
472                                         return;
473                                 
474                                 if (textbox_ctrl.SelectionStart == value)
475                                         return;                                 
476                                 
477                                 textbox_ctrl.SelectionStart = value;
478                         }
479                 }
480
481                 [DefaultValue (false)]
482                 public bool Sorted {
483                         get { return sorted; }
484
485                         set {
486                                 if (sorted == value)
487                                         return;
488
489                                 sorted = value;
490                                 SelectedIndex = -1;
491                                 if (sorted) {
492                                         Items.Sort ();
493                                         Layout ();
494                                 }
495                         }
496                 }
497
498                 [Bindable (true)]
499                 [Localizable (true)]
500                 public override string Text {
501                         get {
502                                 if (dropdown_style != ComboBoxStyle.DropDownList) {
503                                         if (textbox_ctrl != null) {
504                                                 return textbox_ctrl.Text;
505                                         }
506                                 }
507
508                                 if (SelectedItem != null)
509                                         return GetItemText (SelectedItem);
510                                                                 
511                                 return base.Text;                               
512                         }
513                         set {                           
514                                 if (value == null) {
515                                         SelectedIndex = -1;
516                                         return;
517                                 }
518                                 
519                                 int index = FindString (value);
520                                 
521                                 if (index != -1) {
522                                         SelectedIndex = index;
523                                         return;                                 
524                                 }
525                                 
526                                 if (dropdown_style != ComboBoxStyle.DropDownList)
527                                         textbox_ctrl.Text = GetItemText (value);
528                         }
529                 }
530
531                 #endregion Public Properties
532
533                 #region Public Methods
534                 protected virtual void AddItemsCore (object[] value)
535                 {
536                         
537                 }
538
539                 public void BeginUpdate ()
540                 {
541                         suspend_ctrlupdate = true;
542                 }
543
544                 protected override void Dispose (bool disposing)
545                 {                                               
546                         if (disposing) {
547                                 if (listbox_ctrl != null) {
548                                         listbox_ctrl.Dispose ();
549                                         Controls.RemoveImplicit (listbox_ctrl);
550                                         listbox_ctrl = null;
551                                 }                       
552                         
553                                 if (textbox_ctrl != null) {
554                                         Controls.RemoveImplicit (textbox_ctrl);
555                                         textbox_ctrl.Dispose ();
556                                         textbox_ctrl = null;
557                                 }                       
558                         }
559                         
560                         base.Dispose (disposing);
561                 }
562
563                 public void EndUpdate ()
564                 {
565                         suspend_ctrlupdate = false;
566                         UpdatedItems ();
567                         Refresh ();
568                 }
569
570                 public int FindString (string s)
571                 {
572                         return FindString (s, -1);
573                 }
574
575                 public int FindString (string s, int startIndex)
576                 {
577                         if (Items.Count == 0) 
578                                 return -1; // No exception throwing if empty
579
580                         if (startIndex < -1 || startIndex >= Items.Count - 1)
581                                 throw new  ArgumentOutOfRangeException ("Index of out range");
582
583                         startIndex++;
584                         for (int i = startIndex; i < Items.Count; i++) {
585                                 if ((GetItemText (Items[i])).StartsWith (s))
586                                         return i;
587                         }
588
589                         return -1;
590                 }
591
592                 public int FindStringExact (string s)
593                 {
594                         return FindStringExact (s, -1);
595                 }
596
597                 public int FindStringExact (string s, int startIndex)
598                 {
599                         if (Items.Count == 0) 
600                                 return -1; // No exception throwing if empty
601
602                         if (startIndex < -1 || startIndex >= Items.Count - 1)
603                                 throw new ArgumentOutOfRangeException ("Index of out range");
604
605                         startIndex++;
606                         for (int i = startIndex; i < Items.Count; i++) {
607                                 if ((GetItemText (Items[i])).Equals (s))
608                                         return i;
609                         }
610
611                         return -1;
612                 }
613
614                 public int GetItemHeight (int index)
615                 {       
616                         if (DrawMode == DrawMode.OwnerDrawVariable && IsHandleCreated) {
617
618                                 if (index < 0 || index >= Items.Count )
619                                         throw new ArgumentOutOfRangeException ("The item height value is less than zero");
620                                 
621                                 object item = Items [index];
622                                 if (item_heights.Contains (item))
623                                         return (int) item_heights [item];
624                                 
625                                 MeasureItemEventArgs args = new MeasureItemEventArgs (DeviceContext, index, ItemHeight);
626                                 OnMeasureItem (args);
627                                 item_heights [item] = args.ItemHeight;
628                                 return args.ItemHeight;
629                         }
630
631                         return ItemHeight;
632                 }
633
634                 protected override bool IsInputKey (Keys keyData)
635                 {
636                         switch (keyData) {
637                         case Keys.Up:
638                         case Keys.Down:
639                         case Keys.Left:
640                         case Keys.Right:
641                         case Keys.PageUp:
642                         case Keys.PageDown:                     
643                                 return true;
644                         
645                         default:                                        
646                                 return false;
647                         }
648                 }
649
650                 protected override void OnBackColorChanged (EventArgs e)
651                 {
652                         base.OnBackColorChanged (e);
653                 }
654
655                 protected override void OnDataSourceChanged (EventArgs e)
656                 {
657                         base.OnDataSourceChanged (e);
658                         BindDataItems ();
659                         
660                         if (DataSource == null || DataManager == null) {
661                                 SelectedIndex = -1;
662                         } 
663                         else {
664                                 SelectedIndex = DataManager.Position;
665                         }
666                 }
667
668                 protected override void OnDisplayMemberChanged (EventArgs e)
669                 {
670                         base.OnDisplayMemberChanged (e);
671
672                         if (DataManager == null || !IsHandleCreated)
673                                return;
674
675                         BindDataItems ();
676                         SelectedIndex = DataManager.Position;
677                 }
678
679                 protected virtual void OnDrawItem (DrawItemEventArgs e)
680                 {
681                         switch (DrawMode) {
682                         case DrawMode.OwnerDrawFixed:
683                         case DrawMode.OwnerDrawVariable:
684                                 if (DrawItem != null)
685                                         DrawItem (this, e);
686                                 break;
687                         default:
688                                 ThemeEngine.Current.DrawComboBoxItem (this, e);
689                                 break;
690                         }
691                 }               
692
693                 protected virtual void OnDropDown (EventArgs e)
694                 {
695                         if (DropDown != null)
696                                 DropDown (this, e);
697                 }
698
699                 protected virtual void OnDropDownStyleChanged (EventArgs e)
700                 {
701                         if (DropDownStyleChanged != null)
702                                 DropDownStyleChanged (this, e);
703                 }
704
705                 protected override void OnFontChanged (EventArgs e)
706                 {
707                         base.OnFontChanged (e);
708
709                         if (textbox_ctrl != null)
710                                 textbox_ctrl.Font = Font;
711                         
712                         if (!item_height_specified) {
713                                 SizeF sz = DeviceContext.MeasureString ("The quick brown Fox", Font);
714                                 item_height = (int) sz.Height;
715                         }
716
717                         if (IntegralHeight)
718                                 UpdateBounds ();
719
720                         Layout ();
721                 }
722
723                 protected override void OnForeColorChanged (EventArgs e)
724                 {
725                         base.OnForeColorChanged (e);
726                 }
727
728                 [EditorBrowsable(EditorBrowsableState.Advanced)]                
729                 protected override void OnGotFocus (EventArgs e)
730                 {
731                         if (dropdown_style == ComboBoxStyle.DropDownList) {
732                                 // We draw DDL styles manually, so they require a
733                                 // refresh to have their selection drawn
734                                 Invalidate ();
735                         }
736                         
737                         if (textbox_ctrl != null) {
738                                 textbox_ctrl.SetSelectable (false);
739                                 textbox_ctrl.ActivateCaret (true);
740                                 textbox_ctrl.ShowSelection = true;
741                                 textbox_ctrl.SelectAll ();
742                         }
743
744                         base.OnGotFocus (e);
745                 }
746
747                 [EditorBrowsable(EditorBrowsableState.Advanced)]                
748                 protected override void OnLostFocus (EventArgs e)
749                 {
750                         if (dropdown_style == ComboBoxStyle.DropDownList) {
751                                 // We draw DDL styles manually, so they require a
752                                 // refresh to have their selection drawn
753                                 Invalidate ();
754                         }
755
756                         if (listbox_ctrl != null && dropped_down) {
757                                 listbox_ctrl.HideWindow ();
758                         }
759
760                         if (textbox_ctrl != null) {
761                                 textbox_ctrl.SetSelectable (true);
762                                 textbox_ctrl.ActivateCaret (false);
763                                 textbox_ctrl.ShowSelection = false;
764                         }
765
766                         base.OnLostFocus (e);
767                 }
768
769                 protected override void OnHandleCreated (EventArgs e)
770                 {
771                         base.OnHandleCreated (e);
772
773                         if (listbox_ctrl != null)
774                                 Controls.AddImplicit (listbox_ctrl);
775                         
776                         if (textbox_ctrl != null)
777                                 Controls.AddImplicit (textbox_ctrl);
778
779                         Layout ();
780                 }
781
782                 protected override void OnHandleDestroyed (EventArgs e)
783                 {
784                         base.OnHandleDestroyed (e);
785                 }
786
787                 protected override void OnKeyPress (KeyPressEventArgs e)
788                 {
789                         // int index = FindStringCaseInsensitive (e.KeyChar.ToString (), SelectedIndex);
790                         //if (index != -1)
791                         //      SelectedIndex = index;
792
793                         base.OnKeyPress (e);
794                 }
795
796                 protected virtual void OnMeasureItem (MeasureItemEventArgs e)
797                 {
798                         if (MeasureItem != null)
799                                 MeasureItem (this, e);
800                 }
801
802                 protected override void OnParentBackColorChanged (EventArgs e)
803                 {
804                         base.OnParentBackColorChanged (e);
805                 }
806
807                 protected override void OnResize (EventArgs e)
808                 {                       
809                         Layout ();
810                         if (listbox_ctrl != null)
811                                 listbox_ctrl.CalcListBoxArea ();
812                 }
813
814                 protected override void OnSelectedIndexChanged (EventArgs e)
815                 {
816                         base.OnSelectedIndexChanged (e);
817
818                         if (SelectedIndexChanged != null)
819                                 SelectedIndexChanged (this, e);
820                 }
821
822                 protected virtual void OnSelectedItemChanged (EventArgs e)
823                 {
824                         
825                 }
826
827                 protected override void OnSelectedValueChanged (EventArgs e)
828                 {
829                         base.OnSelectedValueChanged (e);
830                 }
831
832                 protected virtual void OnSelectionChangeCommitted (EventArgs e)
833                 {
834                         if (SelectionChangeCommitted != null)
835                                 SelectionChangeCommitted (this, e);
836                 }
837
838                 protected override void RefreshItem (int index)
839                 {
840                         if (index < 0 || index >= Items.Count)
841                                 throw new ArgumentOutOfRangeException ("Index of out range");
842                                 
843                         if (draw_mode == DrawMode.OwnerDrawVariable)
844                                 item_heights.Remove (Items [index]);
845                 }
846
847                 public void Select (int start, int length)
848                 {
849                         if (start < 0)
850                                 throw new ArgumentException ("Start cannot be less than zero");
851                                 
852                         if (length < 0)
853                                 throw new ArgumentException ("length cannot be less than zero");
854                                 
855                         if (dropdown_style == ComboBoxStyle.DropDownList)
856                                 return;
857
858                         textbox_ctrl.Select (start, length);
859                 }
860
861                 public void SelectAll ()
862                 {
863                         if (dropdown_style == ComboBoxStyle.DropDownList)
864                                 return;
865
866                         if (textbox_ctrl != null) {
867                                 textbox_ctrl.ShowSelection = true;
868                                 textbox_ctrl.SelectAll ();
869                         }
870                 }               
871
872                 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
873                 {                       
874                         if ((specified & BoundsSpecified.Height) != 0) {
875                                 requested_height = height;
876
877                                 if (DropDownStyle == ComboBoxStyle.Simple && height > PreferredHeight) {
878                                         if (IntegralHeight) {
879                                                 int border = ThemeEngine.Current.Border3DSize.Height;
880                                                 int lb_height = height - PreferredHeight - 2;
881                                                 if (lb_height - 2 * border > ItemHeight) {
882                                                         int partial = (lb_height - 2 * border) % ItemHeight;
883                                                         height -= partial;
884                                                 } else
885                                                         height = PreferredHeight;
886                                         }
887                                 } else
888                                         height = PreferredHeight;
889                         }
890
891                         base.SetBoundsCore (x, y, width, height, specified);
892                 }
893
894                 protected override void SetItemCore (int index, object value)
895                 {
896                         if (index < 0 || index >= Items.Count)
897                                 return;
898
899                         Items[index] = value;
900                 }
901
902                 protected override void SetItemsCore (IList value)
903                 {
904                         BeginUpdate ();
905                         try {
906                                 Items.Clear ();
907                                 Items.AddRange (value);
908                         } finally {
909                                EndUpdate ();
910                         }
911                 }
912
913                 public override string ToString ()
914                 {
915                         return base.ToString () + ", Items.Count:" + Items.Count;
916                 }
917
918                 protected override void WndProc (ref Message m)
919                 {
920                         switch ((Msg) m.Msg) {
921                         case Msg.WM_KEYUP:
922                         case Msg.WM_KEYDOWN:
923                                 Keys keys = (Keys) m.WParam.ToInt32 ();
924                                 if (keys == Keys.Up || keys == Keys.Down)
925                                         break;
926                                 goto case Msg.WM_CHAR;
927                         case Msg.WM_CHAR:
928                                 if (textbox_ctrl != null)
929                                         XplatUI.SendMessage (textbox_ctrl.Handle, (Msg) m.Msg, m.WParam, m.LParam);
930                                 break;
931                         case Msg.WM_MOUSE_LEAVE:
932                                 Point location = PointToClient (Control.MousePosition);
933                                 if (ClientRectangle.Contains (location))
934                                         return;
935                                 break;
936                         default:
937                                 break;
938                         }
939                         base.WndProc (ref m);
940                 }
941
942                 #endregion Public Methods
943
944                 #region Private Methods
945
946                 internal override bool InternalCapture {
947                         get { return Capture; }
948                         set {}
949                 }
950                 
951                 void Layout ()
952                 {                       
953                         int border = ThemeEngine.Current.Border3DSize.Width;
954
955                         text_area = ClientRectangle;
956                         text_area.Height = PreferredHeight;
957                         
958                         listbox_area = ClientRectangle;
959                         listbox_area.Y = text_area.Bottom + 3;
960                         listbox_area.Height -= (text_area.Height + 2);
961
962                         Rectangle prev_button_area = button_area;
963
964                         if (DropDownStyle == ComboBoxStyle.Simple)
965                                 button_area = Rectangle.Empty;
966                         else {
967                                 button_area = text_area;
968                                 button_area.X = text_area.Right - button_width - border;
969                                 button_area.Y = text_area.Y + border;
970                                 button_area.Width = button_width;
971                                 button_area.Height = text_area.Height - 2 * border;
972                         }
973
974                         if (button_area != prev_button_area) {
975                                 prev_button_area.Y -= border;
976                                 prev_button_area.Width += border;
977                                 prev_button_area.Height += 2 * border;
978                                 Invalidate (prev_button_area);
979                                 Invalidate (button_area);
980                         }
981
982                         if (textbox_ctrl != null) {
983                                 textbox_ctrl.Location = new Point (text_area.X + border, text_area.Y + border);
984                                 textbox_ctrl.Width = text_area.Width - button_area.Width - border * 2;
985                                 textbox_ctrl.Height = text_area.Height - border * 2;
986                         }
987
988                         if (listbox_ctrl != null && dropdown_style == ComboBoxStyle.Simple) {
989                                 listbox_ctrl.Location = listbox_area.Location;
990                                 listbox_ctrl.CalcListBoxArea ();
991                         }
992                 }
993
994                 private void CreateComboListBox ()
995                 {                       
996                         listbox_ctrl = new ComboListBox (this);                 
997                         listbox_ctrl.HighlightedIndex = SelectedIndex;
998                 }
999                 
1000                 internal void Draw (Rectangle clip, Graphics dc)
1001                 {                               
1002                         Theme theme = ThemeEngine.Current;
1003
1004                         if (DropDownStyle == ComboBoxStyle.Simple)
1005                                 dc.FillRectangle (theme.ResPool.GetSolidBrush (Parent.BackColor), ClientRectangle);
1006
1007                         if (clip.IntersectsWith (text_area))
1008                                 ControlPaint.DrawBorder3D (dc, text_area, Border3DStyle.Sunken);
1009
1010                         int border = theme.Border3DSize.Width;
1011
1012                         // No edit control, we paint the edit ourselves
1013                         if (dropdown_style == ComboBoxStyle.DropDownList) {
1014                                 DrawItemState state = DrawItemState.None;
1015                                 Rectangle item_rect = text_area;
1016                                 item_rect.X += border;
1017                                 item_rect.Y += border;
1018                                 item_rect.Width -= (button_area.Width + 2 * border);                            
1019                                 item_rect.Height -= 2 * border;                         
1020                                                                 
1021                                 if (Focused) {
1022                                         state = DrawItemState.Selected;
1023                                         state |= DrawItemState.Focus;
1024                                 }
1025                                 
1026                                 state |= DrawItemState.ComboBoxEdit;                            
1027                                 OnDrawItem (new DrawItemEventArgs (dc, Font, item_rect, SelectedIndex, state, ForeColor, BackColor));
1028                         }                                               
1029                         
1030                         if (show_dropdown_button) {
1031                                 dc.FillRectangle (theme.ResPool.GetSolidBrush (theme.ColorControl), button_area);
1032
1033                                 if (!is_enabled)
1034                                         button_state = ButtonState.Inactive;
1035                                 
1036                                 theme.CPDrawComboButton (dc, button_area, button_state);
1037                         }                       
1038                 }
1039
1040                 internal void DropDownListBox ()
1041                 {
1042                         if (DropDownStyle == ComboBoxStyle.Simple)
1043                                 return;                 
1044                         
1045                         if (listbox_ctrl == null)
1046                                 CreateComboListBox ();
1047
1048                         listbox_ctrl.Location = PointToScreen (new Point (text_area.X, text_area.Y + text_area.Height));
1049                                                 
1050                         if (listbox_ctrl.ShowWindow ())                                 
1051                                 dropped_down = true;                                    
1052                         
1053                         button_state = ButtonState.Pushed;                              
1054                         if (dropdown_style == ComboBoxStyle.DropDownList)
1055                                 Invalidate (text_area);
1056
1057                         OnDropDown (EventArgs.Empty);
1058                 }
1059                 
1060                 internal void DropDownListBoxFinished ()
1061                 {
1062                         if (DropDownStyle == ComboBoxStyle.Simple)
1063                                 return;                 
1064                                 
1065                         button_state = ButtonState.Normal;
1066                         Invalidate (button_area);
1067                         dropped_down = false;
1068                 }
1069                 
1070                 private int FindStringCaseInsensitive (string search)
1071                 {                       
1072                         if (search.Length == 0) {
1073                                 return -1;
1074                         }
1075                         
1076                         for (int i = 0; i < Items.Count; i++) 
1077                         {                               
1078                                 if (String.Compare (GetItemText (Items[i]), 0, search, 0, search.Length, true) == 0)
1079                                         return i;
1080                         }
1081
1082                         return -1;
1083                 }
1084
1085                 internal int FindStringCaseInsensitive (string search, int start_index)
1086                 {
1087                         if (search.Length == 0) {
1088                                 return -1;
1089                         }
1090
1091                         for (int i = 0; i < Items.Count; i++) {
1092                                 int index = (i + start_index) % Items.Count;
1093                                 if (String.Compare (GetItemText (Items [index]), 0, search, 0, search.Length, true) == 0)
1094                                         return index;
1095                         }
1096
1097                         return -1;
1098                 }
1099
1100                 private void OnKeyDownCB(object sender, KeyEventArgs e)
1101                 {
1102                         if (Items.Count == 0)
1103                                 return;
1104
1105                         switch (e.KeyCode) 
1106                         {                       
1107                                 case Keys.Up:
1108                                         SelectedIndex = Math.Max(SelectedIndex-1, 0);
1109                                         break;                          
1110         
1111                                 case Keys.Down:
1112                                         SelectedIndex = Math.Min(SelectedIndex+1, Items.Count-1);
1113                                         break;
1114                                 
1115                                 case Keys.PageUp:
1116                                         if (listbox_ctrl != null)
1117                                                 SelectedIndex = Math.Max(SelectedIndex- (listbox_ctrl.page_size-1), 0);
1118                                         break;                          
1119         
1120                                 case Keys.PageDown:             
1121                                         if (listbox_ctrl != null)               
1122                                                 SelectedIndex = Math.Min(SelectedIndex+(listbox_ctrl.page_size-1), Items.Count-1);
1123                                         break;
1124                                 
1125                                 default:
1126                                         break;
1127                         }
1128                 }
1129                 
1130                 void OnMouseDownCB (object sender, MouseEventArgs e)
1131                 {
1132                         Rectangle area;
1133                         if (DropDownStyle == ComboBoxStyle.DropDownList)
1134                                 area = ClientRectangle;
1135                         else
1136                                 area = button_area;
1137
1138                         if (area.Contains (e.X, e.Y)) {
1139                                 DropDownListBox ();                                     
1140                                 Invalidate (button_area);
1141                                 Update ();
1142                         }
1143                         Capture = true;
1144                 }
1145
1146                 void OnMouseMoveCB (object sender, MouseEventArgs e)
1147                 {                       
1148                         if (DropDownStyle == ComboBoxStyle.Simple)
1149                                 return;
1150
1151                         if (listbox_ctrl != null && listbox_ctrl.Visible) {
1152                                 Point location = listbox_ctrl.PointToClient (Control.MousePosition);
1153                                 if (listbox_ctrl.ClientRectangle.Contains (location))
1154                                         listbox_ctrl.Capture = true;
1155                         }
1156                 }
1157
1158                 void OnMouseUpCB (object sender, MouseEventArgs e)
1159                 {
1160                         Capture = false;
1161                         OnClick (EventArgs.Empty);
1162
1163                         if (dropped_down)
1164                                 listbox_ctrl.Capture = true;
1165                 }
1166
1167                 private void OnMouseWheelCB (object sender, MouseEventArgs me)
1168                 {
1169                         if (Items.Count == 0)
1170                                 return;
1171
1172                         if (listbox_ctrl != null && listbox_ctrl.Visible) {
1173                                 int lines = me.Delta / 120 * SystemInformation.MouseWheelScrollLines;
1174                                 listbox_ctrl.Scroll (-lines);
1175                         } else {
1176                                 int lines = me.Delta / 120;
1177                                 int index = SelectedIndex - lines;
1178                                 if (index < 0)
1179                                         index = 0;
1180                                 else if (index >= Items.Count)
1181                                         index = Items.Count - 1;
1182                                 SelectedIndex = index;
1183                         }
1184                 }
1185
1186                 internal override void OnPaintInternal (PaintEventArgs pevent)
1187                 {
1188                         if (suspend_ctrlupdate)
1189                                 return;
1190                                 
1191                         Draw (ClientRectangle, pevent.Graphics);                        
1192                 }
1193                 
1194                 private void OnTextBoxClick (object sender, EventArgs e)
1195                 {
1196                         OnClick (e);
1197                 }
1198
1199                 private void OnTextChangedEdit (object sender, EventArgs e)
1200                 {
1201                         if (process_textchanged_event == false)
1202                                 return; 
1203                                 
1204                         OnTextChanged (EventArgs.Empty);
1205
1206                         int item = FindStringCaseInsensitive (textbox_ctrl.Text);
1207                         
1208                         if (item == -1)
1209                                 return;
1210
1211                         // TODO:  THIS IS BROKEN-ISH
1212                         // I don't think we should hilight, and setting the top item does weirdness
1213                         // when there is no scrollbar
1214                         
1215                         if (listbox_ctrl != null) {
1216                                 listbox_ctrl.SetTopItem (item);
1217                                 listbox_ctrl.HighlightedIndex = item;
1218                         }
1219
1220                         base.Text = textbox_ctrl.Text;
1221                 }
1222                 
1223                 internal void SetControlText (string s)
1224                 {               
1225                         process_textchanged_event = false;
1226                         textbox_ctrl.Text = s;
1227                         process_textchanged_event = true;
1228                 }
1229                 
1230                 void UpdateBounds ()
1231                 {
1232                         if (requested_height != -1)
1233                                 SetBounds (0, 0, 0, requested_height, BoundsSpecified.Height);
1234                 }
1235
1236                 private void UpdatedItems ()
1237                 {
1238                         if (listbox_ctrl != null) {
1239                                 listbox_ctrl.UpdateLastVisibleItem ();
1240                                 listbox_ctrl.CalcListBoxArea ();
1241                                 listbox_ctrl.Refresh ();
1242                         }
1243                 }
1244
1245                 #endregion Private Methods
1246
1247                 [ListBindableAttribute (false)]
1248                 public class ObjectCollection : IList, ICollection, IEnumerable
1249                 {
1250
1251                         private ComboBox owner;
1252                         internal ArrayList object_items = new ArrayList ();
1253
1254                         public ObjectCollection (ComboBox owner)
1255                         {
1256                                 this.owner = owner;
1257                         }
1258
1259                         #region Public Properties
1260                         public int Count {
1261                                 get { return object_items.Count; }
1262                         }
1263
1264                         public bool IsReadOnly {
1265                                 get { return false; }
1266                         }
1267
1268                         [Browsable (false)]
1269                         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
1270                         public virtual object this [int index] {
1271                                 get {
1272                                         if (index < 0 || index >= Count)
1273                                                 throw new ArgumentOutOfRangeException ("Index of out range");
1274
1275                                         return object_items[index];
1276                                 }
1277                                 set {
1278                                         if (index < 0 || index >= Count)
1279                                                 throw new ArgumentOutOfRangeException ("Index of out range");
1280                                         if (value == null)
1281                                                 throw new ArgumentNullException ("value");
1282
1283                                         object_items[index] = value;
1284                                         if (owner.listbox_ctrl != null)
1285                                                 owner.listbox_ctrl.InvalidateItem (index);
1286                                         if (index == owner.SelectedIndex) {
1287                                                 if (owner.textbox_ctrl == null)
1288                                                         owner.Refresh ();
1289                                                 else
1290                                                         owner.textbox_ctrl.SelectedText = value.ToString ();
1291                                         }
1292                                 }
1293                         }
1294
1295                         bool ICollection.IsSynchronized {
1296                                 get { return false; }
1297                         }
1298
1299                         object ICollection.SyncRoot {
1300                                 get { return this; }
1301                         }
1302
1303                         bool IList.IsFixedSize {
1304                                 get { return false; }
1305                         }
1306
1307                         #endregion Public Properties
1308                         
1309                         #region Public Methods
1310                         public int Add (object item)
1311                         {
1312                                 int idx;
1313
1314                                 idx = AddItem (item);
1315                                 owner.UpdatedItems ();
1316                                 return idx;
1317                         }
1318
1319                         public void AddRange (object[] items)
1320                         {
1321                                 if (items == null)
1322                                         throw new ArgumentNullException ("items");
1323
1324                                 foreach (object mi in items)
1325                                         AddItem (mi);
1326                                         
1327                                 owner.UpdatedItems ();
1328                         }
1329
1330                         public void Clear ()
1331                         {
1332                                 owner.selected_index = -1;
1333                                 object_items.Clear ();
1334                                 owner.UpdatedItems ();
1335                                 owner.Refresh ();
1336                         }
1337                         
1338                         public bool Contains (object obj)
1339                         {
1340                                 if (obj == null)
1341                                         throw new ArgumentNullException ("obj");
1342
1343                                 return object_items.Contains (obj);
1344                         }
1345
1346                         public void CopyTo (object[] dest, int arrayIndex)
1347                         {
1348                                 object_items.CopyTo (dest, arrayIndex);
1349                         }
1350
1351                         void ICollection.CopyTo (Array dest, int index)
1352                         {
1353                                 object_items.CopyTo (dest, index);
1354                         }
1355
1356                         public IEnumerator GetEnumerator ()
1357                         {
1358                                 return object_items.GetEnumerator ();
1359                         }
1360
1361                         int IList.Add (object item)
1362                         {
1363                                 return Add (item);
1364                         }
1365
1366                         public int IndexOf (object value)
1367                         {
1368                                 if (value == null)
1369                                         throw new ArgumentNullException ("value");
1370
1371                                 return object_items.IndexOf (value);
1372                         }
1373
1374                         public void Insert (int index,  object item)
1375                         {
1376                                 if (index < 0 || index > Count)
1377                                         throw new ArgumentOutOfRangeException ("Index of out range");                                   
1378                                 if (item == null)
1379                                         throw new ArgumentNullException ("item");
1380                                 
1381                                 owner.BeginUpdate ();
1382                                 
1383                                 if (owner.Sorted)
1384                                         AddItem (item);
1385                                 else
1386                                         object_items.Insert (index, item);
1387                                                                                                 
1388                                 owner.EndUpdate ();     // Calls UpdatedItems
1389                         }
1390
1391                         public void Remove (object value)
1392                         {                               
1393                                 if (value == null)
1394                                         return;
1395
1396                                 if (IndexOf (value) == owner.SelectedIndex)
1397                                         owner.SelectedIndex = -1;
1398                                 
1399                                 RemoveAt (IndexOf (value));                             
1400                         }
1401
1402                         public void RemoveAt (int index)
1403                         {
1404                                 if (index < 0 || index >= Count)
1405                                         throw new ArgumentOutOfRangeException ("Index of out range");
1406                                         
1407                                 if (index == owner.SelectedIndex)
1408                                         owner.SelectedIndex = -1;
1409
1410                                 object_items.RemoveAt (index);
1411                                 owner.UpdatedItems ();
1412                         }
1413                         #endregion Public Methods
1414
1415                         #region Private Methods
1416                         private int AddItem (object item)
1417                         {
1418                                 if (item == null)
1419                                         throw new ArgumentNullException ("item");
1420
1421                                 if (owner.Sorted) {
1422                                         int index = 0;
1423                                         foreach (string s in object_items) {
1424                                                 if (String.Compare (item as String, s) < 0) {
1425                                                         object_items.Insert (index, item);
1426                                                         return index;
1427                                                 }
1428                                                 index++;
1429                                         }
1430                                 }
1431                                 object_items.Add (item);
1432                                 return object_items.Count - 1;
1433                         }
1434                         
1435                         internal void AddRange (IList items)
1436                         {
1437                                 foreach (object mi in items)
1438                                         AddItem (mi);
1439                                                                                 
1440                                 owner.UpdatedItems ();
1441                         }
1442
1443                         internal void Sort ()
1444                         {
1445                                 object_items.Sort ();
1446                         }
1447
1448                         #endregion Private Methods
1449                 }
1450
1451                 internal class ComboTextBox : TextBox {
1452
1453                         private ComboBox owner;
1454
1455                         public ComboTextBox (ComboBox owner)
1456                         {
1457                                 this.owner = owner;
1458                                 ShowSelection = false;
1459                         }
1460
1461                         internal void SetSelectable (bool selectable)
1462                         {
1463                                 SetStyle (ControlStyles.Selectable, selectable);
1464                         }
1465
1466                         internal void ActivateCaret (bool active)
1467                         {
1468                                 if (active)
1469                                         document.CaretHasFocus ();
1470                                 else
1471                                         document.CaretLostFocus ();
1472                         }
1473
1474                         internal override void OnGotFocusInternal (EventArgs e)
1475                         {
1476                                 owner.Select (false, true);
1477                         }
1478
1479                         internal override void OnLostFocusInternal (EventArgs e)
1480                         {
1481                                 owner.Select (false, true);
1482                         }                       
1483                 }
1484
1485                 internal class ComboListBox : Control
1486                 {
1487                         private ComboBox owner;                 
1488                         private VScrollBarLB vscrollbar_ctrl;
1489                         private int top_item;                   /* First item that we show the in the current page */
1490                         private int last_item;                  /* Last visible item */
1491                         internal int page_size;                 /* Number of listbox items per page */
1492                         private Rectangle textarea_drawable;    /* Rectangle of the drawable text area */
1493                         
1494                         internal enum ItemNavigation
1495                         {
1496                                 First,
1497                                 Last,
1498                                 Next,
1499                                 Previous,
1500                                 NextPage,
1501                                 PreviousPage,
1502                         }
1503                         
1504                         class VScrollBarLB : VScrollBar
1505                         {
1506                                 public VScrollBarLB ()
1507                                 {                                       
1508                                 }
1509                                 
1510                                 internal override bool InternalCapture {
1511                                         get { return Capture; }
1512                                         set { }
1513                                 }
1514
1515                                 public bool FireMouseDown (MouseEventArgs e) 
1516                                 {
1517                                         if (Visible) {
1518                                                 e = TranslateEvent (e);
1519                                                 if (ClientRectangle.Contains (e.X, e.Y)) {
1520                                                         OnMouseDown (e);
1521                                                         return true;
1522                                                 }
1523                                         }
1524                                         return false;
1525                                 }       
1526                                 
1527                                 public void FireMouseUp (MouseEventArgs e) 
1528                                 {
1529                                         if (Visible) {
1530                                                 e = TranslateEvent (e);
1531                                                 if (ClientRectangle.Contains (e.X, e.Y))
1532                                                         OnMouseUp (e);
1533                                         }
1534                                 }
1535                                 
1536                                 public void FireMouseMove (MouseEventArgs e) 
1537                                 {
1538                                         if (Visible) {
1539                                                 e = TranslateEvent (e);
1540                                                 if (ClientRectangle.Contains (e.X, e.Y))
1541                                                         OnMouseMove (e);
1542                                         }
1543                                 }                       
1544                                 
1545                                 MouseEventArgs TranslateEvent (MouseEventArgs e)
1546                                 {
1547                                         Point loc = PointToClient (Control.MousePosition);
1548                                         return new MouseEventArgs (e.Button, e.Clicks, loc.X, loc.Y, e.Delta);
1549                                 }
1550                         }
1551
1552                         public ComboListBox (ComboBox owner)
1553                         {                                       
1554                                 this.owner = owner;                                                             
1555                                 top_item = 0;
1556                                 last_item = 0;
1557                                 page_size = 0;
1558
1559                                 MouseWheel += new MouseEventHandler (OnMouseWheelCLB);
1560
1561                                 SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
1562                                 SetStyle (ControlStyles.ResizeRedraw | ControlStyles.Opaque, true);
1563
1564                                 if (owner.DropDownStyle == ComboBoxStyle.Simple)
1565                                         InternalBorderStyle = BorderStyle.Fixed3D;
1566                                 else
1567                                         InternalBorderStyle = BorderStyle.FixedSingle;
1568                         }
1569
1570                         protected override CreateParams CreateParams
1571                         {
1572                                 get {
1573                                         CreateParams cp = base.CreateParams;                                    
1574                                         if (owner == null || owner.DropDownStyle == ComboBoxStyle.Simple)
1575                                                 return cp;
1576
1577                                         cp.Style ^= (int) WindowStyles.WS_CHILD;
1578                                         cp.Style |= (int) WindowStyles.WS_POPUP;
1579                                         cp.ExStyle |= (int) WindowExStyles.WS_EX_TOOLWINDOW | (int) WindowExStyles.WS_EX_TOPMOST;
1580                                         return cp;
1581                                 }
1582                         }
1583
1584                         protected override void Select (bool directed, bool forward)
1585                         {
1586                                 // Do nothing, we never want to be selected
1587                         }
1588
1589                         internal override bool InternalCapture {
1590                                 get {
1591                                         return Capture;
1592                                 }
1593
1594                                 set {
1595                                 }
1596                         }
1597
1598                         int BorderWidth {
1599                                 get {
1600                                         switch (border_style) {
1601                                         case BorderStyle.Fixed3D:
1602                                                 return ThemeEngine.Current.Border3DSize.Width;
1603                                         default:
1604                                                 return ThemeEngine.Current.BorderSize.Width;
1605                                         }
1606                                 }
1607                         }
1608
1609                         #region Private Methods                 
1610                         // Calcs the listbox area
1611                         internal void CalcListBoxArea ()
1612                         {                               
1613                                 int width, height;
1614                                 bool show_scrollbar = false;
1615                                 
1616                                 if (owner.DropDownStyle == ComboBoxStyle.Simple) {
1617                                         Rectangle area = owner.listbox_area;
1618                                         width = area.Width;
1619                                         height = area.Height;
1620                                 }
1621                                 else { // DropDown or DropDownList
1622                                         
1623                                         width = owner.DropDownWidth;
1624                                         int count = (owner.Items.Count <= owner.MaxDropDownItems) ? owner.Items.Count : owner.MaxDropDownItems;                         
1625                                         
1626                                         if (owner.DrawMode == DrawMode.OwnerDrawVariable) {                                             
1627                                                 height = 0;
1628                                                 for (int i = 0; i < count; i++) {
1629                                                         height += owner.GetItemHeight (i);
1630                                                 }
1631                                                 
1632                                         } else  {
1633                                                 height = owner.ItemHeight * count;
1634                                         }
1635                                 }
1636                                 
1637                                 if (owner.Items.Count <= owner.MaxDropDownItems) {                                      
1638                                         if (vscrollbar_ctrl != null)
1639                                                 vscrollbar_ctrl.Visible = false;
1640                                 } else {                                        
1641                                         /* Need vertical scrollbar */
1642                                         if (vscrollbar_ctrl == null) {
1643                                                 vscrollbar_ctrl = new VScrollBarLB ();
1644                                                 vscrollbar_ctrl.Minimum = 0;
1645                                                 vscrollbar_ctrl.SmallChange = 1;
1646                                                 vscrollbar_ctrl.LargeChange = 1;
1647                                                 vscrollbar_ctrl.Maximum = 0;
1648                                                 vscrollbar_ctrl.ValueChanged += new EventHandler (VerticalScrollEvent);
1649                                                 Controls.AddImplicit (vscrollbar_ctrl);
1650                                         }
1651                                         
1652                                         vscrollbar_ctrl.Height = height - 2 * BorderWidth;
1653                                                         
1654                                         vscrollbar_ctrl.Location = new Point (width - vscrollbar_ctrl.Width - BorderWidth - 1, 0);
1655
1656                                         vscrollbar_ctrl.Maximum = owner.Items.Count - (owner.DropDownStyle == ComboBoxStyle.Simple ? page_size : owner.maxdrop_items);
1657                                         show_scrollbar = vscrollbar_ctrl.Visible = true;
1658
1659                                         int hli = HighlightedIndex;
1660                                         if (hli > 0) {
1661                                                 hli = Math.Min (hli, vscrollbar_ctrl.Maximum);
1662                                                 vscrollbar_ctrl.Value = hli;
1663                                         }
1664                                 }
1665                                 
1666                                 Size = new Size (width, height);
1667                                 textarea_drawable = ClientRectangle;
1668                                 textarea_drawable.Width = width;
1669                                 textarea_drawable.Height = height;                              
1670                                 
1671                                 if (vscrollbar_ctrl != null && show_scrollbar)
1672                                         textarea_drawable.Width -= vscrollbar_ctrl.Width;
1673
1674                                 last_item = LastVisibleItem ();
1675                                 page_size = textarea_drawable.Height / owner.ItemHeight;
1676                         }                       
1677
1678                         private void Draw (Rectangle clip, Graphics dc)
1679                         {       
1680                                 dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (owner.BackColor), clip);
1681
1682                                 if (owner.Items.Count > 0) {
1683                                         
1684                                         for (int i = top_item; i <= last_item; i++) {
1685                                                 Rectangle item_rect = GetItemDisplayRectangle (i, top_item);
1686
1687                                                 if (!clip.IntersectsWith (item_rect))
1688                                                         continue;
1689
1690                                                 DrawItemState state = DrawItemState.None;
1691
1692                                                 if (i == HighlightedIndex) {
1693                                                         state |= DrawItemState.Selected;
1694                                                         
1695                                                         if (owner.DropDownStyle == ComboBoxStyle.DropDownList) {
1696                                                                 state |= DrawItemState.Focus;
1697                                                         }                                                       
1698                                                 }
1699                                                         
1700                                                 owner.OnDrawItem (new DrawItemEventArgs (dc, owner.Font, item_rect,
1701                                                         i, state, owner.ForeColor, owner.BackColor));
1702                                         }
1703                                 }
1704                         }
1705
1706                         int highlighted_index = -1;
1707
1708                         public int HighlightedIndex {
1709                                 get { return highlighted_index; }
1710                                 set { 
1711                                         if (highlighted_index == value)
1712                                                 return;
1713
1714                                         if (highlighted_index != -1)
1715                                                 Invalidate (GetItemDisplayRectangle (highlighted_index, top_item));
1716                                         highlighted_index = value;
1717                                         if (highlighted_index != -1)
1718                                                 Invalidate (GetItemDisplayRectangle (highlighted_index, top_item));
1719                                 }
1720                         }
1721
1722                         private Rectangle GetItemDisplayRectangle (int index, int top_index)
1723                         {
1724                                 if (index < 0 || index >= owner.Items.Count)
1725                                         throw new  ArgumentOutOfRangeException ("GetItemRectangle index out of range.");
1726
1727                                 Rectangle item_rect = new Rectangle ();
1728                                 int height = owner.GetItemHeight (index);
1729
1730                                 item_rect.X = 0;
1731                                 item_rect.Width = textarea_drawable.Width;
1732                                 if (owner.DrawMode == DrawMode.OwnerDrawVariable) {
1733                                         item_rect.Y = 0;
1734                                         for (int i = top_index; i < index; i++)
1735                                                 item_rect.Y += owner.GetItemHeight (i);
1736                                 } else
1737                                         item_rect.Y = height * (index - top_index);
1738
1739                                 item_rect.Height = height;
1740                                 return item_rect;
1741                         }
1742
1743                         public void HideWindow ()
1744                         {
1745                                 if (owner.DropDownStyle == ComboBoxStyle.Simple)
1746                                         return;
1747                                         
1748                                 Capture = false;
1749                                 Hide ();
1750                                 owner.DropDownListBoxFinished ();
1751                         }
1752
1753                         private int IndexFromPointDisplayRectangle (int x, int y)
1754                         {
1755                                 for (int i = top_item; i <= last_item; i++) {
1756                                         if (GetItemDisplayRectangle (i, top_item).Contains (x, y) == true)
1757                                                 return i;
1758                                 }
1759
1760                                 return -1;
1761                         }
1762
1763                         public void InvalidateItem (int index)
1764                         {
1765                                 if (Visible)
1766                                         Invalidate (GetItemDisplayRectangle (index, top_item));
1767                         }
1768
1769                         private int LastVisibleItem ()
1770                         {
1771                                 Rectangle item_rect;
1772                                 int top_y = textarea_drawable.Y + textarea_drawable.Height;
1773                                 int i = 0;                              
1774                                 
1775                                 for (i = top_item; i < owner.Items.Count; i++) {
1776                                         item_rect = GetItemDisplayRectangle (i, top_item);                              
1777                                         if (item_rect.Y + item_rect.Height > top_y) {
1778                                                 return i;
1779                                         }
1780                                 }
1781                                 return i - 1;
1782                         }
1783
1784                         public void SetTopItem (int item)
1785                         {
1786                                 if (top_item == item)
1787                                         return;
1788                                 top_item = item;
1789                                 UpdateLastVisibleItem ();
1790                                 Invalidate ();
1791                         }                       
1792
1793                         protected override void OnMouseDown (MouseEventArgs e)
1794                         {
1795                                 if (vscrollbar_ctrl != null)
1796                                         vscrollbar_ctrl.FireMouseDown (e);
1797                         }
1798
1799                         protected override void OnMouseMove (MouseEventArgs e)
1800                         {                                               
1801                                 if (owner.DropDownStyle == ComboBoxStyle.Simple)
1802                                         return;
1803
1804                                 Point pt = PointToClient (Control.MousePosition);
1805                                 int index = IndexFromPointDisplayRectangle (pt.X, pt.Y);
1806
1807                                 if (index != -1) {
1808                                         HighlightedIndex = index;
1809                                         return;
1810                                 }
1811                                 
1812                                 if (vscrollbar_ctrl != null)
1813                                         vscrollbar_ctrl.FireMouseMove (e);
1814                         }
1815                         
1816                         protected override void OnMouseUp (MouseEventArgs e)
1817                         {
1818                                 int index = IndexFromPointDisplayRectangle (e.X, e.Y);
1819
1820                                 if (index == -1) {                                      
1821                                         if (vscrollbar_ctrl == null || !vscrollbar_ctrl.FireMouseDown (e))
1822                                                 HideWindow ();
1823                                 } else {
1824                                         owner.OnSelectionChangeCommitted (new EventArgs ());
1825                                         owner.SelectedIndex = index;
1826                                         HideWindow ();
1827                                 }
1828
1829                                 if (vscrollbar_ctrl != null)
1830                                         vscrollbar_ctrl.FireMouseUp (e);
1831                         }
1832
1833                         internal override void OnPaintInternal (PaintEventArgs pevent)
1834                         {                               
1835                                 Draw (pevent.ClipRectangle,pevent.Graphics);
1836                         }
1837
1838                         public bool ShowWindow ()
1839                         {
1840                                 if (owner.DropDownStyle == ComboBoxStyle.Simple && owner.Items.Count == 0)
1841                                         return false;
1842
1843                                 HighlightedIndex = owner.SelectedIndex;
1844
1845                                 CalcListBoxArea ();                             
1846                                 Show ();
1847
1848                                 Refresh ();
1849                                 owner.OnDropDown (EventArgs.Empty);
1850                                 return true;
1851                         }
1852                         
1853                         public void UpdateLastVisibleItem ()
1854                         {
1855                                 last_item = LastVisibleItem ();
1856                         }
1857
1858                         public void Scroll (int delta)
1859                         {
1860                                 if (delta == 0 || vscrollbar_ctrl == null || !vscrollbar_ctrl.Visible)
1861                                         return;
1862
1863                                 int max = vscrollbar_ctrl.Maximum;//- (page_size) + 1;
1864
1865                                 int val = vscrollbar_ctrl.Value + delta;
1866                                 if (val > max)
1867                                         val = max;
1868                                 else if (val < vscrollbar_ctrl.Minimum)
1869                                         val = vscrollbar_ctrl.Minimum;
1870                                 vscrollbar_ctrl.Value = val;
1871                         }
1872
1873                         private void OnMouseWheelCLB (object sender, MouseEventArgs me)
1874                         {
1875                                 if (owner.Items.Count == 0)
1876                                         return;
1877
1878                                 int lines = me.Delta / 120 * SystemInformation.MouseWheelScrollLines;
1879                                 Scroll (-lines);
1880                         }
1881
1882                         // Value Changed
1883                         private void VerticalScrollEvent (object sender, EventArgs e)
1884                         {                               
1885                                 if (top_item == vscrollbar_ctrl.Value)
1886                                         return;
1887
1888                                 top_item =  vscrollbar_ctrl.Value;
1889                                 UpdateLastVisibleItem ();
1890                                 Invalidate ();
1891                         }                       
1892                         
1893                         protected override void WndProc(ref Message m) {
1894                                 if (m.Msg == (int)Msg.WM_SETFOCUS) {
1895                                         if (m.WParam != IntPtr.Zero) {
1896                                                 XplatUI.SetFocus(m.WParam);
1897                                         }
1898                                 }
1899                                 base.WndProc (ref m);
1900                         }
1901
1902                         #endregion Private Methods
1903                 }
1904         }
1905 }
1906