* TreeView.cs: Don't draw the selected node when we lose
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / TextBoxBase.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-2005 Novell, Inc. (http://www.novell.com)
21 //
22 // Authors:
23 //      Peter Bartok    pbartok@novell.com
24 //
25 //
26
27 // NOT COMPLETE
28 #undef Debug
29
30 using System.ComponentModel;
31 using System.ComponentModel.Design;
32 using System.Drawing;
33 using System.Drawing.Text;
34 using System.Text;
35 using System.Runtime.InteropServices;
36
37 namespace System.Windows.Forms {
38         [DefaultEvent("TextChanged")]
39         [Designer("System.Windows.Forms.Design.TextBoxBaseDesigner, " + Consts.AssemblySystem_Design)]
40         public abstract class TextBoxBase : Control {
41                 #region Local Variables
42                 internal HorizontalAlignment    alignment;
43                 internal bool                   accepts_tab;
44                 internal bool                   accepts_return;
45                 internal bool                   auto_size;
46                 internal CharacterCasing        character_casing;
47                 internal bool                   undo;
48                 internal bool                   hide_selection;
49                 internal int                    max_length;
50                 internal bool                   modified;
51                 internal bool                   multiline;
52                 internal bool                   read_only;
53                 internal bool                   word_wrap;
54                 internal Document               document;
55                 internal LineTag                caret_tag;              // tag our cursor is in
56                 internal int                    caret_pos;              // position on the line our cursor is in (can be 0 = beginning of line)
57                 internal HScrollBar             hscroll;
58                 internal VScrollBar             vscroll;
59                 internal RichTextBoxScrollBars  scrollbars;
60                 internal bool                   grabbed;
61                 internal bool                   richtext;
62                 internal int                    requested_height;
63                 internal int                    canvas_width;
64                 internal int                    canvas_height;
65                 internal int                    track_width = 20;
66                 #if Debug
67                 internal static bool    draw_lines = false;
68                 #endif
69
70                 #endregion      // Local Variables
71
72                 #region Internal Constructor
73                 // Constructor will go when complete, only for testing - pdb
74                 internal TextBoxBase() {
75                         alignment = HorizontalAlignment.Left;
76                         accepts_return = false;
77                         accepts_tab = false;
78                         auto_size = true;
79                         border_style = BorderStyle.Fixed3D;
80                         character_casing = CharacterCasing.Normal;
81                         undo = false;
82                         hide_selection = true;
83                         max_length = 32767;
84                         modified = false;
85                         multiline = false;
86                         read_only = false;
87                         word_wrap = true;
88                         richtext = false;
89                         document = new Document(this);
90                         document.WidthChanged += new EventHandler(document_WidthChanged);
91                         document.HeightChanged += new EventHandler(document_HeightChanged);
92                         //document.CaretMoved += new EventHandler(CaretMoved);
93                         document.Wrap = false;
94                         requested_height = -1;
95
96                         MouseDown += new MouseEventHandler(TextBoxBase_MouseDown);
97                         MouseUp += new MouseEventHandler(TextBoxBase_MouseUp);
98                         MouseMove += new MouseEventHandler(TextBoxBase_MouseMove);
99                         SizeChanged += new EventHandler(TextBoxBase_SizeChanged);
100                         FontChanged += new EventHandler(TextBoxBase_FontOrColorChanged);
101                         ForeColorChanged += new EventHandler(TextBoxBase_FontOrColorChanged);
102                         
103                         scrollbars = RichTextBoxScrollBars.None;
104
105                         hscroll = new HScrollBar();
106                         hscroll.ValueChanged += new EventHandler(hscroll_ValueChanged);
107                         hscroll.control_style &= ~ControlStyles.Selectable;
108                         hscroll.Enabled = false;
109                         hscroll.Visible = false;
110
111                         vscroll = new VScrollBar();
112                         vscroll.ValueChanged += new EventHandler(vscroll_ValueChanged);
113                         vscroll.control_style &= ~ControlStyles.Selectable;
114                         vscroll.Enabled = false;
115                         vscroll.Visible = false;
116
117                         SuspendLayout ();
118                         this.Controls.AddImplicit (hscroll);
119                         this.Controls.AddImplicit (vscroll);
120                         ResumeLayout ();
121                         
122                         //SetStyle(ControlStyles.ResizeRedraw, true);
123                         SetStyle(ControlStyles.UserPaint | ControlStyles.StandardClick, false);
124
125                         canvas_width = ClientSize.Width;
126                         canvas_height = ClientSize.Height;
127
128                         CalculateScrollBars();
129                 }
130                 #endregion      // Internal Constructor
131
132                 #region Private and Internal Methods
133                 internal string CaseAdjust(string s) {
134                         if (character_casing == CharacterCasing.Normal) {
135                                 return s;
136                         }
137                         if (character_casing == CharacterCasing.Lower) {
138                                 return s.ToLower();
139                         } else {
140                                 return s.ToUpper();
141                         }
142                 }
143                 #endregion      // Private and Internal Methods
144
145                 #region Public Instance Properties
146                 [DefaultValue(false)]
147                 public bool AcceptsTab {
148                         get {
149                                 return accepts_tab;
150                         }
151
152                         set {
153                                 if (value != accepts_tab) {
154                                         accepts_tab = value;
155                                         OnAcceptsTabChanged(EventArgs.Empty);
156                                 }
157                         }
158                 }
159
160                 [DefaultValue(true)]
161                 [Localizable(true)]
162                 [RefreshProperties(RefreshProperties.Repaint)]
163                 public virtual bool AutoSize {
164                         get {
165                                 return auto_size;
166                         }
167
168                         set {
169                                 if (value != auto_size) {
170                                         auto_size = value;
171                                         if (auto_size) {
172                                                 if (PreferredHeight != ClientSize.Height) {
173                                                         ClientSize = new Size(ClientSize.Width, PreferredHeight);
174                                                 }
175                                         }
176                                         OnAutoSizeChanged(EventArgs.Empty);
177                                 }
178                         }
179                 }
180
181                 [DispId(-501)]
182                 public override System.Drawing.Color BackColor {
183                         get {
184                                 return base.BackColor;
185                         }
186                         set {
187                                 base.BackColor = value;
188                         }
189                 }
190
191                 [Browsable(false)]
192                 [EditorBrowsable(EditorBrowsableState.Never)]
193                 public override System.Drawing.Image BackgroundImage {
194                         get {
195                                 return base.BackgroundImage;
196                         }
197                         set {
198                                 base.BackgroundImage = value;
199                         }
200                 }
201
202                 [DefaultValue(BorderStyle.Fixed3D)]
203                 [DispId(-504)]
204                 public BorderStyle BorderStyle {
205                         get { return InternalBorderStyle; }
206                         set { 
207                                 InternalBorderStyle = value; 
208                                 OnBorderStyleChanged(EventArgs.Empty);
209                         }
210                 }
211
212                 [Browsable(false)]
213                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
214                 public bool CanUndo {
215                         get {
216                                 return undo;
217                         }
218                 }
219
220                 [DispId(-513)]
221                 public override System.Drawing.Color ForeColor {
222                         get {
223                                 return base.ForeColor;
224                         }
225                         set {
226                                 base.ForeColor = value;
227                         }
228                 }
229
230                 [DefaultValue(true)]
231                 public bool HideSelection {
232                         get {
233                                 return hide_selection;
234                         }
235
236                         set {
237                                 if (value != hide_selection) {
238                                         hide_selection = value;
239                                         OnHideSelectionChanged(EventArgs.Empty);
240                                 }
241                                 if (hide_selection) {
242                                         document.selection_visible = false;
243                                 } else {
244                                         document.selection_visible = true;
245                                 }
246                                 document.InvalidateSelectionArea();
247
248                         }
249                 }
250
251                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
252                 [Editor("System.Windows.Forms.Design.StringArrayEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
253                 [Localizable(true)]
254                 public string[] Lines {
255                         get {
256                                 string[]        lines;
257                                 int             i;
258                                 int             l;
259
260                                 l = document.Lines;
261                                 lines = new string[l];
262
263                                 for (i = 1; i <= l; i++) {
264                                         lines[i - 1] = document.GetLine(i).text.ToString();
265                                 }
266
267                                 return lines;
268                         }
269
270                         set {
271                                 int     i;
272                                 int     l;
273                                 Brush   brush;
274
275                                 document.Empty();
276
277                                 l = value.Length;
278                                 brush = ThemeEngine.Current.ResPool.GetSolidBrush(this.ForeColor);
279
280                                 for (i = 0; i < l; i++) {
281                                         document.Add(i+1, CaseAdjust(value[i]), alignment, Font, brush);
282                                 }
283                                 CalculateDocument();
284                                 OnTextChanged(EventArgs.Empty);
285                         }
286                 }
287
288                 [DefaultValue(32767)]
289                 [Localizable(true)]
290                 public virtual int MaxLength {
291                         get {
292                                 return max_length;
293                         }
294
295                         set {
296                                 if (value != max_length) {
297                                         max_length = value;
298                                 }
299                         }
300                 }
301
302                 [Browsable(false)]
303                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
304                 public bool Modified {
305                         get {
306                                 return modified;
307                         }
308
309                         set {
310                                 if (value != modified) {
311                                         modified = value;
312                                         OnModifiedChanged(EventArgs.Empty);
313                                 }
314                         }
315                 }
316
317                 [DefaultValue(false)]
318                 [Localizable(true)]
319                 [RefreshProperties(RefreshProperties.All)]
320                 public virtual bool Multiline {
321                         get {
322                                 return multiline;
323                         }
324
325                         set {
326                                 if (value != multiline) {
327                                         multiline = value;
328                                         // Make sure we update our size; the user may have already set the size before going to multiline
329                                         if (multiline && requested_height != -1) {
330                                                 Height = requested_height;
331                                                 requested_height = -1;
332                                         }
333
334                                         OnMultilineChanged(EventArgs.Empty);
335                                 }
336
337                                 document.multiline = multiline;
338
339                                 if (multiline) {
340                                         document.Wrap = word_wrap;
341                                 } else {
342                                         document.Wrap = false;
343                                 }
344                         }
345                 }
346
347                 [Browsable(false)]
348                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
349                 [EditorBrowsable(EditorBrowsableState.Advanced)]
350                 public int PreferredHeight {
351                         get {
352                                 return this.Font.Height + 7;    // FIXME - consider border style as well
353                         }
354                 }
355
356                 [DefaultValue(false)]
357                 public bool ReadOnly {
358                         get {
359                                 return read_only;
360                         }
361
362                         set {
363                                 if (value != read_only) {
364                                         read_only = value;
365                                         OnReadOnlyChanged(EventArgs.Empty);
366                                 }
367                         }
368                 }
369
370                 [Browsable(false)]
371                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
372                 public virtual string SelectedText {
373                         get {
374                                 return document.GetSelection();
375                         }
376
377                         set {
378                                 if (!read_only) {
379                                         document.ReplaceSelection(CaseAdjust(value));
380                                         OnTextChanged(EventArgs.Empty);
381                                 }
382                         }
383                 }
384
385                 [Browsable(false)]
386                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
387                 public virtual int SelectionLength {
388                         get {
389                                 return document.SelectionLength();
390                         }
391
392                         set {
393                                 if (value != 0) {
394                                         int     start;
395                                         Line    line;
396                                         LineTag tag;
397                                         int     pos;
398
399                                         start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
400
401                                         document.CharIndexToLineTag(start + value, out line, out tag, out pos);
402                                         document.SetSelectionEnd(line, pos);
403                                         document.PositionCaret(line, pos);
404                                 } else {
405                                         document.SetSelectionEnd(document.selection_start.line, document.selection_start.pos);
406                                         document.PositionCaret(document.selection_start.line, document.selection_start.pos);
407                                 }
408                         }
409                 }
410
411                 [Browsable(false)]
412                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
413                 public int SelectionStart {
414                         get {
415                                 int index;
416
417                                 index = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
418
419                                 return index;
420                         }
421
422                         set {
423                                 Line    line;
424                                 LineTag tag;
425                                 int     pos;
426
427                                 document.CharIndexToLineTag(value, out line, out tag, out pos);
428                                 document.SetSelectionStart(line, pos);
429                         }
430                 }
431
432                 [Localizable(true)]
433                 public override string Text {
434                         get {
435                                 if (document == null || document.Root == null || document.Root.text == null) {
436                                         return string.Empty;
437                                 }
438
439                                 if (!multiline) {
440                                         return document.Root.text.ToString();
441                                 } else {
442                                         StringBuilder   sb;
443                                         int             i;
444
445                                         sb = new StringBuilder();
446
447                                         for (i = 1; i < document.Lines; i++) {
448                                                 sb.Append(document.GetLine(i).text.ToString() + Environment.NewLine);
449                                         }
450                                         sb.Append(document.GetLine(i).text.ToString());
451                                         return sb.ToString();
452                                 }
453                         }
454
455                         set {
456                                 if (value == base.Text) {
457                                         return;
458                                 }
459
460                                 if (value != null) {
461                                         Line    line;
462
463                                         if (multiline) {
464                                                 string[]        lines;
465
466                                                 lines = value.Split(new char[] {'\n'});
467
468                                                 for (int i = 0; i < lines.Length; i++) {
469                                                         if (lines[i].EndsWith("\r")) {
470                                                                 lines[i] = lines[i].Substring(0, lines[i].Length - 1);
471                                                         }
472                                                 }
473                                                 this.Lines = lines;
474
475                                                 line = document.GetLine(1);
476                                                 document.SetSelectionStart(line, 0);
477
478                                                 line = document.GetLine(document.Lines);
479                                                 document.SetSelectionEnd(line, line.text.Length);
480                                                 document.PositionCaret(line, line.text.Length);
481                                         } else {
482                                                 document.Clear();
483                                                 document.Add(1, CaseAdjust(value), alignment, Font, ThemeEngine.Current.ResPool.GetSolidBrush(ForeColor));
484                                                 CalculateDocument();
485                                                 line = document.GetLine(1);
486                                                 document.SetSelectionStart(line, 0);
487                                                 document.SetSelectionEnd(line, value.Length);
488                                                 document.PositionCaret(line, value.Length);
489                                         }
490                                 }
491                                 base.Text = value;
492                                 OnTextChanged(EventArgs.Empty);
493                         }
494                 }
495
496                 [Browsable(false)]
497                 public virtual int TextLength {
498                         get {
499                                 if (document == null || document.Root == null || document.Root.text == null) {
500                                         return 0;
501                                 }
502
503                                 if (!multiline) {
504                                         return document.Root.text.Length;
505                                 } else {
506                                         int     total;
507                                         int     i;
508
509                                         total = 0;
510                                         for (i = 1; i < document.Lines; i++) {
511                                                 total += document.GetLine(i).text.Length + Environment.NewLine.Length;
512                                         }
513                                         total += document.GetLine(i).text.Length;
514
515                                         return total;
516                                 }
517                         }
518                 }
519
520                 [DefaultValue(true)]
521                 [Localizable(true)]
522                 public bool WordWrap {
523                         get {
524                                 return word_wrap;
525                         }
526
527                         set {
528                                 if (value != word_wrap) {
529                                         if (multiline) {
530                                                 word_wrap = value;
531                                                 document.Wrap = value;
532                                         }
533                                 }
534                         }
535                 }
536                 #endregion      // Public Instance Properties
537
538                 #region Protected Instance Properties
539                 protected override CreateParams CreateParams {
540                         get {
541                                 return base.CreateParams;
542                         }
543                 }
544
545                 protected override System.Drawing.Size DefaultSize {
546                         get {
547                                 return base.DefaultSize;
548                         }
549                 }
550                 #endregion      // Protected Instance Properties
551
552                 #region Public Instance Methods
553                 public void AppendText(string text) {
554                         if (multiline) {
555                                 string[]        lines;
556                                 int             linecount;
557
558                                 // Break the string into separate lines
559                                 lines = text.Split(new char[] {'\n'});
560                                 linecount = lines.Length;
561                                 for (int i = 0; i < linecount; i++) {
562                                         if (lines[i].EndsWith("\r")) {
563                                                 lines[i] = lines[i].Substring(0, lines[i].Length - 1);
564                                         }
565                                 }
566
567                                 // Grab the formatting for the last element
568                                 document.MoveCaret(CaretDirection.CtrlEnd);
569
570                                 // Insert the first line
571                                 document.InsertString(document.CaretLine, document.CaretPosition, lines[0]);
572
573                                 for (int i = 1; i < linecount; i++) {
574                                         document.Add(document.CaretLine.LineNo+i, CaseAdjust(lines[i]), alignment, document.CaretTag.font, document.CaretTag.color);
575                                 }
576
577                                 CalculateDocument();
578                                 document.MoveCaret(CaretDirection.CtrlEnd);
579                         } else {
580                                 document.MoveCaret(CaretDirection.CtrlEnd);
581                                 document.InsertStringAtCaret(text, true);
582 //blah Console.WriteLine("TextBox.cs(582) Invalidate called in AppendText");
583                                 Invalidate();
584                         }
585                         OnTextChanged(EventArgs.Empty);
586                 }
587
588                 public void Clear() {
589                         Text = null;
590                 }
591
592                 public void ClearUndo() {
593                         // FIXME
594                         throw new NotImplementedException();
595                 }
596
597                 public void Copy() {
598                         // FIXME
599                         throw new NotImplementedException();
600                 }
601
602                 public void Cut() {
603                         // FIXME
604                         throw new NotImplementedException();
605                 }
606
607                 public void Paste() {
608                         // FIXME
609                         throw new NotImplementedException();
610                 }
611
612                 public void ScrollToCaret() {
613                         // FIXME
614                         throw new NotImplementedException();
615                 }
616
617                 public void Select(int start, int length) {
618                         SelectionStart = start;
619                         SelectionLength = length;
620                 }
621
622
623                 public void SelectAll() {
624                         Line    last;
625
626                         last = document.GetLine(document.Lines);
627                         document.SetSelectionStart(document.GetLine(1), 0);
628                         document.SetSelectionEnd(last, last.text.Length);
629                 }
630
631                 public override string ToString() {
632                         return Text;
633                 }
634
635                 public void Undo() {
636                         return;
637                 }
638                 #endregion      // Public Instance Methods
639
640                 #region Protected Instance Methods
641                 protected override void CreateHandle() {
642                         base.CreateHandle ();
643                 }
644
645                 protected override bool IsInputKey(Keys keyData) {
646                         switch (keyData) {
647 #if not
648                                 // We handle Enter in ProcessDialogKey
649                                 case Keys.Enter: {
650                                         if (multiline && (accepts_return || ((keyData & Keys.Control) != 0))) {
651                                                 return true;
652                                         }
653                                         return false;
654                                 }
655 #endif
656
657                                 case Keys.Tab: {
658                                         if (accepts_tab && multiline) {
659                                                 return true;
660                                         }
661                                         return false;
662                                 }
663                         }
664                         return false;
665                 }
666
667
668                 protected virtual void OnAcceptsTabChanged(EventArgs e) {
669                         if (AcceptsTabChanged != null) {
670                                 AcceptsTabChanged(this, e);
671                         }
672                 }
673
674                 protected virtual void OnAutoSizeChanged(EventArgs e) {
675                         if (AutoSizeChanged != null) {
676                                 AutoSizeChanged(this, e);
677                         }
678                 }
679
680                 protected virtual void OnBorderStyleChanged(EventArgs e) {
681                         if (BorderStyleChanged != null) {
682                                 BorderStyleChanged(this, e);
683                         }
684                 }
685
686                 protected override void OnFontChanged(EventArgs e) {
687                         base.OnFontChanged (e);
688
689                         if (auto_size) {
690                                 if (PreferredHeight != ClientSize.Height) {
691                                         Height = PreferredHeight;
692                                 }
693                         }
694                 }
695
696                 protected override void OnHandleCreated(EventArgs e) {
697                         base.OnHandleCreated (e);
698                 }
699
700                 protected override void OnHandleDestroyed(EventArgs e) {
701                         base.OnHandleDestroyed (e);
702                 }
703
704                 protected virtual void OnHideSelectionChanged(EventArgs e) {
705                         if (HideSelectionChanged != null) {
706                                 HideSelectionChanged(this, e);
707                         }
708                 }
709
710                 protected virtual void OnModifiedChanged(EventArgs e) {
711                         if (ModifiedChanged != null) {
712                                 ModifiedChanged(this, e);
713                         }
714                 }
715
716                 protected virtual void OnMultilineChanged(EventArgs e) {
717                         if (MultilineChanged != null) {
718                                 MultilineChanged(this, e);
719                         }
720                 }
721
722                 protected virtual void OnReadOnlyChanged(EventArgs e) {
723                         if (ReadOnlyChanged != null) {
724                                 ReadOnlyChanged(this, e);
725                         }
726                 }
727
728                 protected override bool ProcessDialogKey(Keys keyData) {
729                         switch (keyData & Keys.KeyCode) {
730                                 case Keys.Left: {
731                                         document.SetSelectionToCaret(true);
732
733                                         if ((Control.ModifierKeys & Keys.Control) != 0) {
734                                                 document.MoveCaret(CaretDirection.WordBack);
735                                         } else {
736                                                 document.MoveCaret(CaretDirection.CharBack);
737                                         }
738                                         CaretMoved(this, null);
739                                         return true;
740                                 }
741
742                                 case Keys.Right: {
743                                         document.SetSelectionToCaret(true);
744
745                                         if ((Control.ModifierKeys & Keys.Control) != 0) {
746                                                 document.MoveCaret(CaretDirection.WordForward);
747                                         } else {
748                                                 document.MoveCaret(CaretDirection.CharForward);
749                                         }
750                                         CaretMoved(this, null);
751                                         return true;
752                                 }
753
754                                 case Keys.Up: {
755                                         document.SetSelectionToCaret(true);
756                                         document.MoveCaret(CaretDirection.LineUp);
757                                         CaretMoved(this, null);
758                                         return true;
759                                 }
760
761                                 case Keys.Down: {
762                                         document.SetSelectionToCaret(true);
763                                         document.MoveCaret(CaretDirection.LineDown);
764                                         CaretMoved(this, null);
765                                         return true;
766                                 }
767
768                                 case Keys.Home: {
769                                         document.SetSelectionToCaret(true);
770
771                                         if ((Control.ModifierKeys & Keys.Control) != 0) {
772                                                 document.MoveCaret(CaretDirection.CtrlHome);
773                                         } else {
774                                                 document.MoveCaret(CaretDirection.Home);
775                                         }
776                                         CaretMoved(this, null);
777                                         return true;
778                                 }
779
780                                 case Keys.End: {
781                                         document.SetSelectionToCaret(true);
782
783                                         if ((Control.ModifierKeys & Keys.Control) != 0) {
784                                                 document.MoveCaret(CaretDirection.CtrlEnd);
785                                         } else {
786                                                 document.MoveCaret(CaretDirection.End);
787                                         }
788                                         CaretMoved(this, null);
789                                         return true;
790                                 }
791
792                                 case Keys.Enter: {
793                                         // ignoring accepts_return, fixes bug #76355
794                                         if (!read_only && multiline && (accepts_return || (FindForm().AcceptButton == null) || ((Control.ModifierKeys & Keys.Control) != 0))) {
795                                                 Line    line;
796
797                                                 if (document.selection_visible) {
798                                                         document.ReplaceSelection("");
799                                                 }
800                                                 document.SetSelectionToCaret(true);
801
802                                                 line = document.CaretLine;
803
804                                                 document.Split(document.CaretLine, document.CaretTag, document.CaretPosition, false);
805                                                 OnTextChanged(EventArgs.Empty);
806                                                 document.UpdateView(line, 2, 0);
807                                                 document.MoveCaret(CaretDirection.CharForward);
808                                                 CaretMoved(this, null);
809                                                 return true;
810                                         }
811                                         break;
812                                 }
813
814                                 case Keys.Tab: {
815                                         if (!read_only && accepts_tab && multiline) {
816                                                 document.InsertChar(document.CaretLine, document.CaretPosition, '\t');
817                                                 if (document.selection_visible) {
818                                                         document.ReplaceSelection("");
819                                                 }
820                                                 document.SetSelectionToCaret(true);
821
822                                                 OnTextChanged(EventArgs.Empty);
823                                                 CaretMoved(this, null);
824                                                 return true;
825                                         }
826                                         break;
827                                 }
828
829
830                                 case Keys.Back: {
831                                         if (read_only) {
832                                                 break;
833                                         }
834
835                                         // delete only deletes on the line, doesn't do the combine
836                                         if (document.selection_visible) {
837                                                 document.ReplaceSelection("");
838                                         }
839                                         document.SetSelectionToCaret(true);
840                                         if (document.CaretPosition == 0) {
841                                                 if (document.CaretLine.LineNo > 1) {
842                                                         Line    line;
843                                                         int     new_caret_pos;
844
845                                                         line = document.GetLine(document.CaretLine.LineNo - 1);
846                                                         new_caret_pos = line.text.Length;
847
848                                                         document.Combine(line, document.CaretLine);
849                                                         document.UpdateView(line, 1, 0);
850                                                         document.PositionCaret(line, new_caret_pos);
851                                                         document.MoveCaret(CaretDirection.CharForward);
852                                                         document.UpdateCaret();
853                                                         OnTextChanged(EventArgs.Empty);
854                                                 }
855                                         } else {
856                                                 document.DeleteChar(document.CaretTag, document.CaretPosition, false);
857                                                 document.MoveCaret(CaretDirection.CharBack);
858                                                 OnTextChanged(EventArgs.Empty);
859                                         }
860                                         CaretMoved(this, null);
861                                         return true;
862                                 }
863
864                                 case Keys.Delete: {
865                                         if (read_only) {
866                                                 break;
867                                         }
868
869                                         // delete only deletes on the line, doesn't do the combine
870                                         if (document.CaretPosition == document.CaretLine.text.Length) {
871                                                 if (document.CaretLine.LineNo < document.Lines) {
872                                                         Line    line;
873
874                                                         line = document.GetLine(document.CaretLine.LineNo + 1);
875                                                         document.Combine(document.CaretLine, line);
876                                                         document.UpdateView(document.CaretLine, 2, 0);
877                                                         OnTextChanged(EventArgs.Empty);
878
879                                                         #if not_Debug
880                                                         Line    check_first;
881                                                         Line    check_second;
882
883                                                         check_first = document.GetLine(document.CaretLine.LineNo);
884                                                         check_second = document.GetLine(check_first.line_no + 1);
885
886                                                         Console.WriteLine("Post-UpdateView: Y of first line: {0}, second line: {1}", check_first.Y, check_second.Y);
887                                                         #endif
888
889                                                         // Caret doesn't move
890                                                 }
891                                         } else {
892                                                 document.DeleteChar(document.CaretTag, document.CaretPosition, true);
893                                                 OnTextChanged(EventArgs.Empty);
894                                         }
895                                         document.AlignCaret();
896                                         document.UpdateCaret();
897                                         CaretMoved(this, null);
898                                         return true;
899                                 }
900                         }
901                         return base.ProcessDialogKey (keyData);
902                 }
903
904                 protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) {
905                         // Make sure we don't get sized bigger than we want to be
906                         if (!richtext) {
907                                 if (!multiline) {
908                                         if (height > PreferredHeight) {
909                                                 requested_height = height;
910                                                 height = PreferredHeight;
911                                                 specified |= BoundsSpecified.Height;
912                                         }
913                                 }
914                         }
915
916                         document.ViewPortWidth = width;
917                         document.ViewPortHeight = height;
918
919                         CalculateDocument();
920
921                         base.SetBoundsCore (x, y, width, height, specified);
922                 }
923
924                 protected override void WndProc(ref Message m) {
925                         switch ((Msg)m.Msg) {
926                                 case Msg.WM_PAINT: {
927                                         PaintEventArgs  paint_event;
928
929                                         paint_event = XplatUI.PaintEventStart(Handle, true);
930                                         
931                                         PaintControl(paint_event);
932                                         XplatUI.PaintEventEnd(Handle, true);
933                                         DefWndProc(ref m);
934                                         return;
935                                 }
936
937                                 case Msg.WM_SETFOCUS: {
938                                         // Set caret
939                                         document.CaretHasFocus();
940 Console.WriteLine("Creating caret");
941                                         base.WndProc(ref m);
942                                         return;
943                                 }
944
945                                 case Msg.WM_KILLFOCUS: {
946                                         // Kill caret
947                                         document.CaretLostFocus();
948 Console.WriteLine("Destroying caret");
949                                         base.WndProc(ref m);
950                                         return;
951                                 }
952
953                                 case Msg.WM_CHAR: {
954                                         if (ProcessKeyEventArgs(ref m)) {
955                                                 return;
956                                         }
957
958                                         if (PreProcessMessage(ref m)) {
959                                                 return;
960                                         }
961
962                                         if (ProcessKeyMessage(ref m)) {
963                                                 return;
964                                         }
965
966                                         if (!read_only && (m.WParam.ToInt32() >= 32)) { // FIXME, tabs should probably go through
967                                                 if (document.selection_visible) {
968                                                         document.ReplaceSelection("");
969                                                 }
970
971                                                 switch (character_casing) {
972                                                         case CharacterCasing.Normal: {
973                                                                 document.InsertCharAtCaret((char)m.WParam, true);
974                                                                 OnTextChanged(EventArgs.Empty);
975                                                                 CaretMoved(this, null);
976                                                                 return;
977                                                         }
978
979                                                         case CharacterCasing.Lower: {
980                                                                 document.InsertCharAtCaret(Char.ToLower((char)m.WParam), true);
981                                                                 OnTextChanged(EventArgs.Empty);
982                                                                 CaretMoved(this, null);
983                                                                 return;
984                                                         }
985
986                                                         case CharacterCasing.Upper: {
987                                                                 document.InsertCharAtCaret(Char.ToUpper((char)m.WParam), true);
988                                                                 OnTextChanged(EventArgs.Empty);
989                                                                 CaretMoved(this, null);
990                                                                 return;
991                                                         }
992                                                 }
993                                         }
994                                         DefWndProc(ref m);
995                                         return;
996                                 }
997
998                                 default: {
999                                         base.WndProc(ref m);
1000                                         return;
1001                                 }
1002                         }
1003                 }
1004
1005                 #endregion      // Protected Instance Methods
1006
1007                 #region Events
1008                 public event EventHandler       AcceptsTabChanged;
1009                 public event EventHandler       AutoSizeChanged;
1010                 [Browsable(false)]
1011                 [EditorBrowsable(EditorBrowsableState.Never)]
1012                 public new event EventHandler BackgroundImageChanged {
1013                         add { base.BackgroundImageChanged += value; }
1014                         remove { base.BackgroundImageChanged -= value; }
1015                 }
1016                 public event EventHandler       BorderStyleChanged;
1017                 [Browsable(false)]
1018                 [EditorBrowsable(EditorBrowsableState.Advanced)]
1019                 public event EventHandler       Click;
1020                 public event EventHandler       HideSelectionChanged;
1021                 public event EventHandler       ModifiedChanged;
1022                 public event EventHandler       MultilineChanged;
1023                 [Browsable(false)]
1024                 [EditorBrowsable(EditorBrowsableState.Never)]
1025                 public event PaintEventHandler  Paint;
1026                 public event EventHandler       ReadOnlyChanged;
1027                 #endregion      // Events
1028
1029                 #region Private Methods
1030                 internal Document Document {
1031                         get {
1032                                 return document;
1033                         }
1034
1035                         set {
1036                                 document = value;
1037                         }
1038                 }
1039
1040 static int current;
1041
1042                 private void PaintControl(PaintEventArgs pevent) {
1043                         // Fill background
1044                         pevent.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(BackColor), pevent.ClipRectangle);
1045                         pevent.Graphics.TextRenderingHint=TextRenderingHint.AntiAlias;
1046 //blah Console.WriteLine("Redrawing {0}", pevent.ClipRectangle);
1047                         // Draw the viewable document
1048                         document.Draw(pevent.Graphics, pevent.ClipRectangle);
1049
1050                         Rectangle       rect = ClientRectangle;
1051                         rect.Width--;
1052                         rect.Height--;
1053                         //pevent.Graphics.DrawRectangle(ThemeEngine.Current.ResPool.GetPen(ThemeEngine.Current.ColorControlDark), rect);
1054
1055                         #if Debug
1056                                 int             start;
1057                                 int             end;
1058                                 Line            line;
1059                                 int             line_no;
1060                                 Pen             p;
1061
1062                                 p = new Pen(Color.Red, 1);
1063
1064                                 // First, figure out from what line to what line we need to draw
1065                                 start = document.GetLineByPixel(pevent.ClipRectangle.Top - document.ViewPortY, false).line_no;
1066                                 end = document.GetLineByPixel(pevent.ClipRectangle.Bottom - document.ViewPortY, false).line_no;
1067
1068                                 //Console.WriteLine("Starting drawing on line '{0}'", document.GetLine(start));
1069                                 //Console.WriteLine("Ending drawing on line '{0}'", document.GetLine(end));
1070
1071                                 line_no = start;
1072                                 while (line_no <= end) {
1073                                         line = document.GetLine(line_no);
1074
1075                                         if (draw_lines) {
1076                                                 for (int i = 0; i < line.text.Length; i++) {
1077                                                         pevent.Graphics.DrawLine(p, (int)line.widths[i] - document.ViewPortX, line.Y - document.ViewPortY, (int)line.widths[i] - document.ViewPortX, line.Y + line.height  - document.ViewPortY);
1078                                                 }
1079                                         }
1080
1081                                         line_no++;
1082                                 }
1083                         #endif
1084                 }
1085
1086                 private void TextBoxBase_MouseDown(object sender, MouseEventArgs e) {
1087                         if (e.Button == MouseButtons.Left) {
1088                                 document.PositionCaret(e.X + document.ViewPortX, e.Y + document.ViewPortY);
1089                                 document.SetSelectionToCaret(true);
1090                                 this.grabbed = true;
1091                                 this.Capture = true;
1092                                 return;
1093                         }
1094
1095                         #if Debug
1096                                 LineTag tag;
1097                                 Line    line;
1098                                 int     pos;
1099
1100                                 if (e.Button == MouseButtons.Right) {
1101                                         draw_lines = !draw_lines;
1102                                         this.Invalidate();
1103                                         Console.WriteLine("SelectedText: {0}, length {1}", this.SelectedText, this.SelectionLength);
1104                                         Console.WriteLine("Selection start: {0}", this.SelectionStart);
1105
1106                                         this.SelectionStart = 10;
1107                                         this.SelectionLength = 5;
1108
1109                                         return;
1110                                 }
1111
1112                                 tag = document.FindTag(e.X + document.ViewPortX, e.Y + document.ViewPortY, out pos, false);
1113
1114                                 Console.WriteLine("Click found tag {0}, character {1}", tag, pos);
1115                                 line = tag.line;
1116                                 switch(current) {
1117                                         case 4: LineTag.FormatText(tag.line, pos, (pos+10)<line.Text.Length ? 10 : line.Text.Length - pos+1, new Font("impact", 20, FontStyle.Bold, GraphicsUnit.Pixel), ThemeEngine.Current.ResPool.GetSolidBrush(Color.Red)); break;
1118                                         case 1: LineTag.FormatText(tag.line, pos, (pos+10)<line.Text.Length ? 10 : line.Text.Length - pos+1, new Font("arial unicode ms", 24, FontStyle.Italic, GraphicsUnit.Pixel), ThemeEngine.Current.ResPool.GetSolidBrush(Color.DarkGoldenrod)); break;
1119                                         case 2: LineTag.FormatText(tag.line, pos, (pos+10)<line.Text.Length ? 10 : line.Text.Length - pos+1, new Font("arial", 10, FontStyle.Regular, GraphicsUnit.Pixel), ThemeEngine.Current.ResPool.GetSolidBrush(Color.Aquamarine)); break;
1120                                         case 3: LineTag.FormatText(tag.line, pos, (pos+10)<line.Text.Length ? 10 : line.Text.Length - pos+1, new Font("times roman", 16, FontStyle.Underline, GraphicsUnit.Pixel), ThemeEngine.Current.ResPool.GetSolidBrush(Color.Turquoise)); break;
1121                                         case 0: LineTag.FormatText(tag.line, pos, (pos+10)<line.Text.Length ? 10 : line.Text.Length - pos+1, new Font("times roman", 64, FontStyle.Italic | FontStyle.Bold, GraphicsUnit.Pixel), ThemeEngine.Current.ResPool.GetSolidBrush(Color.LightSeaGreen)); break;
1122                                         case 5: LineTag.FormatText(tag.line, pos, (pos+10)<line.Text.Length ? 10 : line.Text.Length - pos+1, ((TextBoxBase)sender).Font, ThemeEngine.Current.ResPool.GetSolidBrush(ForeColor)); break;
1123                                 }
1124                                 current++;
1125                                 if (current==6) {
1126                                         current=0;
1127                                 }
1128
1129                                 // Update/Recalculate what we see
1130                                 document.UpdateView(line, 0);
1131
1132                                 // Make sure our caret is properly positioned and sized
1133                                 document.AlignCaret();
1134                         #endif
1135                 }
1136
1137                 private void TextBoxBase_MouseUp(object sender, MouseEventArgs e) {
1138                         this.Capture = false;
1139                         this.grabbed = false;
1140                         if (e.Button == MouseButtons.Left) {
1141                                 document.PositionCaret(e.X + document.ViewPortX, e.Y + document.ViewPortY);
1142                                 document.SetSelectionToCaret(false);
1143                                 document.DisplayCaret();
1144                                 return;
1145                         }
1146                 }
1147                 #endregion      // Private Methods
1148
1149
1150                 private void TextBoxBase_SizeChanged(object sender, EventArgs e) {
1151                         canvas_width = ClientSize.Width;
1152                         canvas_height = ClientSize.Height;
1153
1154                         // We always move them, they just might not be displayed
1155                         hscroll.Bounds = new Rectangle (ClientRectangle.Left, ClientRectangle.Bottom - hscroll.Height, ClientSize.Width, hscroll.Height);
1156                         vscroll.Bounds = new Rectangle (ClientRectangle.Right - vscroll.Width, ClientRectangle.Top, vscroll.Width, ClientSize.Height);
1157                         
1158                 }
1159
1160                 internal void CalculateDocument() {
1161                         if (!IsHandleCreated) {
1162                                 return;
1163                         }
1164                         document.RecalculateDocument(CreateGraphics());
1165                         CalculateScrollBars();
1166 //blah Console.WriteLine("TextBox.cs(1175) Invalidate called in CalculateDocument");
1167                         Invalidate();   // FIXME - do we need this?
1168                 }
1169
1170                 internal void CalculateScrollBars() {
1171                         // FIXME - need separate calculations for center and right alignment
1172                         // No scrollbars for a single line
1173                         if (document.Width >= ClientSize.Width) {
1174                                 hscroll.Enabled = true;
1175                                 hscroll.Minimum = 0;
1176                                 hscroll.Maximum = document.Width - ClientSize.Width;
1177                         } else {
1178                                 hscroll.Maximum = document.ViewPortWidth;
1179                                 hscroll.Enabled = false;
1180                         }
1181
1182                         if (document.Height >= ClientSize.Height) {
1183                                 vscroll.Enabled = true;
1184                                 vscroll.Minimum = 0;
1185                                 vscroll.Maximum = document.Height - ClientSize.Height;
1186                         } else {
1187                                 vscroll.Maximum = document.ViewPortHeight;
1188                                 vscroll.Enabled = false;
1189                         }
1190
1191
1192                         if (!multiline) {
1193                                 return;
1194                         }
1195
1196                         if (!WordWrap) {
1197                                 if ((scrollbars & RichTextBoxScrollBars.Horizontal) != 0) {
1198                                         if (((scrollbars & RichTextBoxScrollBars.ForcedHorizontal) != 0) || hscroll.Enabled) {
1199                                                 hscroll.Visible = true;
1200                                         }
1201                                 }
1202                         }
1203
1204                         if ((scrollbars & RichTextBoxScrollBars.Vertical) != 0) {
1205                                 if (((scrollbars & RichTextBoxScrollBars.ForcedVertical) != 0) || vscroll.Enabled) {
1206                                         vscroll.Visible = true;
1207                                 }
1208                         }
1209
1210                         if (hscroll.Visible) {
1211                                 vscroll.Maximum += hscroll.Height;
1212                                 canvas_height = ClientSize.Height - hscroll.Height;
1213                         }
1214
1215                         if (vscroll.Visible) {
1216                                 hscroll.Maximum += vscroll.Width * 2;
1217                                 canvas_width = ClientSize.Width - vscroll.Width * 2;
1218                         }
1219                 }
1220
1221                 private void document_WidthChanged(object sender, EventArgs e) {
1222                         CalculateScrollBars();
1223                 }
1224
1225                 private void document_HeightChanged(object sender, EventArgs e) {
1226                         CalculateScrollBars();
1227                 }
1228
1229                 private void hscroll_ValueChanged(object sender, EventArgs e) {
1230                         XplatUI.ScrollWindow(this.Handle, document.ViewPortX-this.hscroll.Value, 0, false);
1231                         document.ViewPortX = this.hscroll.Value;
1232                         document.UpdateCaret();
1233                         //Console.WriteLine("Dude scrolled horizontal");
1234                 }
1235
1236                 private void vscroll_ValueChanged(object sender, EventArgs e) {
1237                         XplatUI.ScrollWindow(this.Handle, 0, document.ViewPortY-this.vscroll.Value, false);
1238                         document.ViewPortY = this.vscroll.Value;
1239                         document.UpdateCaret();
1240                         //Console.WriteLine("Dude scrolled vertical");
1241                 }
1242
1243                 private void TextBoxBase_MouseMove(object sender, MouseEventArgs e) {
1244                         // FIXME - handle auto-scrolling if mouse is to the right/left of the window
1245                         if (grabbed) {
1246                                 document.PositionCaret(e.X + document.ViewPortX, e.Y + document.ViewPortY);
1247                                 document.SetSelectionToCaret(false);
1248                                 document.DisplayCaret();
1249                         }
1250                 }
1251                                                                               
1252                 private void TextBoxBase_FontOrColorChanged(object sender, EventArgs e) {
1253                         if (!richtext) {
1254                                 Line    line;
1255
1256                                 // Font changes apply to the whole document
1257                                 for (int i = 1; i <= document.Lines; i++) {
1258                                         line = document.GetLine(i);
1259                                         LineTag.FormatText(line, 1, line.text.Length, Font, ThemeEngine.Current.ResPool.GetSolidBrush(ForeColor));
1260                                         document.UpdateView(line, 0);
1261                                 }
1262                                 // Make sure the caret height is matching the new font height
1263                                 document.AlignCaret();
1264                         }
1265                 }
1266
1267                 /// <summary>Ensure the caret is always visible</summary>
1268                 internal void CaretMoved(object sender, EventArgs e) {
1269                         Point   pos;
1270                         int     height;
1271                         
1272                         pos = document.Caret;
1273                         //Console.WriteLine("Caret now at {0} (Thumb: {1}x{2}, Canvas: {3}x{4}, Document {5}x{6})", pos, hscroll.Value, vscroll.Value, canvas_width, canvas_height, document.Width, document.Height);
1274
1275                         // Handle horizontal scrolling
1276                         if (document.CaretLine.alignment == HorizontalAlignment.Left) {
1277                                 if (pos.X < (document.ViewPortX + track_width)) {
1278                                         do {
1279                                                 if ((hscroll.Value - track_width) >= hscroll.Minimum) {
1280                                                         hscroll.Value -= track_width;
1281                                                 } else {
1282                                                         hscroll.Value = hscroll.Minimum;
1283                                                 }
1284                                         } while (hscroll.Value > pos.X);
1285                                 }
1286
1287                                 if ((pos.X > (this.canvas_width + document.ViewPortX - track_width)) && (hscroll.Value != hscroll.Maximum)) {
1288                                         do {
1289                                                 if ((hscroll.Value + track_width) <= hscroll.Maximum) {
1290                                                         hscroll.Value += track_width;
1291                                                 } else {
1292                                                         hscroll.Value = hscroll.Maximum;
1293                                                 }
1294                                         } while (pos.X > (hscroll.Value + this.canvas_width));
1295                                 }
1296                         } else if (document.CaretLine.alignment == HorizontalAlignment.Right) {
1297                                 if (pos.X < document.ViewPortX) {
1298                                         if (pos.X > hscroll.Minimum) {
1299                                                 hscroll.Value = pos.X;
1300                                         } else {
1301                                                 hscroll.Value = hscroll.Minimum;
1302                                         }
1303                                 }
1304
1305                                 if ((pos.X > (this.canvas_width + document.ViewPortX)) && (hscroll.Value != hscroll.Maximum)) {
1306                                         hscroll.Value = hscroll.Maximum;
1307                                 }
1308                         } else {
1309                         }
1310
1311                         if (!multiline) {
1312                                 return;
1313                         }
1314
1315                         // Handle vertical scrolling
1316                         height = document.CaretLine.Height;
1317
1318                         if (pos.Y < document.ViewPortY) {
1319                                 vscroll.Value = pos.Y;
1320                         }
1321
1322                         if ((pos.Y + height) > (document.ViewPortY + canvas_height)) {
1323                                 vscroll.Value = pos.Y - canvas_height + height;
1324                         }
1325                 }
1326         }
1327 }