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