Changing local method variables doesn't make sense.
[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 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
31 using System.Drawing;
32 using System.Drawing.Text;
33 using System.Text;
34
35 namespace System.Windows.Forms {
36         public abstract class TextBoxBase : Control {
37                 #region Local Variables
38                 internal HorizontalAlignment    alignment;
39                 internal bool                   accepts_tab;
40                 internal bool                   accepts_return;
41                 internal bool                   auto_size;
42                 internal CharacterCasing        character_casing;
43                 internal bool                   undo;
44                 internal bool                   hide_selection;
45                 internal int                    max_length;
46                 internal bool                   modified;
47                 internal bool                   multiline;
48                 internal bool                   read_only;
49                 internal bool                   word_wrap;
50                 internal Document               document;
51                 internal LineTag                caret_tag;              // tag our cursor is in
52                 internal int                    caret_pos;              // position on the line our cursor is in (can be 0 = beginning of line)
53                 internal int                    viewport_x;             // left visible pixel
54                 internal int                    viewport_y;             // top visible pixel
55                 internal HScrollBar             hscroll;
56                 internal VScrollBar             vscroll;
57                 internal ScrollBars             scrollbars;
58                 internal bool                   grabbed;
59                 internal bool                   richtext;
60                 internal Rectangle              text_bounds;
61
62                 #if Debug
63                 internal static bool    draw_lines = false;
64                 #endif
65
66                 #endregion      // Local Variables
67
68                 #region Private Constructor
69                 // Constructor will go when complete, only for testing - pdb
70                 public TextBoxBase() {
71                         alignment = HorizontalAlignment.Left;
72                         accepts_return = false;
73                         accepts_tab = false;
74                         auto_size = true;
75                         border_style = BorderStyle.Fixed3D;
76                         character_casing = CharacterCasing.Normal;
77                         undo = false;
78                         hide_selection = true;
79                         max_length = 32767;
80                         modified = false;
81                         multiline = false;
82                         read_only = false;
83                         word_wrap = true;
84                         richtext = false;
85                         document = new Document(this);
86                         text_bounds = Rectangle.Empty;
87
88                         MouseDown += new MouseEventHandler(TextBoxBase_MouseDown);
89                         MouseUp += new MouseEventHandler(TextBoxBase_MouseUp);
90                         MouseMove += new MouseEventHandler(TextBoxBase_MouseMove);
91                         SizeChanged += new EventHandler(TextBoxBase_SizeChanged);
92                         FontChanged += new EventHandler(TextBoxBase_FontOrColorChanged);
93                         ForeColorChanged += new EventHandler(TextBoxBase_FontOrColorChanged);
94
95                         
96                         scrollbars = ScrollBars.None;
97
98                         hscroll = new HScrollBar();
99                         hscroll.ValueChanged +=new EventHandler(hscroll_ValueChanged);
100                         hscroll.Enabled = true;
101                         hscroll.Visible = false;
102
103                         vscroll = new VScrollBar();
104                         vscroll.Visible = false;
105
106                         this.Controls.Add(hscroll);
107                         this.Controls.Add(vscroll);
108
109                         //SetStyle(ControlStyles.ResizeRedraw, true);
110                         SetStyle(ControlStyles.AllPaintingInWmPaint, true);
111                         SetStyle(ControlStyles.UserPaint, true);
112                 }
113                 #endregion      // Private Constructor
114
115                 #region Private and Internal Methods
116                 internal string CaseAdjust(string s) {
117                         if (character_casing == CharacterCasing.Normal) {
118                                 return s;
119                         }
120                         if (character_casing == CharacterCasing.Lower) {
121                                 return s.ToLower();
122                         } else {
123                                 return s.ToUpper();
124                         }
125                 }
126                 #endregion      // Private and Internal Methods
127
128                 #region Public Instance Properties
129                 public bool AcceptsTab {
130                         get {
131                                 return accepts_tab;
132                         }
133
134                         set {
135                                 if (value != accepts_tab) {
136                                         accepts_tab = value;
137                                         OnAcceptsTabChanged(EventArgs.Empty);
138                                 }
139                         }
140                 }
141
142                 public virtual bool AutoSize {
143                         get {
144                                 return auto_size;
145                         }
146
147                         set {
148                                 if (value != auto_size) {
149                                         auto_size = value;
150                                         if (auto_size) {
151                                                 if (PreferredHeight != Height) {
152                                                         Height = PreferredHeight;
153                                                 }
154                                         }
155                                         OnAutoSizeChanged(EventArgs.Empty);
156                                 }
157                         }
158                 }
159
160                 public override System.Drawing.Color BackColor {
161                         get {
162                                 return base.BackColor;
163                         }
164                         set {
165                                 base.BackColor = value;
166                         }
167                 }
168
169                 public override System.Drawing.Image BackgroundImage {
170                         get {
171                                 return base.BackgroundImage;
172                         }
173                         set {
174                                 base.BackgroundImage = value;
175                         }
176                 }
177
178                 public BorderStyle BorderStyle {
179                         get {
180                                 return border_style;
181                         }
182
183                         set {
184                                 if (value != border_style) {
185                                         border_style = value;
186                                         OnBorderStyleChanged(EventArgs.Empty);
187                                 }
188                         }
189                 }
190
191                 public bool CanUndo {
192                         get {
193                                 return undo;
194                         }
195                 }
196
197                 public override System.Drawing.Color ForeColor {
198                         get {
199                                 return base.ForeColor;
200                         }
201                         set {
202                                 base.ForeColor = value;
203                         }
204                 }
205
206                 public bool HideSelection {
207                         get {
208                                 return hide_selection;
209                         }
210
211                         set {
212                                 if (value != hide_selection) {
213                                         hide_selection = value;
214                                         OnHideSelectionChanged(EventArgs.Empty);
215                                 }
216                                 if (hide_selection) {
217                                         document.selection_visible = false;
218                                 } else {
219                                         document.selection_visible = true;
220                                 }
221                                 document.InvalidateSelectionArea();
222
223                         }
224                 }
225
226                 public string[] Lines {
227                         get {
228                                 string[]        lines;
229                                 int             i;
230                                 int             l;
231
232                                 l = document.Lines;
233                                 lines = new string[l];
234
235                                 for (i = 1; i <= l; i++) {
236                                         lines[i - 1] = document.GetLine(i).text.ToString();
237                                 }
238
239                                 return lines;
240                         }
241
242                         set {
243                                 int     i;
244                                 int     l;
245                                 Brush   brush;
246
247                                 document.Empty();
248
249                                 l = value.Length;
250                                 brush = ThemeEngine.Current.ResPool.GetSolidBrush(this.ForeColor);
251
252                                 for (i = 0; i < l; i++) {
253                                         document.Add(i+1, CaseAdjust(value[i]), alignment, Font, brush);
254                                 }
255                                 document.RecalculateDocument(CreateGraphics());
256                                 OnTextChanged(EventArgs.Empty);
257                         }
258                 }
259
260                 public virtual int MaxLength {
261                         get {
262                                 return max_length;
263                         }
264
265                         set {
266                                 if (value != max_length) {
267                                         max_length = value;
268                                 }
269                         }
270                 }
271
272                 public bool Modified {
273                         get {
274                                 return modified;
275                         }
276
277                         set {
278                                 if (value != modified) {
279                                         modified = value;
280                                         OnModifiedChanged(EventArgs.Empty);
281                                 }
282                         }
283                 }
284
285                 public virtual bool Multiline {
286                         get {
287                                 return multiline;
288                         }
289
290                         set {
291                                 if (value != multiline) {
292                                         multiline = value;
293
294                                         // Make sure we update our size; the user may have already set the size before going to multiline
295                                         if (text_bounds != Rectangle.Empty) {
296                                                 SetBoundsCore(text_bounds.X, text_bounds.Y, text_bounds.Width, text_bounds.Height, BoundsSpecified.All);
297                                         }
298
299                                         OnMultilineChanged(EventArgs.Empty);
300                                 }
301
302                                 document.multiline = multiline;
303                         }
304                 }
305
306                 public int PreferredHeight {
307                         get {
308                                 return this.Font.Height + 7;    // FIXME - consider border style as well
309                         }
310                 }
311
312                 public bool ReadOnly {
313                         get {
314                                 return read_only;
315                         }
316
317                         set {
318                                 if (value != read_only) {
319                                         read_only = value;
320                                         OnReadOnlyChanged(EventArgs.Empty);
321                                 }
322                         }
323                 }
324
325                 public virtual string SelectedText {
326                         get {
327                                 return document.GetSelection();
328                         }
329
330                         set {
331                                 document.ReplaceSelection(CaseAdjust(value));
332                                 OnTextChanged(EventArgs.Empty);
333                         }
334                 }
335
336                 public virtual int SelectionLength {
337                         get {
338                                 return document.SelectionLength();
339                         }
340
341                         set {
342                                 if (value != 0) {
343                                         int     start;
344                                         Line    line;
345                                         LineTag tag;
346                                         int     pos;
347
348                                         start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
349
350                                         document.CharIndexToLineTag(start + value, out line, out tag, out pos);
351                                         document.SetSelectionEnd(line, pos);
352                                         document.PositionCaret(line, pos);
353                                 } else {
354                                         document.SetSelectionEnd(document.selection_start.line, document.selection_start.pos);
355                                         document.PositionCaret(document.selection_start.line, document.selection_start.pos);
356                                 }
357                         }
358                 }
359
360                 public int SelectionStart {
361                         get {
362                                 int index;
363
364                                 index = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
365
366                                 return index;
367                         }
368
369                         set {
370                                 Line    line;
371                                 LineTag tag;
372                                 int     pos;
373
374                                 document.CharIndexToLineTag(value, out line, out tag, out pos);
375                                 document.SetSelectionStart(line, pos);
376                         }
377                 }
378
379                 public override string Text {
380                         get {
381                                 if (document == null || document.Root == null || document.Root.text == null) {
382                                         return string.Empty;
383                                 }
384
385                                 if (!multiline) {
386                                         return document.Root.text.ToString();
387                                 } else {
388                                         StringBuilder   sb;
389                                         int             i;
390
391                                         sb = new StringBuilder();
392
393                                         for (i = 1; i < document.Lines; i++) {
394                                                 sb.Append(document.GetLine(i).text.ToString() + Environment.NewLine);
395                                         }
396
397                                         return sb.ToString();
398                                 }
399                         }
400
401                         set {
402                                 Line    line;
403
404                                 if (multiline) {
405                                         string[]        lines;
406
407                                         lines = value.Split(new char[] {'\n'});
408                                         for (int i = 0; i < lines.Length; i++) {
409                                                 if (lines[i].EndsWith("\r")) {
410                                                         lines[i] = lines[i].Substring(0, lines[i].Length - 1);
411                                                 }
412                                         }
413                                         this.Lines = lines;
414
415                                         line = document.GetLine(1);
416                                         document.SetSelectionStart(line, 0);
417
418                                         line = document.GetLine(document.Lines);
419                                         document.SetSelectionEnd(line, line.text.Length);
420                                         document.PositionCaret(line, line.text.Length);
421                                 } else {
422                                         document.Clear();
423                                         document.Add(1, CaseAdjust(value), alignment, Font, ThemeEngine.Current.ResPool.GetSolidBrush(ForeColor));
424                                         document.RecalculateDocument(CreateGraphics());
425                                         line = document.GetLine(1);
426                                         document.SetSelectionStart(line, 0);
427                                         document.SetSelectionEnd(line, value.Length);
428                                         document.PositionCaret(line, value.Length);
429                                 }
430                                 base.Text = value;
431                                 OnTextChanged(EventArgs.Empty);
432                         }
433                 }
434
435                 public virtual int TextLength {
436                         get {
437                                 if (document == null || document.Root == null || document.Root.text == null) {
438                                         return 0;
439                                 }
440
441                                 if (!multiline) {
442                                         return document.Root.text.Length;
443                                 } else {
444                                         int     total;
445                                         int     i;
446
447                                         total = 0;
448                                         for (i = 1; i < document.Lines; i++) {
449                                                 total += document.GetLine(i).text.Length + Environment.NewLine.Length;
450                                         }
451
452                                         return total;
453                                 }
454                         }
455                 }
456
457                 public bool WordWrap {
458                         get {
459                                 return word_wrap;
460                         }
461
462                         set {
463                                 if (value != word_wrap) {
464                                         word_wrap = value;
465                                 }
466                         }
467                 }
468                 #endregion      // Public Instance Properties
469
470                 #region Protected Instance Properties
471                 protected override CreateParams CreateParams {
472                         get {
473                                 return base.CreateParams;
474                         }
475                 }
476
477                 protected override System.Drawing.Size DefaultSize {
478                         get {
479                                 return base.DefaultSize;
480                         }
481                 }
482                 #endregion      // Protected Instance Properties
483
484                 #region Public Instance Methods
485                 public void AppendText(string text) {
486
487                         if (multiline) {
488                                 string[]        lines;
489                                 int             linecount;
490
491                                 // Break the string into separate lines
492                                 lines = text.Split(new char[] {'\n'});
493                                 linecount = lines.Length;
494                                 for (int i = 0; i < linecount; i++) {
495                                         if (lines[i].EndsWith("\r")) {
496                                                 lines[i] = lines[i].Substring(0, lines[i].Length - 1);
497                                         }
498                                 }
499
500                                 // Grab the formatting for the last element
501                                 document.MoveCaret(CaretDirection.CtrlEnd);
502
503                                 // Insert the first line
504                                 document.InsertString(document.CaretLine, document.CaretPosition, lines[0]);
505
506                                 for (int i = 1; i < linecount; i++) {
507                                         document.Add(document.CaretLine.LineNo+i, CaseAdjust(lines[i]), alignment, document.CaretTag.font, document.CaretTag.color);
508                                 }
509
510                                 document.RecalculateDocument(CreateGraphics());
511                                 document.MoveCaret(CaretDirection.CtrlEnd);
512                                 Invalidate();
513                         } else {
514                                 document.MoveCaret(CaretDirection.CtrlEnd);
515                                 document.InsertStringAtCaret(text, true);
516                                 Invalidate();
517                         }
518                         OnTextChanged(EventArgs.Empty);
519                 }
520
521                 public void Clear() {
522                         // FIXME
523                         throw new NotImplementedException();
524                 }
525
526                 public void ClearUndo() {
527                         // FIXME
528                         throw new NotImplementedException();
529                 }
530
531                 public void Copy() {
532                         // FIXME
533                         throw new NotImplementedException();
534                 }
535
536                 public void Cut() {
537                         // FIXME
538                         throw new NotImplementedException();
539                 }
540
541                 public void Paste() {
542                         // FIXME
543                         throw new NotImplementedException();
544                 }
545
546                 public void ScrollToCaret() {
547                         // FIXME
548                         throw new NotImplementedException();
549                 }
550
551                 public void Select(int start, int length) {
552                         SelectionStart = start;
553                         SelectionLength = length;
554                 }
555
556
557                 public void SelectAll() {
558                         Line    last;
559
560                         last = document.GetLine(document.Lines);
561                         document.SetSelectionStart(document.GetLine(1), 0);
562                         document.SetSelectionEnd(last, last.text.Length);
563                 }
564
565                 public override string ToString() {
566                         StringBuilder   sb;
567                         int             i;
568                         int             end;
569
570                         sb = new StringBuilder();
571
572                         end = document.Lines;
573
574                         for (i = 1; i < end; i++) {
575                                 sb.Append(document.GetLine(i).text.ToString() + "\n");
576                         }
577
578                         return sb.ToString();
579                 }
580
581                 public void Undo() {
582                         return;
583                 }
584                 #endregion      // Public Instance Methods
585
586                 #region Protected Instance Methods
587                 protected override void CreateHandle() {
588                         base.CreateHandle ();
589                 }
590
591                 protected override bool IsInputKey(Keys keyData) {
592                         switch (keyData) {
593                                 case Keys.Enter: {
594                                         if (multiline && (accepts_return || ((keyData & Keys.Control) != 0))) {
595                                                 return true;
596                                         }
597                                         return false;
598                                 }
599
600                                 case Keys.Tab: {
601                                         if (accepts_tab) {
602                                                 return true;
603                                         }
604                                         return false;
605                                 }
606                         }
607                         return false;
608                 }
609
610
611                 protected virtual void OnAcceptsTabChanged(EventArgs e) {
612                         if (AcceptsTabChanged != null) {
613                                 AcceptsTabChanged(this, e);
614                         }
615                 }
616
617                 protected virtual void OnAutoSizeChanged(EventArgs e) {
618                         if (AutoSizeChanged != null) {
619                                 AutoSizeChanged(this, e);
620                         }
621                 }
622
623                 protected virtual void OnBorderStyleChanged(EventArgs e) {
624                         if (BorderStyleChanged != null) {
625                                 BorderStyleChanged(this, e);
626                         }
627                 }
628
629                 protected override void OnFontChanged(EventArgs e) {
630                         base.OnFontChanged (e);
631
632                         if (auto_size) {
633                                 if (PreferredHeight != Height) {
634                                         Height = PreferredHeight;
635                                 }
636                         }
637                 }
638
639                 protected override void OnHandleCreated(EventArgs e) {
640                         base.OnHandleCreated (e);
641                 }
642
643                 protected override void OnHandleDestroyed(EventArgs e) {
644                         base.OnHandleDestroyed (e);
645                 }
646
647                 protected virtual void OnHideSelectionChanged(EventArgs e) {
648                         if (HideSelectionChanged != null) {
649                                 HideSelectionChanged(this, e);
650                         }
651                 }
652
653                 protected virtual void OnModifiedChanged(EventArgs e) {
654                         if (ModifiedChanged != null) {
655                                 ModifiedChanged(this, e);
656                         }
657                 }
658
659                 protected virtual void OnMultilineChanged(EventArgs e) {
660                         if (MultilineChanged != null) {
661                                 MultilineChanged(this, e);
662                         }
663                 }
664
665                 protected virtual void OnReadOnlyChanged(EventArgs e) {
666                         if (ReadOnlyChanged != null) {
667                                 ReadOnlyChanged(this, e);
668                         }
669                 }
670
671                 protected override bool ProcessDialogKey(Keys keyData) {
672                         return base.ProcessDialogKey (keyData);
673                 }
674
675                 protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) {
676                         // Make sure we don't get sized bigger than we want to be
677                         if (!richtext) {
678                                 if (!multiline) {
679                                         if (height > PreferredHeight) {
680                                                 text_bounds = new Rectangle(x, y, width, height);
681                                                 text_bounds.Height = PreferredHeight;
682                                         }
683                                 }
684                         }
685                         base.SetBoundsCore (x, y, width, height, specified);
686                 }
687
688                 protected override void WndProc(ref Message m) {
689                         switch ((Msg)m.Msg) {
690                                 case Msg.WM_PAINT: {
691                                         PaintEventArgs  paint_event;
692
693                                         paint_event = XplatUI.PaintEventStart(Handle);
694                                         
695                                         PaintControl(paint_event);
696                                         XplatUI.PaintEventEnd(Handle);
697                                         DefWndProc(ref m);
698                                         return;
699                                 }
700
701                                 case Msg.WM_SETFOCUS: {
702                                         // Set caret
703                                         document.CaretHasFocus();
704 Console.WriteLine("Creating caret");
705                                         base.WndProc(ref m);
706                                         return;
707                                 }
708
709                                 case Msg.WM_KILLFOCUS: {
710                                         // Kill caret
711                                         document.CaretLostFocus();
712 Console.WriteLine("Destroying caret");
713                                         base.WndProc(ref m);
714                                         return;
715                                 }
716
717                                 case Msg.WM_KEYDOWN: {
718                                         switch ((Keys)(m.WParam.ToInt32())) {
719                                                 case Keys.Left: {
720                                                         document.SetSelectionToCaret(true);
721
722                                                         if ((Control.ModifierKeys & Keys.Control) != 0) {
723                                                                 document.MoveCaret(CaretDirection.WordBack);
724                                                         } else {
725                                                                 document.MoveCaret(CaretDirection.CharBack);
726                                                         }
727                                                         return;
728                                                 }
729
730                                                 case Keys.Right: {
731                                                         document.SetSelectionToCaret(true);
732
733                                                         if ((Control.ModifierKeys & Keys.Control) != 0) {
734                                                                 document.MoveCaret(CaretDirection.WordForward);
735                                                         } else {
736                                                                 document.MoveCaret(CaretDirection.CharForward);
737                                                         }
738                                                         return;
739                                                 }
740
741                                                 case Keys.Up: {
742                                                         document.SetSelectionToCaret(true);
743                                                         document.MoveCaret(CaretDirection.LineUp);
744                                                         return;
745                                                 }
746
747                                                 case Keys.Down: {
748                                                         document.SetSelectionToCaret(true);
749                                                         document.MoveCaret(CaretDirection.LineDown);
750                                                         return;
751                                                 }
752
753                                                 case Keys.Home: {
754                                                         document.SetSelectionToCaret(true);
755
756                                                         if ((Control.ModifierKeys & Keys.Control) != 0) {
757                                                                 document.MoveCaret(CaretDirection.CtrlHome);
758                                                         } else {
759                                                                 document.MoveCaret(CaretDirection.Home);
760                                                         }
761                                                         return;
762                                                 }
763
764                                                 case Keys.End: {
765                                                         document.SetSelectionToCaret(true);
766
767                                                         if ((Control.ModifierKeys & Keys.Control) != 0) {
768                                                                 document.MoveCaret(CaretDirection.CtrlEnd);
769                                                         } else {
770                                                                 document.MoveCaret(CaretDirection.End);
771                                                         }
772                                                         return;
773                                                 }
774
775                                                 case Keys.Enter: {
776                                                         if (multiline && (accepts_return || ((Control.ModifierKeys & Keys.Control) != 0))) {
777                                                                 if (document.selection_visible) {
778                                                                         document.ReplaceSelection("");
779                                                                 }
780                                                                 document.SetSelectionToCaret(true);
781
782                                                                 document.Split(document.CaretLine, document.CaretTag, document.CaretPosition);
783                                                                 OnTextChanged(EventArgs.Empty);
784                                                                 document.UpdateView(document.CaretLine, 2, 0);
785                                                                 document.MoveCaret(CaretDirection.CharForward);
786                                                                 return;
787                                                         }
788                                                         break;
789                                                 }
790
791                                                 case Keys.Tab: {
792                                                         if (accepts_tab) {
793                                                                 document.InsertChar(document.CaretLine, document.CaretPosition, '\t');
794                                                                 if (document.selection_visible) {
795                                                                         document.ReplaceSelection("");
796                                                                 }
797                                                                 document.SetSelectionToCaret(true);
798
799                                                                 OnTextChanged(EventArgs.Empty);
800                                                         } else {
801                                                                 base.WndProc(ref m);
802                                                         }
803                                                         return;
804                                                 }
805
806
807                                                 case Keys.Back: {
808                                                         // delete only deletes on the line, doesn't do the combine
809                                                         if (document.selection_visible) {
810                                                                 document.ReplaceSelection("");
811                                                         }
812                                                         document.SetSelectionToCaret(true);
813                                                         if (document.CaretPosition == 0) {
814                                                                 if (document.CaretLine.LineNo > 1) {
815                                                                         Line    line;
816                                                                         int     new_caret_pos;
817
818                                                                         line = document.GetLine(document.CaretLine.LineNo - 1);
819                                                                         new_caret_pos = line.text.Length;
820
821                                                                         document.Combine(line, document.CaretLine);
822                                                                         document.UpdateView(line, 1, 0);
823                                                                         document.PositionCaret(line, new_caret_pos);
824                                                                         document.UpdateCaret();
825                                                                         OnTextChanged(EventArgs.Empty);
826                                                                 }
827                                                         } else {
828                                                                 document.DeleteChar(document.CaretTag, document.CaretPosition, false);
829                                                                 document.MoveCaret(CaretDirection.CharBack);
830                                                                 OnTextChanged(EventArgs.Empty);
831                                                         }
832                                                         return;
833                                                 }
834
835                                                 case Keys.Delete: {
836                                                         // delete only deletes on the line, doesn't do the combine
837                                                         if (document.CaretPosition == document.CaretLine.text.Length) {
838                                                                 if (document.CaretLine.LineNo < document.Lines) {
839                                                                         Line    line;
840
841                                                                         line = document.GetLine(document.CaretLine.LineNo + 1);
842                                                                         document.Combine(document.CaretLine, line);
843                                                                         document.UpdateView(document.CaretLine, 2, 0);
844                                                                         OnTextChanged(EventArgs.Empty);
845
846                                                                         #if Debug
847                                                                                 Line    check_first;
848                                                                                 Line    check_second;
849
850                                                                                 check_first = document.GetLine(document.CaretLine.LineNo);
851                                                                                 check_second = document.GetLine(check_first.line_no + 1);
852
853                                                                                 Console.WriteLine("Post-UpdateView: Y of first line: {0}, second line: {1}", check_first.Y, check_second.Y);
854                                                                         #endif
855
856                                                                         // Caret doesn't move
857                                                                 }
858                                                         } else {
859                                                                 document.DeleteChar(document.CaretTag, document.CaretPosition, true);
860                                                                 OnTextChanged(EventArgs.Empty);
861                                                         }
862                                                         return;
863                                                 }
864                                         }
865                                         base.WndProc(ref m);
866                                         return;
867                                 }
868
869                                 case Msg.WM_CHAR: {
870                                         if (m.WParam.ToInt32() >= 32) { // FIXME, tabs should probably go through
871                                                 if (document.selection_visible) {
872                                                         document.ReplaceSelection("");
873                                                 }
874
875                                                 switch (character_casing) {
876                                                         case CharacterCasing.Normal: {
877                                                                 document.InsertCharAtCaret((char)m.WParam, true);
878                                                                 OnTextChanged(EventArgs.Empty);
879                                                                 return;
880                                                         }
881
882                                                         case CharacterCasing.Lower: {
883                                                                 document.InsertCharAtCaret(Char.ToLower((char)m.WParam), true);
884                                                                 OnTextChanged(EventArgs.Empty);
885                                                                 return;
886                                                         }
887
888                                                         case CharacterCasing.Upper: {
889                                                                 document.InsertCharAtCaret(Char.ToUpper((char)m.WParam), true);
890                                                                 OnTextChanged(EventArgs.Empty);
891                                                                 return;
892                                                         }
893                                                 }
894                                         }
895                                         base.WndProc(ref m);
896                                         return;
897                                 }
898
899                                 default: {
900                                         base.WndProc(ref m);
901                                         return;
902                                 }
903                         }
904                 }
905
906                 #endregion      // Protected Instance Methods
907
908                 #region Events
909                 public event EventHandler       AcceptsTabChanged;
910                 public event EventHandler       AutoSizeChanged;
911                 public event EventHandler       BorderStyleChanged;
912                 public event EventHandler       Click;
913                 public event EventHandler       HideSelectionChanged;
914                 public event EventHandler       ModifiedChanged;
915                 public event EventHandler       MultilineChanged;
916                 public event PaintEventHandler  Paint;
917                 public event EventHandler       ReadOnlyChanged;
918                 #endregion      // Events
919
920                 #region Private Methods
921                 internal Document Document {
922                         get {
923                                 return document;
924                         }
925
926                         set {
927                                 document = value;
928                         }
929                 }
930
931 static int current;
932
933                 private void PaintControl(PaintEventArgs pevent) {
934                         // Fill background
935                         pevent.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(BackColor), pevent.ClipRectangle);
936                         //pevent.Graphics.TextRenderingHint=TextRenderingHint.AntiAlias;
937
938                         // Draw the viewable document
939                         document.Draw(pevent.Graphics, pevent.ClipRectangle);
940
941                         Rectangle       rect = ClientRectangle;
942                         rect.Width--;
943                         rect.Height--;
944                         pevent.Graphics.DrawRectangle(ThemeEngine.Current.ResPool.GetPen(ThemeEngine.Current.ColorButtonShadow), rect);
945
946                         // Set the scrollbar
947                         switch (scrollbars) {
948                                 case ScrollBars.Both: {
949                                         break;
950                                 }
951                                 case ScrollBars.Vertical: {
952                                         break;
953                                 }
954                                 case ScrollBars.Horizontal: {
955                                         hscroll.Minimum = 0;
956                                         hscroll.Maximum = document.Width - this.Width;
957                                         break;
958                                 }
959                         }
960
961                         #if Debug
962                                 int             start;
963                                 int             end;
964                                 Line            line;
965                                 int             line_no;
966                                 Pen             p;
967
968                                 p = new Pen(Color.Red, 1);
969
970                                 // First, figure out from what line to what line we need to draw
971                                 start = document.GetLineByPixel(pevent.ClipRectangle.Top - viewport_y, false).line_no;
972                                 end = document.GetLineByPixel(pevent.ClipRectangle.Bottom - viewport_y, false).line_no;
973
974                                 //Console.WriteLine("Starting drawing on line '{0}'", document.GetLine(start));
975                                 //Console.WriteLine("Ending drawing on line '{0}'", document.GetLine(end));
976
977                                 line_no = start;
978                                 while (line_no <= end) {
979                                         line = document.GetLine(line_no);
980
981                                         if (draw_lines) {
982                                                 for (int i = 0; i < line.text.Length; i++) {
983                                                         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);
984                                                 }
985                                         }
986
987                                         line_no++;
988                                 }
989                         #endif
990                 }
991
992                 private void TextBoxBase_MouseDown(object sender, MouseEventArgs e) {
993                         LineTag tag;
994                         Line    line;
995                         int     pos;
996
997                         if (e.Button == MouseButtons.Left) {
998                                 document.PositionCaret(e.X, e.Y);
999                                 document.SetSelectionToCaret(true);
1000                                 this.grabbed = true;
1001                                 this.Capture = true;
1002                                 return;
1003                         }
1004
1005                         #if Debug
1006                                 if (e.Button == MouseButtons.Right) {
1007                                         draw_lines = !draw_lines;
1008                                         this.Invalidate();
1009                                         Console.WriteLine("SelectedText: {0}, length {1}", this.SelectedText, this.SelectionLength);
1010                                         Console.WriteLine("Selection start: {0}", this.SelectionStart);
1011
1012                                         this.SelectionStart = 10;
1013                                         this.SelectionLength = 5;
1014
1015                                         return;
1016                                 }
1017
1018                                 tag = document.FindTag(e.X, e.Y, out pos, false);
1019
1020                                 Console.WriteLine("Click found tag {0}, character {1}", tag, pos);
1021                                 line = tag.line;
1022                                 switch(current) {
1023                                         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;
1024                                         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;
1025                                         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;
1026                                         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;
1027                                         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;
1028                                         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;
1029                                 }
1030                                 current++;
1031                                 if (current==6) {
1032                                         current=0;
1033                                 }
1034
1035                                 // Update/Recalculate what we see
1036                                 document.UpdateView(line, 0);
1037
1038                                 // Make sure our caret is properly positioned and sized
1039                                 document.AlignCaret();
1040                         #endif
1041                 }
1042
1043                 private void TextBoxBase_MouseUp(object sender, MouseEventArgs e) {
1044                         this.Capture = false;
1045                         this.grabbed = false;
1046                         if (e.Button == MouseButtons.Left) {
1047                                 document.PositionCaret(e.X + viewport_x, e.Y + viewport_y);
1048                                 document.SetSelectionToCaret(false);
1049                                 document.DisplayCaret();
1050                                 return;
1051                         }
1052                 }
1053                 #endregion      // Private Methods
1054
1055
1056                 private void TextBoxBase_SizeChanged(object sender, EventArgs e) {
1057
1058                         // First, check which scrollbars we need
1059                         
1060                         hscroll.Bounds = new Rectangle (ClientRectangle.Left, ClientRectangle.Bottom - hscroll.Height, Width, hscroll.Height);
1061                         
1062                 }
1063
1064                 private void hscroll_ValueChanged(object sender, EventArgs e) {
1065                         XplatUI.ScrollWindow(this.Handle, document.ViewPortX-this.hscroll.Value, 0, true);
1066                         document.ViewPortX = this.hscroll.Value;
1067                         document.UpdateCaret();
1068                         Console.WriteLine("Dude scrolled");
1069                 }
1070
1071                 private void TextBoxBase_MouseMove(object sender, MouseEventArgs e) {
1072                         // FIXME - handle auto-scrolling if mouse is to the right/left of the window
1073                         if (grabbed) {
1074                                 document.PositionCaret(e.X + viewport_x, e.Y + viewport_y);
1075                                 document.SetSelectionToCaret(false);
1076                                 document.DisplayCaret();
1077                         }
1078                 }
1079                                                                               
1080                 private void TextBoxBase_FontOrColorChanged(object sender, EventArgs e) {
1081                         if (!richtext) {
1082                                 Line    line;
1083
1084                                 // Font changes apply to the whole document
1085                                 for (int i = 1; i <= document.Lines; i++) {
1086                                         line = document.GetLine(i);
1087                                         LineTag.FormatText(line, 1, line.text.Length, Font, ThemeEngine.Current.ResPool.GetSolidBrush(ForeColor));
1088                                         document.UpdateView(line, 0);
1089                                 }
1090                                 // Make sure the caret height is matching the new font height
1091                                 document.AlignCaret();
1092                         }
1093                 }
1094         }
1095 }