* TextBoxBase.cs: Set the default max values to MaxValue since
[mono-project.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / TextBoxBase.cs
blob1088a89885374270b265a424ae5d61459cc94a96
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.
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.
20 // Copyright (c) 2004-2006 Novell, Inc. (http://www.novell.com)
22 // Authors:
23 // Peter Bartok pbartok@novell.com
27 // NOT COMPLETE
28 #undef Debug
29 #undef DebugClick
31 using System.ComponentModel;
32 using System.ComponentModel.Design;
33 using System.Drawing;
34 using System.Drawing.Text;
35 using System.Text;
36 using System.Runtime.InteropServices;
38 namespace System.Windows.Forms {
39 [DefaultEvent("TextChanged")]
40 [Designer("System.Windows.Forms.Design.TextBoxBaseDesigner, " + Consts.AssemblySystem_Design)]
41 public abstract class TextBoxBase : Control {
42 #region Local Variables
43 internal HorizontalAlignment alignment;
44 internal bool accepts_tab;
45 internal bool accepts_return;
46 internal bool auto_size;
47 internal bool backcolor_set;
48 internal CharacterCasing character_casing;
49 internal bool undo;
50 internal bool hide_selection;
51 internal int max_length;
52 internal bool modified;
53 internal bool multiline;
54 internal char password_char;
55 internal bool read_only;
56 internal bool word_wrap;
57 internal Document document;
58 internal LineTag caret_tag; // tag our cursor is in
59 internal int caret_pos; // position on the line our cursor is in (can be 0 = beginning of line)
60 internal ImplicitHScrollBar hscroll;
61 internal ImplicitVScrollBar vscroll;
62 internal RichTextBoxScrollBars scrollbars;
63 internal bool richtext;
64 internal bool show_selection; // set to true to always show selection, even if no focus is set
65 internal int selection_length; // set to the user-specified selection length, or -1 if none
66 internal int requested_height;
67 internal int canvas_width;
68 internal int canvas_height;
69 static internal int track_width = 2; //
70 static internal int track_border = 5; //
71 internal DateTime click_last;
72 internal CaretSelection click_mode;
73 internal Bitmap bmp;
74 #if Debug
75 internal static bool draw_lines = false;
76 #endif
78 #endregion // Local Variables
80 #region Internal Constructor
81 // Constructor will go when complete, only for testing - pdb
82 internal TextBoxBase() {
83 alignment = HorizontalAlignment.Left;
84 accepts_return = false;
85 accepts_tab = false;
86 auto_size = true;
87 border_style = BorderStyle.Fixed3D;
88 character_casing = CharacterCasing.Normal;
89 undo = false;
90 hide_selection = true;
91 max_length = 32767;
92 modified = false;
93 multiline = false;
94 password_char = '\0';
95 read_only = false;
96 word_wrap = true;
97 richtext = false;
98 show_selection = false;
99 document = new Document(this);
100 document.WidthChanged += new EventHandler(document_WidthChanged);
101 document.HeightChanged += new EventHandler(document_HeightChanged);
102 //document.CaretMoved += new EventHandler(CaretMoved);
103 document.Wrap = false;
104 requested_height = -1;
105 click_last = DateTime.Now;
106 click_mode = CaretSelection.Position;
107 bmp = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
109 MouseDown += new MouseEventHandler(TextBoxBase_MouseDown);
110 MouseUp += new MouseEventHandler(TextBoxBase_MouseUp);
111 MouseMove += new MouseEventHandler(TextBoxBase_MouseMove);
112 SizeChanged += new EventHandler(TextBoxBase_SizeChanged);
113 FontChanged += new EventHandler(TextBoxBase_FontOrColorChanged);
114 ForeColorChanged += new EventHandler(TextBoxBase_FontOrColorChanged);
115 MouseWheel += new MouseEventHandler(TextBoxBase_MouseWheel);
117 scrollbars = RichTextBoxScrollBars.None;
119 hscroll = new ImplicitHScrollBar();
120 hscroll.ValueChanged += new EventHandler(hscroll_ValueChanged);
121 hscroll.control_style &= ~ControlStyles.Selectable;
122 hscroll.Enabled = false;
123 hscroll.Visible = false;
124 hscroll.Maximum = Int32.MaxValue;
126 vscroll = new ImplicitVScrollBar();
127 vscroll.ValueChanged += new EventHandler(vscroll_ValueChanged);
128 vscroll.control_style &= ~ControlStyles.Selectable;
129 vscroll.Enabled = false;
130 vscroll.Visible = false;
131 vscroll.Maximum = Int32.MaxValue;
133 SuspendLayout ();
134 this.Controls.AddImplicit (hscroll);
135 this.Controls.AddImplicit (vscroll);
136 ResumeLayout ();
138 //SetStyle(ControlStyles.ResizeRedraw, true);
139 SetStyle(ControlStyles.UserPaint | ControlStyles.StandardClick, false);
141 canvas_width = ClientSize.Width;
142 canvas_height = ClientSize.Height;
143 document.ViewPortWidth = canvas_width;
144 document.ViewPortHeight = canvas_height;
146 Cursor = Cursors.IBeam;
148 CalculateScrollBars();
150 #endregion // Internal Constructor
152 #region Private and Internal Methods
153 internal string CaseAdjust(string s) {
154 if (character_casing == CharacterCasing.Normal) {
155 return s;
157 if (character_casing == CharacterCasing.Lower) {
158 return s.ToLower();
159 } else {
160 return s.ToUpper();
164 internal override void HandleClick(int clicks, MouseEventArgs me) {
165 // MS seems to fire the click event in spite of the styles they set
166 control_style |= ControlStyles.StandardClick | ControlStyles.StandardDoubleClick;
167 base.HandleClick (clicks, me);
168 control_style ^= ControlStyles.StandardClick | ControlStyles.StandardDoubleClick;
171 #endregion // Private and Internal Methods
173 #region Public Instance Properties
174 [DefaultValue(false)]
175 [MWFCategory("Behavior")]
176 public bool AcceptsTab {
177 get {
178 return accepts_tab;
181 set {
182 if (value != accepts_tab) {
183 accepts_tab = value;
184 OnAcceptsTabChanged(EventArgs.Empty);
189 [DefaultValue(true)]
190 [Localizable(true)]
191 [RefreshProperties(RefreshProperties.Repaint)]
192 [MWFCategory("Behavior")]
193 public virtual bool AutoSize {
194 get {
195 return auto_size;
198 set {
199 if (value != auto_size) {
200 auto_size = value;
201 if (auto_size) {
202 if (PreferredHeight != ClientSize.Height) {
203 ClientSize = new Size(ClientSize.Width, PreferredHeight);
206 OnAutoSizeChanged(EventArgs.Empty);
211 [DispId(-501)]
212 public override System.Drawing.Color BackColor {
213 get {
214 return base.BackColor;
216 set {
217 if (value != ThemeEngine.Current.ColorWindow) {
218 backcolor_set = true;
219 } else {
220 backcolor_set = false;
222 base.BackColor = value;
226 [Browsable(false)]
227 [EditorBrowsable(EditorBrowsableState.Never)]
228 public override System.Drawing.Image BackgroundImage {
229 get {
230 return base.BackgroundImage;
232 set {
233 base.BackgroundImage = value;
237 [DefaultValue(BorderStyle.Fixed3D)]
238 [DispId(-504)]
239 [MWFCategory("Appearance")]
240 public BorderStyle BorderStyle {
241 get { return InternalBorderStyle; }
242 set {
243 InternalBorderStyle = value;
244 OnBorderStyleChanged(EventArgs.Empty);
248 [Browsable(false)]
249 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
250 public bool CanUndo {
251 get {
252 return undo;
256 [DispId(-513)]
257 public override System.Drawing.Color ForeColor {
258 get {
259 return base.ForeColor;
261 set {
262 base.ForeColor = value;
266 [DefaultValue(true)]
267 [MWFCategory("Behavior")]
268 public bool HideSelection {
269 get {
270 return hide_selection;
273 set {
274 if (value != hide_selection) {
275 hide_selection = value;
276 OnHideSelectionChanged(EventArgs.Empty);
278 if (hide_selection) {
279 document.selection_visible = false;
280 } else {
281 document.selection_visible = true;
283 document.InvalidateSelectionArea();
288 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
289 [Editor("System.Windows.Forms.Design.StringArrayEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
290 [Localizable(true)]
291 [MWFCategory("Layout")]
292 public string[] Lines {
293 get {
294 string[] lines;
295 int i;
296 int l;
298 l = document.Lines;
300 // Handle empty document
301 if ((l == 1) && (document.GetLine(1).text.Length == 0)) {
302 return new string[0];
305 lines = new string[l];
307 for (i = 1; i <= l; i++) {
308 lines[i - 1] = document.GetLine(i).text.ToString();
311 return lines;
314 set {
315 int i;
316 int l;
317 Brush brush;
319 document.Empty();
321 l = value.Length;
322 brush = ThemeEngine.Current.ResPool.GetSolidBrush(this.ForeColor);
324 for (i = 0; i < l; i++) {
325 document.Add(i+1, CaseAdjust(value[i]), alignment, Font, brush);
327 CalculateDocument();
328 OnTextChanged(EventArgs.Empty);
332 [DefaultValue(32767)]
333 [Localizable(true)]
334 [MWFCategory("Behavior")]
335 public virtual int MaxLength {
336 get {
337 if (max_length == 2147483646) { // We don't distinguish between single and multi-line limits
338 return 0;
340 return max_length;
343 set {
344 if (value != max_length) {
345 max_length = value;
350 [Browsable(false)]
351 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
352 public bool Modified {
353 get {
354 return modified;
357 set {
358 if (value != modified) {
359 modified = value;
360 OnModifiedChanged(EventArgs.Empty);
365 [DefaultValue(false)]
366 [Localizable(true)]
367 [RefreshProperties(RefreshProperties.All)]
368 [MWFCategory("Behavior")]
369 public virtual bool Multiline {
370 get {
371 return multiline;
374 set {
375 if (value != multiline) {
376 multiline = value;
377 // Make sure we update our size; the user may have already set the size before going to multiline
378 if (multiline && requested_height != -1) {
379 Height = requested_height;
380 requested_height = -1;
383 OnMultilineChanged(EventArgs.Empty);
386 document.multiline = multiline;
388 if (multiline) {
389 document.Wrap = word_wrap;
390 document.PasswordChar = "";
392 } else {
393 document.Wrap = false;
394 if (this.password_char != '\0') {
395 document.PasswordChar = password_char.ToString();
396 } else {
397 document.PasswordChar = "";
403 [Browsable(false)]
404 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
405 [EditorBrowsable(EditorBrowsableState.Advanced)]
406 public int PreferredHeight {
407 get {
408 return this.Font.Height + 7; // FIXME - consider border style as well
412 [DefaultValue(false)]
413 [MWFCategory("Behavior")]
414 public bool ReadOnly {
415 get {
416 return read_only;
419 set {
420 if (value != read_only) {
421 read_only = value;
422 OnReadOnlyChanged(EventArgs.Empty);
427 [Browsable(false)]
428 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
429 public virtual string SelectedText {
430 get {
431 return document.GetSelection();
434 set {
435 if (!read_only) {
436 document.ReplaceSelection(CaseAdjust(value));
437 document.SetSelectionStart(document.caret.line, document.caret.pos);
438 document.SetSelectionEnd(document.caret.line, document.caret.pos);
439 ScrollToCaret();
440 OnTextChanged(EventArgs.Empty);
445 [Browsable(false)]
446 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
447 public virtual int SelectionLength {
448 get {
449 return document.SelectionLength();
452 set {
453 if (value < 0) {
454 throw new ArgumentException(String.Format("{0} is not a valid value", value), "value");
457 if (value != 0) {
458 int start;
459 Line line;
460 LineTag tag;
461 int pos;
463 selection_length = value;
465 start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
467 document.CharIndexToLineTag(start + value, out line, out tag, out pos);
468 document.SetSelectionEnd(line, pos);
469 document.PositionCaret(line, pos);
470 } else {
471 selection_length = -1;
473 document.SetSelectionEnd(document.selection_start.line, document.selection_start.pos);
474 document.PositionCaret(document.selection_start.line, document.selection_start.pos);
479 [Browsable(false)]
480 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
481 public int SelectionStart {
482 get {
483 int index;
485 index = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
487 return index;
490 set {
491 document.SetSelectionStart(value);
492 if (selection_length > -1 ) {
493 document.SetSelectionEnd(value + selection_length);
494 } else {
495 document.SetSelectionEnd(value);
497 ScrollToCaret();
501 [Localizable(true)]
502 public override string Text {
503 get {
504 if (document == null || document.Root == null || document.Root.text == null) {
505 return string.Empty;
508 if (!multiline) {
509 return document.Root.text.ToString();
510 } else {
511 StringBuilder sb;
512 int i;
514 sb = new StringBuilder();
516 for (i = 1; i < document.Lines; i++) {
517 if (i > 1)
518 sb.Append (Environment.NewLine);
519 sb.Append(document.GetLine(i).text.ToString());
521 sb.Append(document.GetLine(document.Lines).text.ToString());
522 return sb.ToString();
526 set {
527 if (value == Text)
528 return;
530 if ((value != null) && (value != "")) {
531 Line line;
533 if (multiline) {
534 string[] lines;
536 lines = value.Split(new char[] {'\n'});
538 for (int i = 0; i < lines.Length; i++) {
539 if (lines[i].EndsWith("\r")) {
540 lines[i] = lines[i].Substring(0, lines[i].Length - 1);
543 this.Lines = lines;
545 line = document.GetLine(1);
547 if (!Focused) {
548 document.SetSelectionStart(line, 0);
550 line = document.GetLine(document.Lines);
551 document.SetSelectionEnd(line, line.text.Length);
552 selection_length = -1;
553 document.PositionCaret(line, line.text.Length);
554 } else {
555 document.SetSelectionStart(line, 0);
556 document.SetSelectionEnd(line, 0);
557 selection_length = -1;
558 document.PositionCaret(line, 0);
560 } else {
561 document.Clear();
562 document.Add(1, CaseAdjust(value), alignment, Font, ThemeEngine.Current.ResPool.GetSolidBrush(ForeColor));
563 CalculateDocument();
564 line = document.GetLine(1);
566 if (!Focused) {
567 document.SetSelectionStart(line, 0);
568 document.SetSelectionEnd(line, value.Length);
569 selection_length = -1;
570 document.PositionCaret(line, value.Length);
571 } else {
572 document.SetSelectionStart(line, 0);
573 document.SetSelectionEnd(line, 0);
574 selection_length = -1;
575 document.PositionCaret(line, 0);
578 } else {
579 document.Empty();
580 CalculateDocument();
583 OnTextChanged(EventArgs.Empty);
587 [Browsable(false)]
588 public virtual int TextLength {
589 get {
590 if (document == null || document.Root == null || document.Root.text == null) {
591 return 0;
594 if (!multiline) {
595 return document.Root.text.Length;
596 } else {
597 int total;
598 int i;
600 total = 0;
601 for (i = 1; i < document.Lines; i++) {
602 total += document.GetLine(i).text.Length + Environment.NewLine.Length;
604 total += document.GetLine(i).text.Length;
606 return total;
611 [DefaultValue(true)]
612 [Localizable(true)]
613 [MWFCategory("Behavior")]
614 public bool WordWrap {
615 get {
616 return word_wrap;
619 set {
620 if (value != word_wrap) {
621 if (multiline) {
622 word_wrap = value;
623 document.Wrap = value;
628 #endregion // Public Instance Properties
630 #region Protected Instance Properties
631 protected override CreateParams CreateParams {
632 get {
633 return base.CreateParams;
637 protected override System.Drawing.Size DefaultSize {
638 get {
639 return new Size(100, 20);
642 #endregion // Protected Instance Properties
644 #region Public Instance Methods
645 public void AppendText(string text) {
646 if (multiline) {
647 // Grab the formatting for the last element
648 document.MoveCaret(CaretDirection.CtrlEnd);
649 // grab the end tag
650 if (document.CaretTag.next != null) {
651 document.CaretTag = document.CaretTag.next;
653 document.Insert(document.CaretLine, document.CaretTag, document.CaretPosition, false, text);
655 CalculateDocument();
656 } else {
657 document.MoveCaret(CaretDirection.CtrlEnd);
658 document.InsertStringAtCaret(text, true);
660 Invalidate();
663 document.MoveCaret(CaretDirection.CtrlEnd);
664 document.SetSelectionStart(document.CaretLine, document.CaretPosition);
665 document.SetSelectionEnd(document.CaretLine, document.CaretPosition);
666 selection_length = -1;
668 OnTextChanged(EventArgs.Empty);
671 public void Clear() {
672 Text = null;
675 public void ClearUndo() {
676 document.undo.Clear();
679 public void Copy() {
680 DataObject o;
682 o = new DataObject(DataFormats.Text, SelectedText);
683 if (this is RichTextBox) {
684 o.SetData(DataFormats.Rtf, ((RichTextBox)this).SelectedRtf);
686 Clipboard.SetDataObject(o);
689 public void Cut() {
690 DataObject o;
692 o = new DataObject(DataFormats.Text, SelectedText);
693 if (this is RichTextBox) {
694 o.SetData(DataFormats.Rtf, ((RichTextBox)this).SelectedRtf);
696 Clipboard.SetDataObject(o);
697 document.ReplaceSelection("");
700 public void Paste() {
701 Paste(Clipboard.GetDataObject(), null, false);
704 public void ScrollToCaret() {
705 if (IsHandleCreated) {
706 CaretMoved(this, EventArgs.Empty);
710 public void Select(int start, int length) {
711 SelectionStart = start;
712 SelectionLength = length;
716 public void SelectAll() {
717 Line last;
719 last = document.GetLine(document.Lines);
720 document.SetSelectionStart(document.GetLine(1), 0);
721 document.SetSelectionEnd(last, last.text.Length);
722 selection_length = -1;
725 public override string ToString() {
726 return String.Concat (base.ToString (), ", Text: ", Text);
729 public void Undo() {
730 document.undo.Undo();
732 #endregion // Public Instance Methods
734 #region Protected Instance Methods
735 protected override void CreateHandle() {
736 base.CreateHandle ();
737 document.AlignCaret();
738 ScrollToCaret();
741 protected override bool IsInputKey(Keys keyData) {
742 if ((keyData & Keys.Alt) != 0) {
743 return base.IsInputKey(keyData);
746 switch (keyData & Keys.KeyCode) {
747 case Keys.Enter: {
748 if (multiline && accepts_return) {
749 return true;
751 return false;
754 case Keys.Tab: {
755 if (accepts_tab && multiline) {
756 if ((keyData & Keys.Control) == 0) {
757 return true;
760 return false;
763 case Keys.Left:
764 case Keys.Right:
765 case Keys.Up:
766 case Keys.Down:
767 case Keys.PageUp:
768 case Keys.PageDown:
769 case Keys.Home:
770 case Keys.End: {
771 return true;
774 return false;
778 protected virtual void OnAcceptsTabChanged(EventArgs e) {
779 if (AcceptsTabChanged != null) {
780 AcceptsTabChanged(this, e);
784 protected virtual void OnAutoSizeChanged(EventArgs e) {
785 if (AutoSizeChanged != null) {
786 AutoSizeChanged(this, e);
790 protected virtual void OnBorderStyleChanged(EventArgs e) {
791 if (BorderStyleChanged != null) {
792 BorderStyleChanged(this, e);
796 protected override void OnFontChanged(EventArgs e) {
797 base.OnFontChanged (e);
799 if (auto_size && !multiline) {
800 if (PreferredHeight != ClientSize.Height) {
801 Height = PreferredHeight;
806 protected override void OnHandleCreated(EventArgs e) {
807 base.OnHandleCreated (e);
810 protected override void OnHandleDestroyed(EventArgs e) {
811 base.OnHandleDestroyed (e);
814 protected virtual void OnHideSelectionChanged(EventArgs e) {
815 if (HideSelectionChanged != null) {
816 HideSelectionChanged(this, e);
820 protected virtual void OnModifiedChanged(EventArgs e) {
821 if (ModifiedChanged != null) {
822 ModifiedChanged(this, e);
826 protected virtual void OnMultilineChanged(EventArgs e) {
827 if (MultilineChanged != null) {
828 MultilineChanged(this, e);
832 protected virtual void OnReadOnlyChanged(EventArgs e) {
833 if (ReadOnlyChanged != null) {
834 ReadOnlyChanged(this, e);
838 protected override bool ProcessDialogKey(Keys keyData) {
839 return base.ProcessDialogKey(keyData);
842 private bool ProcessKey(Keys keyData) {
843 bool control;
844 bool shift;
846 control = (Control.ModifierKeys & Keys.Control) != 0;
847 shift = (Control.ModifierKeys & Keys.Shift) != 0;
849 switch (keyData & Keys.KeyCode) {
850 case Keys.X: { // Cut (Ctrl-X)
851 if (control) {
852 Cut();
853 return true;
855 return false;
858 case Keys.C: { // Copy (Ctrl-C)
859 if (control) {
860 Copy();
861 return true;
863 return false;
866 case Keys.V: { // Paste (Ctrl-V)
867 if (control) {
868 return Paste(Clipboard.GetDataObject(), null, true);
870 return false;
873 case Keys.Z: { // Undo (Ctrl-Z)
874 if (control) {
875 Undo();
876 return true;
878 return false;
881 case Keys.A: { // Select All (Ctrl-A)
882 if (control) {
883 SelectAll();
884 return true;
886 return false;
889 case Keys.Left: {
890 if (control) {
891 document.MoveCaret(CaretDirection.WordBack);
892 } else {
893 if (!document.selection_visible || shift) {
894 document.MoveCaret(CaretDirection.CharBack);
895 } else {
896 document.MoveCaret(CaretDirection.SelectionStart);
900 if (!shift) {
901 document.SetSelectionToCaret(true);
902 } else {
903 document.SetSelectionToCaret(false);
906 CaretMoved(this, null);
907 return true;
910 case Keys.Right: {
911 if (control) {
912 document.MoveCaret(CaretDirection.WordForward);
913 } else {
914 if (!document.selection_visible || shift) {
915 document.MoveCaret(CaretDirection.CharForward);
916 } else {
917 document.MoveCaret(CaretDirection.SelectionEnd);
920 if (!shift) {
921 document.SetSelectionToCaret(true);
922 } else {
923 document.SetSelectionToCaret(false);
926 CaretMoved(this, null);
927 return true;
930 case Keys.Up: {
931 if (control) {
932 if (document.CaretPosition == 0) {
933 document.MoveCaret(CaretDirection.LineUp);
934 } else {
935 document.MoveCaret(CaretDirection.Home);
937 } else {
938 document.MoveCaret(CaretDirection.LineUp);
941 if ((Control.ModifierKeys & Keys.Shift) == 0) {
942 document.SetSelectionToCaret(true);
943 } else {
944 document.SetSelectionToCaret(false);
947 CaretMoved(this, null);
948 return true;
951 case Keys.Down: {
952 if (control) {
953 if (document.CaretPosition == document.CaretLine.Text.Length) {
954 document.MoveCaret(CaretDirection.LineDown);
955 } else {
956 document.MoveCaret(CaretDirection.End);
958 } else {
959 document.MoveCaret(CaretDirection.LineDown);
962 if ((Control.ModifierKeys & Keys.Shift) == 0) {
963 document.SetSelectionToCaret(true);
964 } else {
965 document.SetSelectionToCaret(false);
968 CaretMoved(this, null);
969 return true;
972 case Keys.Home: {
973 if ((Control.ModifierKeys & Keys.Control) != 0) {
974 document.MoveCaret(CaretDirection.CtrlHome);
975 } else {
976 document.MoveCaret(CaretDirection.Home);
979 if ((Control.ModifierKeys & Keys.Shift) == 0) {
980 document.SetSelectionToCaret(true);
981 } else {
982 document.SetSelectionToCaret(false);
985 CaretMoved(this, null);
986 return true;
989 case Keys.End: {
990 if ((Control.ModifierKeys & Keys.Control) != 0) {
991 document.MoveCaret(CaretDirection.CtrlEnd);
992 } else {
993 document.MoveCaret(CaretDirection.End);
996 if ((Control.ModifierKeys & Keys.Shift) == 0) {
997 document.SetSelectionToCaret(true);
998 } else {
999 document.SetSelectionToCaret(false);
1002 CaretMoved(this, null);
1003 return true;
1006 case Keys.Enter: {
1007 // ignoring accepts_return, fixes bug #76355
1008 if (!read_only && multiline && (accepts_return || (FindForm() != null && FindForm().AcceptButton == null) || ((Control.ModifierKeys & Keys.Control) != 0))) {
1009 Line line;
1011 if (document.selection_visible) {
1012 document.ReplaceSelection("");
1014 document.SetSelectionToCaret(true);
1016 line = document.CaretLine;
1018 document.Split(document.CaretLine, document.CaretTag, document.CaretPosition, false);
1019 OnTextChanged(EventArgs.Empty);
1020 document.UpdateView(line, 2, 0);
1021 document.MoveCaret(CaretDirection.CharForward);
1022 CaretMoved(this, null);
1023 return true;
1025 break;
1028 case Keys.Tab: {
1029 if (!read_only && accepts_tab && multiline) {
1030 document.InsertChar(document.CaretLine, document.CaretPosition, '\t');
1031 if (document.selection_visible) {
1032 document.ReplaceSelection("");
1034 document.SetSelectionToCaret(true);
1036 OnTextChanged(EventArgs.Empty);
1037 CaretMoved(this, null);
1038 return true;
1040 break;
1043 case Keys.Insert: {
1044 if (shift) {
1045 Paste(Clipboard.GetDataObject(), null, true);
1046 return true;
1049 if (control) {
1050 Copy();
1051 return true;
1054 // FIXME - need overwrite/insert toggle?
1055 return false;
1058 case Keys.PageUp: {
1059 if ((Control.ModifierKeys & Keys.Control) != 0) {
1060 document.MoveCaret(CaretDirection.CtrlPgUp);
1061 } else {
1062 document.MoveCaret(CaretDirection.PgUp);
1064 return true;
1067 case Keys.PageDown: {
1068 if ((Control.ModifierKeys & Keys.Control) != 0) {
1069 document.MoveCaret(CaretDirection.CtrlPgDn);
1070 } else {
1071 document.MoveCaret(CaretDirection.PgDn);
1073 return true;
1076 case Keys.Delete: {
1077 if (shift) {
1078 Cut();
1079 return true;
1082 if (read_only) {
1083 break;
1086 if (document.selection_visible) {
1087 document.ReplaceSelection("");
1088 } else {
1089 // DeleteChar only deletes on the line, doesn't do the combine
1090 if (document.CaretPosition == document.CaretLine.Text.Length) {
1091 if (document.CaretLine.LineNo < document.Lines) {
1092 Line line;
1094 line = document.GetLine(document.CaretLine.LineNo + 1);
1095 document.Combine(document.CaretLine, line);
1096 document.UpdateView(document.CaretLine, 2, 0);
1098 #if not_Debug
1099 Line check_first;
1100 Line check_second;
1102 check_first = document.GetLine(document.CaretLine.LineNo);
1103 check_second = document.GetLine(check_first.line_no + 1);
1105 Console.WriteLine("Post-UpdateView: Y of first line: {0}, second line: {1}", check_first.Y, check_second.Y);
1106 #endif
1108 // Caret doesn't move
1110 } else {
1111 if (!control) {
1112 document.DeleteChar(document.CaretTag, document.CaretPosition, true);
1113 } else {
1114 int end_pos;
1116 end_pos = document.CaretPosition;
1118 while ((end_pos < document.CaretLine.Text.Length) && !Document.IsWordSeparator(document.CaretLine.Text[end_pos])) {
1119 end_pos++;
1122 if (end_pos < document.CaretLine.Text.Length) {
1123 end_pos++;
1125 document.DeleteChars(document.CaretTag, document.CaretPosition, end_pos - document.CaretPosition);
1130 OnTextChanged(EventArgs.Empty);
1131 document.AlignCaret();
1132 document.UpdateCaret();
1133 CaretMoved(this, null);
1134 return true;
1137 return false;
1140 private void HandleBackspace(bool control) {
1141 bool fire_changed;
1143 fire_changed = false;
1145 // delete only deletes on the line, doesn't do the combine
1146 if (document.selection_visible) {
1147 document.ReplaceSelection("");
1148 fire_changed = true;
1150 document.SetSelectionToCaret(true);
1152 if (document.CaretPosition == 0) {
1153 if (document.CaretLine.LineNo > 1) {
1154 Line line;
1155 int new_caret_pos;
1157 line = document.GetLine(document.CaretLine.LineNo - 1);
1158 new_caret_pos = line.text.Length;
1160 document.Combine(line, document.CaretLine);
1161 document.UpdateView(line, 1, 0);
1162 document.PositionCaret(line, new_caret_pos);
1163 //document.MoveCaret(CaretDirection.CharForward);
1164 document.UpdateCaret();
1165 fire_changed = true;
1167 } else {
1168 if (!control || document.CaretPosition == 0) {
1169 document.DeleteChar(document.CaretTag, document.CaretPosition, false);
1170 document.MoveCaret(CaretDirection.CharBack);
1171 } else {
1172 int start_pos;
1174 start_pos = document.CaretPosition - 1;
1176 while ((start_pos > 0) && !Document.IsWordSeparator(document.CaretLine.Text[start_pos - 1])) {
1177 start_pos--;
1179 document.DeleteChars(document.CaretTag, start_pos, document.CaretPosition - start_pos);
1180 document.PositionCaret(document.CaretLine, start_pos);
1182 document.UpdateCaret();
1183 fire_changed = true;
1185 if (fire_changed) {
1186 OnTextChanged(EventArgs.Empty);
1188 CaretMoved(this, null);
1191 protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) {
1192 // Make sure we don't get sized bigger than we want to be
1193 if (!richtext) {
1194 if (!multiline) {
1195 if (height != PreferredHeight) {
1196 requested_height = height;
1197 height = PreferredHeight;
1198 specified |= BoundsSpecified.Height;
1203 base.SetBoundsCore (x, y, width, height, specified);
1205 TextBoxBase_SizeChanged(this, EventArgs.Empty);
1206 CalculateDocument();
1209 protected override void WndProc(ref Message m) {
1210 switch ((Msg)m.Msg) {
1211 case Msg.WM_KEYDOWN: {
1212 if (ProcessKeyMessage(ref m) || ProcessKey((Keys)m.WParam.ToInt32() | XplatUI.State.ModifierKeys)) {
1213 m.Result = IntPtr.Zero;
1214 return;
1216 DefWndProc (ref m);
1217 return;
1220 case Msg.WM_CHAR: {
1221 int ch;
1223 if (ProcessKeyMessage(ref m)) {
1224 m.Result = IntPtr.Zero;
1225 return;
1228 if (read_only) {
1229 return;
1232 m.Result = IntPtr.Zero;
1234 ch = m.WParam.ToInt32();
1236 if (ch == 127) {
1237 HandleBackspace(true);
1238 } else if (ch >= 32) {
1239 if (document.selection_visible) {
1240 document.ReplaceSelection("");
1243 char c = (char)m.WParam;
1244 switch (character_casing) {
1245 case CharacterCasing.Upper:
1246 c = Char.ToUpper((char) m.WParam);
1247 break;
1248 case CharacterCasing.Lower:
1249 c = Char.ToLower((char) m.WParam);
1250 break;
1253 if (document.Length < max_length) {
1254 document.InsertCharAtCaret(c, true);
1255 OnTextChanged(EventArgs.Empty);
1256 CaretMoved(this, null);
1257 } else {
1258 XplatUI.AudibleAlert();
1260 return;
1261 } else if (ch == 8) {
1262 HandleBackspace(false);
1265 return;
1268 default: {
1269 base.WndProc(ref m);
1270 return;
1275 #endregion // Protected Instance Methods
1277 #region Events
1278 public event EventHandler AcceptsTabChanged;
1279 public event EventHandler AutoSizeChanged;
1280 [Browsable(false)]
1281 [EditorBrowsable(EditorBrowsableState.Never)]
1282 public new event EventHandler BackgroundImageChanged {
1283 add { base.BackgroundImageChanged += value; }
1284 remove { base.BackgroundImageChanged -= value; }
1286 public event EventHandler BorderStyleChanged;
1287 [Browsable(false)]
1288 [EditorBrowsable(EditorBrowsableState.Advanced)]
1289 public event EventHandler Click {
1290 add { base.Click += value; }
1291 remove { base.Click -= value; }
1294 public event EventHandler HideSelectionChanged;
1295 public event EventHandler ModifiedChanged;
1296 public event EventHandler MultilineChanged;
1297 [Browsable(false)]
1298 [EditorBrowsable(EditorBrowsableState.Never)]
1299 public event PaintEventHandler Paint;
1300 public event EventHandler ReadOnlyChanged;
1302 internal event EventHandler HScrolled;
1303 internal event EventHandler VScrolled;
1304 #endregion // Events
1306 #region Private Methods
1307 internal Document Document {
1308 get {
1309 return document;
1312 set {
1313 document = value;
1317 internal bool ShowSelection {
1318 get {
1319 if (show_selection) {
1320 return true;
1323 return has_focus;
1326 set {
1327 if (show_selection == value)
1328 return;
1330 show_selection = value;
1331 // Currently InvalidateSelectionArea is commented out so do a full invalidate
1332 document.InvalidateSelectionArea();
1336 internal Graphics CreateGraphicsInternal() {
1337 if (IsHandleCreated) {
1338 return base.CreateGraphics();
1341 return Graphics.FromImage(bmp);
1344 #if Debug
1345 static int current;
1346 #endif
1348 internal override void OnPaintInternal (PaintEventArgs pevent) {
1349 // Fill background
1350 if (backcolor_set || (Enabled && !read_only)) {
1351 pevent.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(BackColor), pevent.ClipRectangle);
1352 } else {
1353 pevent.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(ThemeEngine.Current.ColorControl), pevent.ClipRectangle);
1355 pevent.Graphics.TextRenderingHint=TextRenderingHint.AntiAlias;
1357 // Draw the viewable document
1358 document.Draw(pevent.Graphics, pevent.ClipRectangle);
1360 Rectangle rect = ClientRectangle;
1361 rect.Width--;
1362 rect.Height--;
1363 //pevent.Graphics.DrawRectangle(ThemeEngine.Current.ResPool.GetPen(ThemeEngine.Current.ColorControlDark), rect);
1365 #if Debug
1366 int start;
1367 int end;
1368 Line line;
1369 int line_no;
1370 Pen p;
1372 p = new Pen(Color.Red, 1);
1374 // First, figure out from what line to what line we need to draw
1375 start = document.GetLineByPixel(pevent.ClipRectangle.Top - document.ViewPortY, false).line_no;
1376 end = document.GetLineByPixel(pevent.ClipRectangle.Bottom - document.ViewPortY, false).line_no;
1378 //Console.WriteLine("Starting drawing on line '{0}'", document.GetLine(start));
1379 //Console.WriteLine("Ending drawing on line '{0}'", document.GetLine(end));
1381 line_no = start;
1382 while (line_no <= end) {
1383 line = document.GetLine(line_no);
1385 if (draw_lines) {
1386 for (int i = 0; i < line.text.Length; i++) {
1387 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);
1391 line_no++;
1393 #endif
1396 internal override void OnGotFocusInternal (EventArgs e)
1398 document.CaretHasFocus ();
1399 base.OnGotFocusInternal (e);
1402 internal override void OnLostFocusInternal (EventArgs e)
1404 document.CaretLostFocus ();
1405 base.OnLostFocusInternal (e);
1408 private void TextBoxBase_MouseDown(object sender, MouseEventArgs e) {
1409 if (e.Button == MouseButtons.Left) {
1410 TimeSpan interval;
1412 interval = DateTime.Now - click_last;
1413 document.PositionCaret(e.X + document.ViewPortX, e.Y + document.ViewPortY);
1415 // Handle place caret/select word/select line behaviour
1416 if (e.Clicks == 1) {
1417 if (SystemInformation.DoubleClickTime < interval.TotalMilliseconds) {
1418 #if DebugClick
1419 Console.WriteLine("Single Click Invalidating from char {0} to char {1} ({2})", document.selection_start.pos, document.selection_end.pos, document.selection_start.line.text.ToString(document.selection_start.pos, document.selection_end.pos - document.selection_start.pos));
1420 #endif
1421 document.SetSelectionToCaret(true);
1422 click_mode = CaretSelection.Position;
1423 } else {
1424 #if DebugClick
1425 Console.WriteLine("Tripple Click Selecting line");
1426 #endif
1427 document.ExpandSelection(CaretSelection.Line, false);
1428 click_mode = CaretSelection.Line;
1430 } else {
1431 // We select the line if the word is already selected, and vice versa
1432 if (click_mode != CaretSelection.Word) {
1433 if (click_mode == CaretSelection.Line) {
1434 document.Invalidate(document.selection_start.line, 0, document.selection_start.line, document.selection_start.line.text.Length);
1436 click_mode = CaretSelection.Word;
1437 document.ExpandSelection(CaretSelection.Word, false); // Setting initial selection
1438 } else {
1439 click_mode = CaretSelection.Line;
1440 document.ExpandSelection(CaretSelection.Line, false); // Setting initial selection
1444 // Reset
1445 click_last = DateTime.Now;
1446 return;
1449 if ((e.Button == MouseButtons.Middle) && (((int)Environment.OSVersion.Platform == 4) || ((int)Environment.OSVersion.Platform == 128))) {
1450 Document.Marker marker;
1452 marker.tag = document.FindCursor(e.X + document.ViewPortX, e.Y + document.ViewPortY, out marker.pos);
1453 marker.line = marker.tag.line;
1454 marker.height = marker.tag.height;
1456 document.SetSelection(marker.line, marker.pos, marker.line, marker.pos);
1457 Paste (Clipboard.GetDataObject (true), null, true);
1461 #if Debug
1462 LineTag tag;
1463 Line line;
1464 int pos;
1466 if (e.Button == MouseButtons.Right) {
1467 draw_lines = !draw_lines;
1468 this.Invalidate();
1469 Console.WriteLine("SelectedText: {0}, length {1}", this.SelectedText, this.SelectionLength);
1470 Console.WriteLine("Selection start: {0}", this.SelectionStart);
1472 this.SelectionStart = 10;
1473 this.SelectionLength = 5;
1475 return;
1478 tag = document.FindTag(e.X + document.ViewPortX, e.Y + document.ViewPortY, out pos, false);
1480 Console.WriteLine("Click found tag {0}, character {1}", tag, pos);
1481 line = tag.line;
1482 switch(current) {
1483 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;
1484 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;
1485 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;
1486 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;
1487 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;
1488 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;
1490 current++;
1491 if (current==6) {
1492 current=0;
1495 // Update/Recalculate what we see
1496 document.UpdateView(line, 0);
1498 // Make sure our caret is properly positioned and sized
1499 document.AlignCaret();
1500 #endif
1503 private void TextBoxBase_MouseUp(object sender, MouseEventArgs e) {
1504 if (e.Button == MouseButtons.Left) {
1505 document.PositionCaret(e.X + document.ViewPortX, e.Y + document.ViewPortY);
1506 if (click_mode == CaretSelection.Position) {
1507 document.SetSelectionToCaret(false);
1508 document.DisplayCaret();
1509 } else {
1510 document.ExpandSelection(click_mode, true);
1512 return;
1516 private void TextBoxBase_SizeChanged(object sender, EventArgs e) {
1517 if (hscroll.Visible) {
1518 //vscroll.Maximum += hscroll.Height;
1519 canvas_height = ClientSize.Height - hscroll.Height;
1520 } else {
1521 canvas_height = ClientSize.Height;
1524 if (vscroll.Visible) {
1525 //hscroll.Maximum += vscroll.Width;
1526 canvas_width = ClientSize.Width - vscroll.Width;
1527 } else {
1528 canvas_width = ClientSize.Width;
1532 document.ViewPortWidth = canvas_width;
1533 document.ViewPortHeight = canvas_height;
1535 // We always move them, they just might not be displayed
1536 hscroll.Bounds = new Rectangle (ClientRectangle.Left, ClientRectangle.Height - hscroll.Height, ClientSize.Width - (vscroll.Visible ? vscroll.Width : 0), hscroll.Height);
1537 vscroll.Bounds = new Rectangle (ClientRectangle.Right - vscroll.Width, ClientRectangle.Top, vscroll.Width, ClientSize.Height - (hscroll.Visible ? hscroll.Height : 0));
1541 private void TextBoxBase_MouseWheel(object sender, MouseEventArgs e) {
1542 Line line;
1543 int line_no;
1545 if (!vscroll.Enabled) {
1546 return;
1549 if (e.Delta < 0) {
1550 line_no = document.GetLineByPixel(document.ViewPortY, false).line_no + SystemInformation.MouseWheelScrollLines;
1551 if (line_no > document.Lines) {
1552 line_no = document.Lines;
1554 } else {
1555 line_no = document.GetLineByPixel(document.ViewPortY, false).line_no - SystemInformation.MouseWheelScrollLines;
1556 if (line_no < 1) {
1557 line_no = 1;
1561 line = document.GetLine(line_no);
1562 if (line.Y < vscroll.Maximum) {
1563 vscroll.Value = line.Y;
1564 } else {
1565 vscroll.Value = vscroll.Maximum;
1569 internal void CalculateDocument() {
1570 if (!IsHandleCreated) {
1571 return;
1573 document.RecalculateDocument(CreateGraphicsInternal());
1574 CalculateScrollBars();
1575 Invalidate();
1578 internal void CalculateScrollBars() {
1579 // FIXME - need separate calculations for center and right alignment
1580 // No scrollbars for a single line
1582 if (!multiline) {
1583 return;
1586 if (document.Width >= document.ViewPortWidth) {
1587 hscroll.Enabled = true;
1588 hscroll.Minimum = 0;
1589 hscroll.LargeChange = document.ViewPortWidth < 0 ? 0 : document.ViewPortWidth;
1590 hscroll.Maximum = document.Width;
1591 } else {
1592 hscroll.Maximum = document.ViewPortWidth;
1593 hscroll.Enabled = false;
1596 if (document.Height >= document.ViewPortHeight) {
1597 vscroll.Enabled = true;
1598 vscroll.Minimum = 0;
1599 vscroll.LargeChange = document.ViewPortHeight < 0 ? 0 : document.ViewPortHeight;
1600 vscroll.Maximum = document.Height;
1601 } else {
1602 vscroll.Maximum = document.ViewPortHeight;
1603 vscroll.Enabled = false;
1607 if (!WordWrap) {
1608 if ((scrollbars & RichTextBoxScrollBars.Horizontal) != 0) {
1609 if (((scrollbars & RichTextBoxScrollBars.ForcedHorizontal) != 0) || hscroll.Enabled) {
1610 hscroll.Visible = true;
1611 } else {
1612 hscroll.Visible = false;
1614 } else {
1615 hscroll.Visible = false;
1619 if ((scrollbars & RichTextBoxScrollBars.Vertical) != 0) {
1620 if (((scrollbars & RichTextBoxScrollBars.ForcedVertical) != 0) || vscroll.Enabled) {
1621 vscroll.Visible = true;
1622 } else {
1623 vscroll.Visible = false;
1625 } else {
1626 vscroll.Visible = false;
1629 TextBoxBase_SizeChanged(this, EventArgs.Empty);
1632 private void document_WidthChanged(object sender, EventArgs e) {
1633 CalculateScrollBars();
1636 private void document_HeightChanged(object sender, EventArgs e) {
1637 CalculateScrollBars();
1640 private void hscroll_ValueChanged(object sender, EventArgs e) {
1641 int old_viewport_x;
1643 old_viewport_x = document.ViewPortX;
1644 document.ViewPortX = this.hscroll.Value;
1646 if (vscroll.Visible) {
1647 XplatUI.ScrollWindow(this.Handle, new Rectangle(0, 0, ClientSize.Width - vscroll.Width, ClientSize.Height), old_viewport_x - this.hscroll.Value, 0, false);
1648 } else {
1649 XplatUI.ScrollWindow(this.Handle, ClientRectangle, old_viewport_x - this.hscroll.Value, 0, false);
1651 document.UpdateCaret();
1653 if (HScrolled != null) {
1654 HScrolled(this, EventArgs.Empty);
1658 private void vscroll_ValueChanged(object sender, EventArgs e) {
1659 int old_viewport_y;
1661 old_viewport_y = document.ViewPortY;
1662 document.ViewPortY = this.vscroll.Value;
1664 if (hscroll.Visible) {
1665 XplatUI.ScrollWindow(this.Handle, new Rectangle(0, 0, ClientSize.Width, ClientSize.Height - hscroll.Height), 0, old_viewport_y - this.vscroll.Value, false);
1666 } else {
1667 XplatUI.ScrollWindow(this.Handle, ClientRectangle, 0, old_viewport_y - this.vscroll.Value, false);
1669 document.UpdateCaret();
1671 if (VScrolled != null) {
1672 VScrolled(this, EventArgs.Empty);
1676 private void TextBoxBase_MouseMove(object sender, MouseEventArgs e) {
1677 // FIXME - handle auto-scrolling if mouse is to the right/left of the window
1678 if (Capture) {
1679 document.PositionCaret(e.X + document.ViewPortX, e.Y + document.ViewPortY);
1680 if (click_mode == CaretSelection.Position) {
1681 document.SetSelectionToCaret(false);
1682 document.DisplayCaret();
1683 } else {
1684 document.ExpandSelection(click_mode, true);
1689 private void TextBoxBase_FontOrColorChanged(object sender, EventArgs e) {
1690 if (!richtext) {
1691 Line line;
1693 // Font changes apply to the whole document
1694 for (int i = 1; i <= document.Lines; i++) {
1695 line = document.GetLine(i);
1696 LineTag.FormatText(line, 1, line.text.Length, Font, ThemeEngine.Current.ResPool.GetSolidBrush(ForeColor));
1697 document.UpdateView(line, 0);
1699 // Make sure the caret height is matching the new font height
1700 document.AlignCaret();
1704 /// <summary>Ensure the caret is always visible</summary>
1705 internal void CaretMoved(object sender, EventArgs e) {
1706 Point pos;
1707 int height;
1709 pos = document.Caret;
1710 //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);
1713 // Horizontal scrolling:
1714 // If the caret moves to the left outside the visible area, we jump the document into view, not just one
1715 // character, but 1/3 of the width of the document
1716 // If the caret moves to the right outside the visible area, we scroll just enough to keep the caret visible
1718 // Handle horizontal scrolling
1719 if (document.CaretLine.alignment == HorizontalAlignment.Left) {
1720 // Check if we moved out of view to the left
1721 if (pos.X < (document.ViewPortX)) {
1722 do {
1723 if ((hscroll.Value - document.ViewPortWidth / 3) >= hscroll.Minimum) {
1724 hscroll.Value -= document.ViewPortWidth / 3;
1725 } else {
1726 hscroll.Value = hscroll.Minimum;
1728 } while (hscroll.Value > pos.X);
1731 // Check if we moved out of view to the right
1732 if ((pos.X >= (document.ViewPortWidth + document.ViewPortX)) && (hscroll.Value != hscroll.Maximum)) {
1733 if ((pos.X - document.ViewPortWidth + 1) <= hscroll.Maximum) {
1734 if (pos.X - document.ViewPortWidth >= 0) {
1735 hscroll.Value = pos.X - document.ViewPortWidth + 1;
1736 } else {
1737 hscroll.Value = 0;
1739 } else {
1740 hscroll.Value = hscroll.Maximum;
1743 } else if (document.CaretLine.alignment == HorizontalAlignment.Right) {
1744 // hscroll.Value = pos.X;
1746 // if ((pos.X > (this.canvas_width + document.ViewPortX)) && (hscroll.Enabled && (hscroll.Value != hscroll.Maximum))) {
1747 // hscroll.Value = hscroll.Maximum;
1748 // }
1749 } else {
1750 // FIXME - implement center cursor alignment
1753 if (!multiline) {
1754 return;
1757 // Handle vertical scrolling
1758 height = document.CaretLine.Height + 1;
1760 if (pos.Y < document.ViewPortY) {
1761 vscroll.Value = pos.Y;
1764 if ((pos.Y + height) > (document.ViewPortY + canvas_height)) {
1765 vscroll.Value = pos.Y - canvas_height + height;
1769 internal bool Paste(IDataObject clip, DataFormats.Format format, bool obey_length) {
1770 string s;
1772 if (clip == null)
1773 return false;
1775 if (format == null) {
1776 if ((this is RichTextBox) && clip.GetDataPresent(DataFormats.Rtf)) {
1777 format = DataFormats.GetFormat(DataFormats.Rtf);
1778 } else if (clip.GetDataPresent(DataFormats.UnicodeText)) {
1779 format = DataFormats.GetFormat(DataFormats.UnicodeText);
1780 } else if (clip.GetDataPresent(DataFormats.Text)) {
1781 format = DataFormats.GetFormat(DataFormats.Text);
1782 } else {
1783 return false;
1785 } else {
1786 if ((format.Name == DataFormats.Rtf) && !(this is RichTextBox)) {
1787 return false;
1790 if (!clip.GetDataPresent(format.Name)) {
1791 return false;
1795 if (format.Name == DataFormats.Rtf) {
1796 ((RichTextBox)this).SelectedRtf = (string)clip.GetData(DataFormats.Rtf);
1797 return true;
1798 } else if (format.Name == DataFormats.UnicodeText) {
1799 s = (string)clip.GetData(DataFormats.UnicodeText);
1800 } else if (format.Name == DataFormats.Text) {
1801 s = (string)clip.GetData(DataFormats.Text);
1802 } else {
1803 return false;
1806 if (!obey_length) {
1807 this.SelectedText = s;
1808 } else {
1809 if ((s.Length + document.Length) < max_length) {
1810 this.SelectedText = s;
1811 } else if (document.Length < max_length) {
1812 this.SelectedText = s.Substring(0, max_length - document.Length);
1816 return true;
1818 #endregion // Private Methods