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