2010-01-20 Carlos Alberto Cortez <calberto.cortez@gmail.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / TextBox.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. (http://www.novell.com)
21 //
22 // Authors:
23 //      Peter Bartok    pbartok@novell.com
24 //     Daniel Nauck    (dna(at)mono-project(dot)de)
25 //
26
27 // NOT COMPLETE
28
29 using System;
30 using System.Collections;
31 using System.ComponentModel;
32 using System.ComponentModel.Design;
33 using System.Drawing;
34 #if NET_2_0
35 using System.Collections.Generic;
36 using System.Runtime.InteropServices;
37 #endif
38
39 namespace System.Windows.Forms {
40
41 #if NET_2_0
42         [ComVisible(true)]
43         [ClassInterface (ClassInterfaceType.AutoDispatch)]
44         [Designer ("System.Windows.Forms.Design.TextBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
45 #endif
46         public class TextBox : TextBoxBase {
47                 #region Variables
48                 private ContextMenu     menu;
49                 private MenuItem        undo;
50                 private MenuItem        cut;
51                 private MenuItem        copy;
52                 private MenuItem        paste;
53                 private MenuItem        delete;
54                 private MenuItem        select_all;
55
56 #if NET_2_0
57                 private bool use_system_password_char;
58                 private AutoCompleteStringCollection auto_complete_custom_source;
59                 private AutoCompleteMode auto_complete_mode = AutoCompleteMode.None;
60                 private AutoCompleteSource auto_complete_source = AutoCompleteSource.None;
61                 private AutoCompleteListBox auto_complete_listbox;
62                 private string auto_complete_original_text;
63                 private int auto_complete_selected_index = -1;
64                 private List<string> auto_complete_matches;
65                 private ComboBox auto_complete_cb_source;
66 #endif
67                 #endregion      // Variables
68
69                 #region Public Constructors
70                 public TextBox() {
71
72                         scrollbars = RichTextBoxScrollBars.None;
73                         alignment = HorizontalAlignment.Left;
74                         this.LostFocus +=new EventHandler(TextBox_LostFocus);
75                         this.RightToLeftChanged += new EventHandler (TextBox_RightToLeftChanged);
76 #if NET_2_0
77                         MouseWheel += new MouseEventHandler (TextBox_MouseWheel);
78 #endif
79
80                         BackColor = SystemColors.Window;
81                         ForeColor = SystemColors.WindowText;
82                         backcolor_set = false;
83
84                         SetStyle (ControlStyles.StandardClick | ControlStyles.StandardDoubleClick, false);
85                         SetStyle (ControlStyles.FixedHeight, true);
86
87                         undo = new MenuItem(Locale.GetText("&Undo"));
88                         cut = new MenuItem(Locale.GetText("Cu&t"));
89                         copy = new MenuItem(Locale.GetText("&Copy"));
90                         paste = new MenuItem(Locale.GetText("&Paste"));
91                         delete = new MenuItem(Locale.GetText("&Delete"));
92                         select_all = new MenuItem(Locale.GetText("Select &All"));
93
94                         menu = new ContextMenu(new MenuItem[] { undo, new MenuItem("-"), cut, copy, paste, delete, new MenuItem("-"), select_all});
95                         ContextMenu = menu;
96
97                         menu.Popup += new EventHandler(menu_Popup);
98                         undo.Click += new EventHandler(undo_Click);
99                         cut.Click += new EventHandler(cut_Click);
100                         copy.Click += new EventHandler(copy_Click);
101                         paste.Click += new EventHandler(paste_Click);
102                         delete.Click += new EventHandler(delete_Click);
103                         select_all.Click += new EventHandler(select_all_Click);
104
105                         document.multiline = false;
106                 }
107
108                 #endregion      // Public Constructors
109
110                 #region Private & Internal Methods
111
112                 void TextBox_RightToLeftChanged (object sender, EventArgs e)
113                 {
114                         UpdateAlignment ();
115                 }
116
117                 private void TextBox_LostFocus (object sender, EventArgs e) {
118                         if (hide_selection)
119                                 document.InvalidateSelectionArea ();
120 #if NET_2_0
121                         if (auto_complete_listbox != null && auto_complete_listbox.Visible)
122                                 auto_complete_listbox.HideListBox (false);
123 #endif
124                 }
125
126 #if NET_2_0
127                 private void TextBox_MouseWheel (object o, MouseEventArgs args)
128                 {
129                         if (auto_complete_listbox == null || !auto_complete_listbox.Visible)
130                                 return;
131
132                         int lines = args.Delta / 120;
133                         auto_complete_listbox.Scroll (-lines);
134                 }
135
136                 // Receives either WM_KEYDOWN or WM_CHAR that will likely need the generation/lookup
137                 // of new matches
138                 private void ProcessAutoCompleteInput (ref Message m, bool deleting_chars)
139                 {
140                         // Need to call base.WndProc before to have access to
141                         // the updated Text property value
142                         base.WndProc (ref m);
143                         auto_complete_original_text = Text;
144                         ShowAutoCompleteListBox (deleting_chars);
145                 }
146
147                 private void ShowAutoCompleteListBox (bool deleting_chars)
148                 {
149                         // 
150                         // We only support CustomSource by now
151                         //
152
153                         IList source = auto_complete_cb_source == null ? auto_complete_custom_source : (IList)auto_complete_cb_source.Items;
154
155                         bool append = auto_complete_mode == AutoCompleteMode.Append || auto_complete_mode == AutoCompleteMode.SuggestAppend;
156                         bool suggest = auto_complete_mode == AutoCompleteMode.Suggest || auto_complete_mode == AutoCompleteMode.SuggestAppend;
157
158                         if (Text.Length == 0) {
159                                 if (auto_complete_listbox != null)
160                                         auto_complete_listbox.HideListBox (false);
161                                 return;
162                         }
163
164                         if (auto_complete_matches == null)
165                                 auto_complete_matches = new List<string> ();
166
167                         string text = Text;
168                         auto_complete_matches.Clear ();
169
170                         for (int i = 0; i < source.Count; i++) {
171                                 string item_text = auto_complete_cb_source == null ? auto_complete_custom_source [i] :
172                                         auto_complete_cb_source.GetItemText (auto_complete_cb_source.Items [i]);
173                                 if (item_text.StartsWith (text, StringComparison.CurrentCultureIgnoreCase))
174                                         auto_complete_matches.Add (item_text);
175                         }
176
177                         auto_complete_matches.Sort ();
178
179                         // Return if we have a single exact match
180                         if ((auto_complete_matches.Count == 0) || (auto_complete_matches.Count == 1 && 
181                                                 auto_complete_matches [0].Equals (text, StringComparison.CurrentCultureIgnoreCase))) {
182
183                                 if (auto_complete_listbox != null && auto_complete_listbox.Visible)
184                                         auto_complete_listbox.HideListBox (false);
185                                 return;
186                         }
187
188                         auto_complete_selected_index = suggest ? -1 : 0;
189
190                         if (suggest) {
191                                 if (auto_complete_listbox == null)
192                                         auto_complete_listbox = new AutoCompleteListBox (this);
193
194                                 // Show or update auto complete listbox contents
195                                 auto_complete_listbox.Location = PointToScreen (new Point (0, Height));
196                                 auto_complete_listbox.ShowListBox ();
197                         }
198
199                         if (append && !deleting_chars)
200                                 AppendAutoCompleteMatch (0);
201
202                         document.MoveCaret (CaretDirection.End);
203                 }
204
205                 internal void HideAutoCompleteList ()
206                 {
207                         if (auto_complete_listbox != null)
208                                 auto_complete_listbox.HideListBox (false);
209                 }
210
211                 internal bool IsAutoCompleteAvailable {
212                         get {
213                                 if (auto_complete_source == AutoCompleteSource.None || auto_complete_mode == AutoCompleteMode.None)
214                                         return false;
215
216                                 // We only support CustomSource by now, as well as an internal custom source used by ComboBox
217                                 if (auto_complete_source != AutoCompleteSource.CustomSource)
218                                         return false;
219                                 IList custom_source = auto_complete_cb_source == null ? auto_complete_custom_source : (IList)auto_complete_cb_source.Items;
220                                 if (custom_source == null || custom_source.Count == 0)
221                                         return false;
222
223                                 return true;
224                         }
225                 }
226
227                 internal ComboBox AutoCompleteInternalSource {
228                         get {
229                                 return auto_complete_cb_source;
230                         }
231                         set {
232                                 auto_complete_cb_source = value;
233                         }
234                 }
235
236                 internal bool CanNavigateAutoCompleteList {
237                         get {
238                                 if (auto_complete_mode == AutoCompleteMode.None)
239                                         return false;
240                                 if (auto_complete_matches == null || auto_complete_matches.Count == 0)
241                                         return false;
242
243                                 bool suggest_window_visible = auto_complete_listbox != null && auto_complete_listbox.Visible;
244                                 if (auto_complete_mode == AutoCompleteMode.Suggest && !suggest_window_visible)
245                                         return false;
246
247                                 return true;
248                         }
249                 }
250
251                 bool NavigateAutoCompleteList (Keys key)
252                 {
253                         if (auto_complete_matches == null || auto_complete_matches.Count == 0)
254                                 return false;
255
256                         bool suggest_window_visible = auto_complete_listbox != null && auto_complete_listbox.Visible;
257                         if (!suggest_window_visible && auto_complete_mode == AutoCompleteMode.Suggest)
258                                 return false;
259
260                         int index = auto_complete_selected_index;
261
262                         switch (key) {
263                                 case Keys.Up:
264                                         index -= 1;
265                                         if (index < -1)
266                                                 index = auto_complete_matches.Count - 1;
267                                         break;
268                                 case Keys.Down:
269                                         index += 1;
270                                         if (index >= auto_complete_matches.Count)
271                                                 index = -1;
272                                         break;
273                                 case Keys.PageUp:
274                                         if (auto_complete_mode == AutoCompleteMode.Append || !suggest_window_visible)
275                                                 goto case Keys.Up;
276
277                                         if (index == -1)
278                                                 index = auto_complete_matches.Count - 1;
279                                         else if (index == 0)
280                                                 index = -1;
281                                         else {
282                                                 index -= auto_complete_listbox.page_size - 1;
283                                                 if (index < 0)
284                                                         index = 0;
285                                         }
286                                         break;
287                                 case Keys.PageDown:
288                                         if (auto_complete_mode == AutoCompleteMode.Append || !suggest_window_visible)
289                                                 goto case Keys.Down;
290
291                                         if (index == -1)
292                                                 index = 0;
293                                         else if (index == auto_complete_matches.Count - 1)
294                                                 index = -1;
295                                         else {
296                                                 index += auto_complete_listbox.page_size - 1;
297                                                 if (index >= auto_complete_matches.Count)
298                                                         index = auto_complete_matches.Count - 1;
299                                         }
300                                         break;
301                                 default:
302                                         break;
303                         }
304
305                         // In SuggestAppend mode the navigation mode depends on the visibility of the suggest lb.
306                         bool suggest = auto_complete_mode == AutoCompleteMode.Suggest || auto_complete_mode == AutoCompleteMode.SuggestAppend;
307                         if (suggest && suggest_window_visible) {
308                                 Text = index == -1 ? auto_complete_original_text : auto_complete_matches [index];
309                                 auto_complete_listbox.HighlightedIndex = index;
310                         } else
311                                 // Append only, not suggest at all
312                                 AppendAutoCompleteMatch (index < 0 ? 0 : index);
313                                 
314                         auto_complete_selected_index = index;
315                         document.MoveCaret (CaretDirection.End);
316
317                         return true;
318                 }
319
320                 void AppendAutoCompleteMatch (int index)
321                 {
322                         Text = auto_complete_original_text + auto_complete_matches [index].Substring (auto_complete_original_text.Length);
323                         SelectionStart = auto_complete_original_text.Length;
324                         SelectionLength = auto_complete_matches [index].Length - auto_complete_original_text.Length;
325                 }
326
327                 // this is called when the user selects a value from the autocomplete list
328                 // *with* the mouse
329                 internal virtual void OnAutoCompleteValueSelected (EventArgs args)
330                 {
331                 }
332 #endif
333
334                 private void UpdateAlignment ()
335                 {
336                         HorizontalAlignment new_alignment = alignment;
337                         RightToLeft rtol = GetInheritedRtoL ();
338
339                         if (rtol == RightToLeft.Yes) {
340                                 if (new_alignment == HorizontalAlignment.Left)
341                                         new_alignment = HorizontalAlignment.Right;
342                                 else if (new_alignment == HorizontalAlignment.Right)
343                                         new_alignment = HorizontalAlignment.Left;
344                         }
345
346                         document.alignment = new_alignment;
347
348                         // MS word-wraps if alignment isn't left
349                         if (Multiline) {
350                                 if (alignment != HorizontalAlignment.Left) {
351                                         document.Wrap = true;
352                                 } else {
353                                         document.Wrap = word_wrap;
354                                 }
355                         }
356
357                         for (int i = 1; i <= document.Lines; i++) {
358                                 document.GetLine (i).Alignment = new_alignment;
359                         }
360
361                         document.RecalculateDocument (CreateGraphicsInternal ());
362
363                         Invalidate ();  // Make sure we refresh
364                 }
365
366                 internal override Color ChangeBackColor (Color backColor)
367                 {
368                         if (backColor == Color.Empty) {
369 #if NET_2_0
370                                 if (!ReadOnly)
371                                         backColor = SystemColors.Window;
372 #else
373                                 backColor = SystemColors.Window;
374 #endif
375                                 backcolor_set = false;
376                         }
377                         return backColor;
378                 }
379
380 #if NET_2_0
381                 void OnAutoCompleteCustomSourceChanged(object sender, CollectionChangeEventArgs e) {
382                         if(auto_complete_source == AutoCompleteSource.CustomSource) {
383                                 //FIXME: handle add, remove and refresh events in AutoComplete algorithm.
384                         }
385                 }
386 #endif
387                 #endregion      // Private & Internal Methods
388
389                 #region Public Instance Properties
390 #if NET_2_0
391                 [MonoTODO("AutoCompletion algorithm is currently not implemented.")]
392                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
393                 [Browsable (true)]
394                 [EditorBrowsable (EditorBrowsableState.Always)]
395                 [Localizable (true)]
396                 [Editor ("System.Windows.Forms.Design.ListControlStringCollectionEditor, " + Consts.AssemblySystem_Design,
397                  "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
398                 public AutoCompleteStringCollection AutoCompleteCustomSource { 
399                         get {
400                                 if(auto_complete_custom_source == null) {
401                                         auto_complete_custom_source = new AutoCompleteStringCollection ();
402                                         auto_complete_custom_source.CollectionChanged += new CollectionChangeEventHandler (OnAutoCompleteCustomSourceChanged);
403                                 }
404                                 return auto_complete_custom_source;
405                         }
406                         set {
407                                 if(auto_complete_custom_source == value)
408                                         return;
409
410                                 if(auto_complete_custom_source != null) //remove eventhandler from old collection
411                                         auto_complete_custom_source.CollectionChanged -= new CollectionChangeEventHandler (OnAutoCompleteCustomSourceChanged);
412
413                                 auto_complete_custom_source = value;
414
415                                 if(auto_complete_custom_source != null)
416                                         auto_complete_custom_source.CollectionChanged += new CollectionChangeEventHandler (OnAutoCompleteCustomSourceChanged);
417                         }
418                 }
419
420                 [MonoTODO("AutoCompletion algorithm is currently not implemented.")]
421                 [Browsable (true)]
422                 [EditorBrowsable (EditorBrowsableState.Always)]
423                 [DefaultValue (AutoCompleteMode.None)]
424                 public AutoCompleteMode AutoCompleteMode {
425                         get { return auto_complete_mode; }
426                         set {
427                                 if(auto_complete_mode == value)
428                                         return;
429
430                                 if((value < AutoCompleteMode.None) || (value > AutoCompleteMode.SuggestAppend))
431                                         throw new InvalidEnumArgumentException (Locale.GetText ("Enum argument value '{0}' is not valid for AutoCompleteMode", value));
432
433                                 auto_complete_mode = value;
434                         }
435                 }
436
437                 [MonoTODO("AutoCompletion algorithm is currently not implemented.")]
438                 [Browsable (true)]
439                 [EditorBrowsable (EditorBrowsableState.Always)]
440                 [DefaultValue (AutoCompleteSource.None)]
441                 [TypeConverter (typeof (TextBoxAutoCompleteSourceConverter))]
442                 public AutoCompleteSource AutoCompleteSource {
443                         get { return auto_complete_source; }
444                         set {
445                                 if(auto_complete_source == value)
446                                         return;
447
448                                 if(!Enum.IsDefined (typeof (AutoCompleteSource), value))
449                                         throw new InvalidEnumArgumentException (Locale.GetText ("Enum argument value '{0}' is not valid for AutoCompleteSource", value));
450
451                                 auto_complete_source = value;
452                         }
453                 }
454
455                 [DefaultValue(false)]
456                 [RefreshProperties (RefreshProperties.Repaint)]
457                 public bool UseSystemPasswordChar {
458                         get {
459                                 return use_system_password_char;
460                         }
461
462                         set {
463                                 if (use_system_password_char != value) {
464                                         use_system_password_char = value;
465                                         
466                                         if (!Multiline)
467                                                 document.PasswordChar = PasswordChar.ToString ();
468                                         else
469                                                 document.PasswordChar = string.Empty;
470                                         Invalidate ();
471                                 }
472                         }
473                 }
474 #endif
475
476                 [DefaultValue(false)]
477                 [MWFCategory("Behavior")]
478                 public bool AcceptsReturn {
479                         get {
480                                 return accepts_return;
481                         }
482
483                         set {
484                                 if (value != accepts_return) {
485                                         accepts_return = value;
486                                 }
487                         }
488                 }
489
490                 [DefaultValue(CharacterCasing.Normal)]
491                 [MWFCategory("Behavior")]
492                 public CharacterCasing CharacterCasing {
493                         get {
494                                 return character_casing;
495                         }
496
497                         set {
498                                 if (value != character_casing) {
499                                         character_casing = value;
500                                 }
501                         }
502                 }
503
504                 [Localizable(true)]
505                 [DefaultValue('\0')]
506                 [MWFCategory("Behavior")]
507 #if NET_2_0
508                 [RefreshProperties (RefreshProperties.Repaint)]
509 #endif
510                 public char PasswordChar {
511                         get {
512 #if NET_2_0
513                                 if (use_system_password_char) {
514                                         return '*';
515                                 }
516 #endif
517                                 return password_char;
518                         }
519
520                         set {
521                                 if (value != password_char) {
522                                         password_char = value;
523                                         if (!Multiline) {
524                                                 document.PasswordChar = PasswordChar.ToString ();
525                                         } else {
526                                                 document.PasswordChar = string.Empty;
527                                         }
528                                         this.CalculateDocument();
529                                 }
530                         }
531                 }
532
533                 [DefaultValue(ScrollBars.None)]
534                 [Localizable(true)]
535                 [MWFCategory("Appearance")]
536                 public ScrollBars ScrollBars {
537                         get {
538                                 return (ScrollBars)scrollbars;
539                         }
540
541                         set {
542                                 if (!Enum.IsDefined (typeof (ScrollBars), value))
543                                         throw new InvalidEnumArgumentException ("value", (int) value,
544                                                 typeof (ScrollBars));
545
546                                 if (value != (ScrollBars)scrollbars) {
547                                         scrollbars = (RichTextBoxScrollBars)value;
548                                         base.CalculateScrollBars();
549                                 }
550                         }
551                 }
552
553 #if ONLY_1_1
554                 [Browsable(false)]
555                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
556                 public override int SelectionLength {
557                         get {
558                                 return base.SelectionLength;
559                         }
560                         set {
561                                 base.SelectionLength = value;
562                         }
563                 }
564 #endif
565
566                 public override string Text {
567                         get {
568                                 return base.Text;
569                         }
570
571                         set {
572                                 base.Text = value;
573                         }
574                 }
575
576                 [DefaultValue(HorizontalAlignment.Left)]
577                 [Localizable(true)]
578                 [MWFCategory("Appearance")]
579                 public HorizontalAlignment TextAlign {
580                         get {
581                                 return alignment;
582                         }
583
584                         set {
585                                 if (value != alignment) {
586                                         alignment = value;
587
588                                         UpdateAlignment ();
589
590                                         OnTextAlignChanged(EventArgs.Empty);
591                                 }
592                         }
593                 }
594                 #endregion      // Public Instance Properties
595
596 #if NET_2_0
597                 public void Paste (string text)
598                 {
599                         document.ReplaceSelection (CaseAdjust (text), false);
600
601                         ScrollToCaret();
602                         OnTextChanged(EventArgs.Empty);
603                 }
604 #endif
605                 #region Protected Instance Methods
606                 protected override CreateParams CreateParams {
607                         get {
608                                 return base.CreateParams;
609                         }
610                 }
611
612 #if ONLY_1_1
613                 protected override ImeMode DefaultImeMode {
614                         get {
615                                 return base.DefaultImeMode;
616                         }
617                 }
618 #endif
619 #if NET_2_0
620                 protected override void Dispose (bool disposing)
621                 {
622                         base.Dispose (disposing);
623                 }
624 #endif
625
626                 protected override bool IsInputKey (Keys keyData)
627                 {
628                         return base.IsInputKey (keyData);
629                 }
630
631                 protected override void OnGotFocus (EventArgs e)
632                 {
633                         base.OnGotFocus (e);
634                         if (selection_length == -1 && !has_been_focused)
635                                 SelectAllNoScroll ();
636                         has_been_focused = true;
637                 }
638
639                 protected override void OnHandleCreated (EventArgs e)
640                 {
641                         base.OnHandleCreated (e);
642                 }
643
644 #if ONLY_1_1
645                 protected override void OnMouseUp(MouseEventArgs mevent)
646                 {
647                         base.OnMouseUp (mevent);
648                 }
649 #endif
650
651                 protected virtual void OnTextAlignChanged (EventArgs e)
652                 {
653                         EventHandler eh = (EventHandler)(Events [TextAlignChangedEvent]);
654                         if (eh != null)
655                                 eh (this, e);
656                 }
657
658                 protected override void WndProc (ref Message m)
659                 {
660                         switch ((Msg)m.Msg) {
661 #if NET_2_0
662                                 case Msg.WM_KEYDOWN:
663                                         if (!IsAutoCompleteAvailable)
664                                                 break;
665
666                                         Keys key_data = (Keys)m.WParam.ToInt32 ();
667                                         switch (key_data) {
668                                                 case Keys.Down:
669                                                 case Keys.Up:
670                                                 case Keys.PageDown:
671                                                 case Keys.PageUp:
672                                                         if (NavigateAutoCompleteList (key_data)) {
673                                                                 m.Result = IntPtr.Zero;
674                                                                 return;
675                                                         }
676                                                         break;
677                                                 case Keys.Enter:
678                                                         if (auto_complete_listbox != null && auto_complete_listbox.Visible)
679                                                                 auto_complete_listbox.HideListBox (false);
680                                                         SelectAll ();
681                                                         break;
682                                                 case Keys.Escape:
683                                                         if (auto_complete_listbox != null && auto_complete_listbox.Visible)
684                                                                 auto_complete_listbox.HideListBox (false);
685                                                         break;
686                                                 case Keys.Delete:
687                                                         ProcessAutoCompleteInput (ref m, true);
688                                                         return;
689                                                 default:
690                                                         break;
691                                         }
692                                         break;
693                                 case Msg.WM_CHAR:
694                                         if (!IsAutoCompleteAvailable)
695                                                 break;
696
697                                         // Don't handle either Enter or Esc - they are handled in the WM_KEYDOWN case
698                                         int char_value = m.WParam.ToInt32 ();
699                                         if (char_value == 13 || char_value == 27)
700                                                 break;
701
702                                         ProcessAutoCompleteInput (ref m, char_value == 8);
703                                         return;
704 #endif
705                                 case Msg.WM_LBUTTONDOWN:
706                                         // When the textbox gets focus by LBUTTON (but not by middle or right)
707                                         // it does not do the select all / scroll thing.
708                                         has_been_focused = true;
709                                         FocusInternal (true);
710                                         break;
711                         }
712
713                         base.WndProc(ref m);
714                 }
715                 #endregion      // Protected Instance Methods
716
717                 #region Events
718                 static object TextAlignChangedEvent = new object ();
719
720                 public event EventHandler TextAlignChanged {
721                         add { Events.AddHandler (TextAlignChangedEvent, value); }
722                         remove { Events.RemoveHandler (TextAlignChangedEvent, value); }
723                 }
724                 #endregion      // Events
725
726                 #region Private Methods
727
728                 internal override ContextMenu ContextMenuInternal {
729                         get {
730                                 ContextMenu res = base.ContextMenuInternal;
731                                 if (res == menu)
732                                         return null;
733                                 return res;
734                         }
735                         set {
736                                 base.ContextMenuInternal = value;
737                         }
738                 }
739
740                 internal void RestoreContextMenu ()
741                 {
742                         ContextMenuInternal = menu;
743                 }
744
745                 private void menu_Popup(object sender, EventArgs e) {
746                         if (SelectionLength == 0) {
747                                 cut.Enabled = false;
748                                 copy.Enabled = false;
749                         } else {
750                                 cut.Enabled = true;
751                                 copy.Enabled = true;
752                         }
753
754                         if (SelectionLength == TextLength) {
755                                 select_all.Enabled = false;
756                         } else {
757                                 select_all.Enabled = true;
758                         }
759
760                         if (!CanUndo) {
761                                 undo.Enabled = false;
762                         } else {
763                                 undo.Enabled = true;
764                         }
765
766                         if (ReadOnly) {
767                                 undo.Enabled = cut.Enabled = paste.Enabled = delete.Enabled = false;
768                         }
769                 }
770
771                 private void undo_Click(object sender, EventArgs e) {
772                         Undo();
773                 }
774
775                 private void cut_Click(object sender, EventArgs e) {
776                         Cut();
777                 }
778
779                 private void copy_Click(object sender, EventArgs e) {
780                         Copy();
781                 }
782
783                 private void paste_Click(object sender, EventArgs e) {
784                         Paste();
785                 }
786
787                 private void delete_Click(object sender, EventArgs e) {
788                         SelectedText = string.Empty;
789                 }
790
791                 private void select_all_Click(object sender, EventArgs e) {
792                         SelectAll();
793                 }
794                 #endregion      // Private Methods
795
796 #if NET_2_0
797                 public override bool Multiline {
798                         get {
799                                 return base.Multiline;
800                         }
801
802                         set {
803                                 base.Multiline = value;
804                         }
805                 }
806
807                 protected override void OnBackColorChanged (EventArgs e)
808                 {
809                         base.OnBackColorChanged (e);
810                 }
811                 
812                 protected override void OnFontChanged (EventArgs e)
813                 {
814                         base.OnFontChanged (e);
815                 }
816
817                 protected override void OnHandleDestroyed (EventArgs e)
818                 {
819                         base.OnHandleDestroyed (e);
820                 }
821
822                 class AutoCompleteListBox : Control
823                 {
824                         TextBox owner;
825                         VScrollBar vscroll;
826                         int top_item;
827                         int last_item;
828                         internal int page_size;
829                         int item_height;
830                         int highlighted_index = -1;
831                         bool user_defined_size;
832                         bool resizing;
833                         Rectangle resizer_bounds;
834
835                         const int DefaultDropDownItems = 7;
836
837                         public AutoCompleteListBox (TextBox tb)
838                         {
839                                 owner = tb;
840                                 item_height = FontHeight + 2;
841
842                                 vscroll = new VScrollBar ();
843                                 vscroll.ValueChanged += VScrollValueChanged;
844                                 Controls.Add (vscroll);
845
846                                 is_visible = false;
847                                 InternalBorderStyle = BorderStyle.FixedSingle;
848                         }
849
850                         protected override CreateParams CreateParams {
851                                 get {
852                                         CreateParams cp = base.CreateParams;
853
854                                         cp.Style ^= (int)WindowStyles.WS_CHILD;
855                                         cp.Style ^= (int)WindowStyles.WS_VISIBLE;
856                                         cp.Style |= (int)WindowStyles.WS_POPUP;
857                                         cp.ExStyle |= (int)WindowExStyles.WS_EX_TOPMOST | (int)WindowExStyles.WS_EX_TOOLWINDOW;
858                                         return cp;
859                                 }
860                         }
861
862                         public int HighlightedIndex {
863                                 get {
864                                         return highlighted_index;
865                                 }
866                                 set {
867                                         if (value == highlighted_index)
868                                                 return;
869
870                                         if (highlighted_index != -1)
871                                                 Invalidate (GetItemBounds (highlighted_index));
872                                         highlighted_index = value;
873                                         if (highlighted_index != -1)
874                                                 Invalidate (GetItemBounds (highlighted_index));
875
876                                         if (highlighted_index != -1)
877                                                 EnsureVisible (highlighted_index);
878                                 }
879                         }
880
881                         public void Scroll (int lines)
882                         {
883                                 int max = vscroll.Maximum - page_size + 1;
884                                 int val = vscroll.Value + lines;
885                                 if (val > max)
886                                         val = max;
887                                 else if (val < vscroll.Minimum)
888                                         val = vscroll.Minimum;
889
890                                 vscroll.Value = val;
891                         }
892
893                         public void EnsureVisible (int index)
894                         {
895                                 if (index < top_item) {
896                                         vscroll.Value = index;
897                                 } else {
898                                         int max = vscroll.Maximum - page_size + 1;
899                                         int rows = Height / item_height;
900                                         if (index > top_item + rows - 1) {
901                                                 index = index - rows + 1;
902                                                 vscroll.Value = index > max ? max : index;
903                                         }
904                                 }
905                         }
906
907                         internal override bool ActivateOnShow {
908                                 get {
909                                         return false;
910                                 }
911                         }
912
913                         void VScrollValueChanged (object o, EventArgs args)
914                         {
915                                 if (top_item == vscroll.Value)
916                                         return;
917
918                                 top_item = vscroll.Value;
919                                 last_item = GetLastVisibleItem ();
920                                 Invalidate ();
921                         }
922
923                         int GetLastVisibleItem ()
924                         {
925                                 int top_y = Height;
926
927                                 for (int i = top_item; i < owner.auto_complete_matches.Count; i++) {
928                                         int pos = i - top_item; // relative to visible area
929                                         if ((pos * item_height) + item_height >= top_y)
930                                                 return i;
931                                 }
932
933                                 return owner.auto_complete_matches.Count - 1;
934                         }
935
936                         Rectangle GetItemBounds (int index)
937                         {
938                                 int pos = index - top_item;
939                                 Rectangle bounds = new Rectangle (0, pos * item_height, Width, item_height);
940                                 if (vscroll.Visible)
941                                         bounds.Width -= vscroll.Width;
942
943                                 return bounds;
944                         }
945
946                         int GetItemAt (Point loc)
947                         {
948                                 if (loc.Y > (last_item - top_item) * item_height + item_height)
949                                         return -1;
950
951                                 int retval = loc.Y / item_height;
952                                 retval += top_item;
953
954                                 return retval;
955                         }
956
957                         void LayoutListBox ()
958                         {
959                                 int total_height = owner.auto_complete_matches.Count * item_height;
960                                 page_size = Math.Max (Height / item_height, 1);
961                                 last_item = GetLastVisibleItem ();
962
963                                 if (Height < total_height) {
964                                         vscroll.Visible = true;
965                                         vscroll.Maximum = owner.auto_complete_matches.Count - 1;
966                                         vscroll.LargeChange = page_size;
967                                         vscroll.Location = new Point (Width - vscroll.Width, 0);
968                                         vscroll.Height = Height - item_height;
969                                 } else
970                                         vscroll.Visible = false;
971
972                                 resizer_bounds = new Rectangle (Width - item_height, Height - item_height,
973                                                 item_height, item_height);
974                         }
975
976                         public void HideListBox (bool set_text)
977                         {
978                                 if (set_text)
979                                         owner.Text = owner.auto_complete_matches [HighlightedIndex];
980
981                                 Capture = false;
982                                 Hide ();
983                         }
984
985                         public void ShowListBox ()
986                         {
987                                 if (!user_defined_size) {
988                                         // This should call the Layout routine for us
989                                         int height = owner.auto_complete_matches.Count > DefaultDropDownItems ? 
990                                                 DefaultDropDownItems * item_height : (owner.auto_complete_matches.Count + 1) * item_height;
991                                         Size = new Size (owner.Width, height);
992                                 } else
993                                         LayoutListBox ();
994
995                                 vscroll.Value = 0;
996                                 HighlightedIndex = -1;
997
998                                 Show ();
999                                 // make sure we are on top - call the raw routine, since we are parentless
1000                                 XplatUI.SetZOrder (Handle, IntPtr.Zero, true, false);
1001                                 Invalidate ();
1002                         }
1003
1004                         protected override void OnResize (EventArgs args)
1005                         {
1006                                 base.OnResize (args);
1007
1008                                 LayoutListBox ();
1009                                 Refresh ();
1010                         }
1011
1012                         protected override void OnMouseDown (MouseEventArgs args)
1013                         {
1014                                 base.OnMouseDown (args);
1015
1016                                 if (!resizer_bounds.Contains (args.Location))
1017                                         return;
1018
1019                                 user_defined_size = true;
1020                                 resizing = true;
1021                                 Capture = true;
1022                         }
1023
1024                         protected override void OnMouseMove (MouseEventArgs args)
1025                         {
1026                                 base.OnMouseMove (args);
1027
1028                                 if (resizing) {
1029                                         Point mouse_loc = Control.MousePosition;
1030                                         Point ctrl_loc = PointToScreen (Point.Empty);
1031
1032                                         Size new_size = new Size (mouse_loc.X - ctrl_loc.X, mouse_loc.Y - ctrl_loc.Y);
1033                                         if (new_size.Height < item_height)
1034                                                 new_size.Height = item_height;
1035                                         if (new_size.Width < item_height)
1036                                                 new_size.Width = item_height;
1037
1038                                         Size = new_size;
1039                                         return;
1040                                 }
1041
1042                                 Cursor = resizer_bounds.Contains (args.Location) ? Cursors.SizeNWSE : Cursors.Default;
1043
1044                                 int item_idx = GetItemAt (args.Location);
1045                                 if (item_idx != -1)
1046                                         HighlightedIndex = item_idx;
1047                         }
1048
1049                         protected override void OnMouseUp (MouseEventArgs args)
1050                         {
1051                                 base.OnMouseUp (args);
1052
1053                                 int item_idx = GetItemAt (args.Location);
1054                                 if (item_idx != -1 && !resizing)
1055                                         HideListBox (true);
1056
1057                                 owner.OnAutoCompleteValueSelected (EventArgs.Empty); // internal
1058                                 resizing = false;
1059                                 Capture = false;
1060                         }
1061
1062                         internal override void OnPaintInternal (PaintEventArgs args)
1063                         {
1064                                 Graphics g = args.Graphics;
1065                                 Brush brush = ThemeEngine.Current.ResPool.GetSolidBrush (ForeColor);
1066
1067                                 int highlighted_idx = HighlightedIndex;
1068
1069                                 int y = 0;
1070                                 int last = GetLastVisibleItem ();
1071                                 for (int i = top_item; i <= last; i++) {
1072                                         Rectangle item_bounds = GetItemBounds (i);
1073                                         if (!item_bounds.IntersectsWith (args.ClipRectangle))
1074                                                 continue;
1075
1076                                         if (i == highlighted_idx) {
1077                                                 g.FillRectangle (SystemBrushes.Highlight, item_bounds);
1078                                                 g.DrawString (owner.auto_complete_matches [i], Font, SystemBrushes.HighlightText, item_bounds);
1079                                         } else 
1080                                                 g.DrawString (owner.auto_complete_matches [i], Font, brush, item_bounds);
1081
1082                                         y += item_height;
1083                                 }
1084
1085                                 ThemeEngine.Current.CPDrawSizeGrip (g, SystemColors.Control, resizer_bounds);
1086                         }
1087                 }
1088 #endif
1089         }
1090         
1091 #if NET_2_0
1092         internal class TextBoxAutoCompleteSourceConverter : EnumConverter
1093         {
1094                 public TextBoxAutoCompleteSourceConverter(Type type)
1095                         : base(type)
1096                 { }
1097
1098                 public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
1099                 {
1100                         StandardValuesCollection stdv = base.GetStandardValues(context);
1101                         AutoCompleteSource[] arr = new AutoCompleteSource[stdv.Count];
1102                         stdv.CopyTo(arr, 0);
1103                         AutoCompleteSource[] arr2 = Array.FindAll(arr, delegate (AutoCompleteSource value) {
1104                                 // No "ListItems" in a TextBox.
1105                                 return value != AutoCompleteSource.ListItems;
1106                         });
1107                         return new StandardValuesCollection(arr2);
1108                 }
1109         }
1110 #endif
1111 }