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:c
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)
23 // Peter Bartok pbartok@novell.com
31 using System.ComponentModel;
32 using System.ComponentModel.Design;
34 using System.Drawing.Text;
36 using System.Runtime.InteropServices;
37 using System.Collections;
39 namespace System.Windows.Forms {
42 [DefaultBindingProperty ("Text")]
43 [ClassInterface (ClassInterfaceType.AutoDispatch)]
45 [DefaultEvent("TextChanged")]
46 [Designer("System.Windows.Forms.Design.TextBoxBaseDesigner, " + Consts.AssemblySystem_Design)]
47 public abstract class TextBoxBase : Control {
48 #region Local Variables
49 internal HorizontalAlignment alignment;
50 internal bool accepts_tab;
51 internal bool accepts_return;
52 internal bool auto_size;
53 internal bool backcolor_set;
54 internal CharacterCasing character_casing;
55 internal bool hide_selection;
56 internal int max_length;
57 internal bool modified;
58 internal char password_char;
59 internal bool read_only;
60 internal bool word_wrap;
61 internal Document document;
62 internal LineTag caret_tag; // tag our cursor is in
63 internal int caret_pos; // position on the line our cursor is in (can be 0 = beginning of line)
64 internal ImplicitHScrollBar hscroll;
65 internal ImplicitVScrollBar vscroll;
66 internal RichTextBoxScrollBars scrollbars;
67 internal Timer scroll_timer;
68 internal bool richtext;
69 internal bool show_selection; // set to true to always show selection, even if no focus is set
71 internal bool has_been_focused;
73 internal int selection_length = -1; // set to the user-specified selection length, or -1 if none
74 internal bool show_caret_w_selection; // TextBox shows the caret when the selection is visible
75 internal int requested_height;
76 internal int canvas_width;
77 internal int canvas_height;
78 static internal int track_width = 2; //
79 static internal int track_border = 5; //
80 internal DateTime click_last;
81 internal int click_point_x;
82 internal int click_point_y;
83 internal CaretSelection click_mode;
85 internal BorderStyle actual_border_style;
86 internal bool shortcuts_enabled = true;
88 internal static bool draw_lines = false;
91 #endregion // Local Variables
93 #region Internal Constructor
94 // Constructor will go when complete, only for testing - pdb
95 internal TextBoxBase() {
96 alignment = HorizontalAlignment.Left;
97 accepts_return = false;
100 InternalBorderStyle = BorderStyle.Fixed3D;
101 actual_border_style = BorderStyle.Fixed3D;
102 character_casing = CharacterCasing.Normal;
103 hide_selection = true;
106 password_char = '\0';
110 show_selection = false;
111 show_caret_w_selection = (this is TextBox);
112 document = new Document(this);
113 document.WidthChanged += new EventHandler(document_WidthChanged);
114 document.HeightChanged += new EventHandler(document_HeightChanged);
115 //document.CaretMoved += new EventHandler(CaretMoved);
116 document.Wrap = false;
117 requested_height = -1;
118 click_last = DateTime.Now;
119 click_mode = CaretSelection.Position;
120 bmp = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
122 MouseDown += new MouseEventHandler(TextBoxBase_MouseDown);
123 MouseUp += new MouseEventHandler(TextBoxBase_MouseUp);
124 MouseMove += new MouseEventHandler(TextBoxBase_MouseMove);
125 SizeChanged += new EventHandler(TextBoxBase_SizeChanged);
126 FontChanged += new EventHandler(TextBoxBase_FontOrColorChanged);
127 ForeColorChanged += new EventHandler(TextBoxBase_FontOrColorChanged);
128 MouseWheel += new MouseEventHandler(TextBoxBase_MouseWheel);
130 scrollbars = RichTextBoxScrollBars.None;
132 hscroll = new ImplicitHScrollBar();
133 hscroll.ValueChanged += new EventHandler(hscroll_ValueChanged);
134 hscroll.SetStyle (ControlStyles.Selectable, false);
135 hscroll.Enabled = false;
136 hscroll.Visible = false;
137 hscroll.Maximum = Int32.MaxValue;
139 vscroll = new ImplicitVScrollBar();
140 vscroll.ValueChanged += new EventHandler(vscroll_ValueChanged);
141 vscroll.SetStyle (ControlStyles.Selectable, false);
142 vscroll.Enabled = false;
143 vscroll.Visible = false;
144 vscroll.Maximum = Int32.MaxValue;
147 this.Controls.AddImplicit (hscroll);
148 this.Controls.AddImplicit (vscroll);
151 SetStyle(ControlStyles.UserPaint | ControlStyles.StandardClick, false);
153 SetStyle(ControlStyles.UseTextForAccessibility, false);
155 base.SetAutoSizeMode (AutoSizeMode.GrowAndShrink);
158 canvas_width = ClientSize.Width;
159 canvas_height = ClientSize.Height;
160 document.ViewPortWidth = canvas_width;
161 document.ViewPortHeight = canvas_height;
163 Cursor = Cursors.IBeam;
165 #endregion // Internal Constructor
167 #region Private and Internal Methods
168 internal string CaseAdjust(string s) {
169 if (character_casing == CharacterCasing.Normal) {
172 if (character_casing == CharacterCasing.Lower) {
180 internal override Size GetPreferredSizeCore (Size proposedSize)
182 return new Size (Width, ExplicitBounds.Height);
186 internal override void HandleClick(int clicks, MouseEventArgs me) {
187 // MS seems to fire the click event in spite of the styles they set
188 bool click_set = GetStyle (ControlStyles.StandardClick);
189 bool doubleclick_set = GetStyle (ControlStyles.StandardDoubleClick);
191 // so explicitly set them to true first
192 SetStyle (ControlStyles.StandardClick | ControlStyles.StandardDoubleClick, true);
194 base.HandleClick (clicks, me);
196 // then revert to our previous state
198 SetStyle (ControlStyles.StandardClick, false);
199 if (!doubleclick_set)
200 SetStyle (ControlStyles.StandardDoubleClick, false);
203 #endregion // Private and Internal Methods
205 #region Public Instance Properties
206 [DefaultValue(false)]
207 [MWFCategory("Behavior")]
208 public bool AcceptsTab {
214 if (value != accepts_tab) {
216 OnAcceptsTabChanged(EventArgs.Empty);
223 [EditorBrowsable (EditorBrowsableState.Never)]
227 [RefreshProperties(RefreshProperties.Repaint)]
228 [MWFCategory("Behavior")]
241 if (value != auto_size) {
244 if (PreferredHeight != ClientSize.Height) {
245 ClientSize = new Size(ClientSize.Width, PreferredHeight);
249 OnAutoSizeChanged(EventArgs.Empty);
256 public override System.Drawing.Color BackColor {
258 return base.BackColor;
261 backcolor_set = true;
262 base.BackColor = ChangeBackColor (value);
267 [EditorBrowsable(EditorBrowsableState.Never)]
268 public override System.Drawing.Image BackgroundImage {
270 return base.BackgroundImage;
273 base.BackgroundImage = value;
277 [DefaultValue(BorderStyle.Fixed3D)]
279 [MWFCategory("Appearance")]
280 public BorderStyle BorderStyle {
281 get { return actual_border_style; }
283 if (value == actual_border_style)
286 if (actual_border_style != BorderStyle.Fixed3D || value != BorderStyle.Fixed3D)
289 actual_border_style = value;
290 document.UpdateMargins ();
292 if (value != BorderStyle.Fixed3D)
293 value = BorderStyle.None;
295 InternalBorderStyle = value;
296 OnBorderStyleChanged(EventArgs.Empty);
301 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
302 public bool CanUndo {
304 return document.undo.CanUndo;
309 public override System.Drawing.Color ForeColor {
311 return base.ForeColor;
314 base.ForeColor = value;
319 [MWFCategory("Behavior")]
320 public bool HideSelection {
322 return hide_selection;
326 if (value != hide_selection) {
327 hide_selection = value;
328 OnHideSelectionChanged(EventArgs.Empty);
330 if (hide_selection) {
331 document.selection_visible = false;
333 document.selection_visible = true;
335 document.InvalidateSelectionArea();
341 [MergableProperty (false)]
343 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
344 [Editor("System.Windows.Forms.Design.StringArrayEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
346 [MWFCategory("Appearance")]
347 public string[] Lines {
352 count = document.Lines;
354 // Handle empty document
355 if ((count == 1) && (document.GetLine (1).text.Length == 0)) {
356 return new string [0];
359 lines = new ArrayList ();
364 StringBuilder lt = new StringBuilder ();
367 line = document.GetLine (i++);
368 lt.Append (line.TextWithoutEnding ());
369 } while (line.ending == LineEnding.Wrap && i <= count);
371 lines.Add (lt.ToString ());
374 return (string []) lines.ToArray (typeof (string));
385 brush = ThemeEngine.Current.ResPool.GetSolidBrush(this.ForeColor);
387 document.SuspendRecalc ();
388 for (i = 0; i < l; i++) {
390 // Don't add the last line if it is just an empty line feed
391 // the line feed is reflected in the previous line's ending
392 if (i == l - 1 && value [i].Length == 0)
395 LineEnding ending = LineEnding.Rich;
396 if (value [i].EndsWith ("\r"))
397 ending = LineEnding.Hard;
399 document.Add (i + 1, CaseAdjust (value [i]), alignment, Font, brush, ending);
402 document.ResumeRecalc (true);
404 // CalculateDocument();
405 OnTextChanged(EventArgs.Empty);
409 [DefaultValue(32767)]
411 [MWFCategory("Behavior")]
412 public virtual int MaxLength {
414 if (max_length == 2147483646) { // We don't distinguish between single and multi-line limits
421 if (value != max_length) {
428 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
429 public bool Modified {
435 if (value != modified) {
437 OnModifiedChanged(EventArgs.Empty);
442 [DefaultValue(false)]
444 [RefreshProperties(RefreshProperties.All)]
445 [MWFCategory("Behavior")]
446 public virtual bool Multiline {
448 return document.multiline;
452 if (value != document.multiline) {
453 document.multiline = value;
454 // Make sure we update our size; the user may have already set the size before going to multiline
455 if (document.multiline && requested_height != -1) {
456 Height = requested_height;
457 requested_height = -1;
461 Parent.PerformLayout ();
463 OnMultilineChanged(EventArgs.Empty);
466 if (document.multiline) {
467 document.Wrap = word_wrap;
468 document.PasswordChar = "";
471 document.Wrap = false;
472 if (this.password_char != '\0') {
473 document.PasswordChar = password_char.ToString();
475 document.PasswordChar = "";
480 CalculateDocument ();
485 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
486 [EditorBrowsable(EditorBrowsableState.Advanced)]
487 public int PreferredHeight {
489 return Font.Height + (BorderStyle == BorderStyle.None ? 0 : 7);
494 [RefreshProperties (RefreshProperties.Repaint)]
496 [DefaultValue(false)]
497 [MWFCategory("Behavior")]
498 public bool ReadOnly {
504 if (value != read_only) {
507 if (!backcolor_set) {
509 background_color = SystemColors.Control;
511 background_color = SystemColors.Window;
514 OnReadOnlyChanged(EventArgs.Empty);
521 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
522 public virtual string SelectedText {
524 return document.GetSelection();
528 document.ReplaceSelection(CaseAdjust(value), false);
531 OnTextChanged(EventArgs.Empty);
536 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
537 public virtual int SelectionLength {
539 int res = document.SelectionLength ();
542 if (res == 0 && !IsHandleCreated)
551 throw new ArgumentException(String.Format("{0} is not a valid value", value), "value");
560 selection_length = value;
562 start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
564 document.CharIndexToLineTag(start + value, out line, out tag, out pos);
565 document.SetSelectionEnd(line, pos, true);
566 document.PositionCaret(line, pos);
568 selection_length = -1;
570 document.SetSelectionEnd(document.selection_start.line, document.selection_start.pos, true);
571 document.PositionCaret(document.selection_start.line, document.selection_start.pos);
577 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
578 public int SelectionStart {
582 index = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
588 document.SetSelectionStart(value, false);
589 if (selection_length > -1 ) {
590 document.SetSelectionEnd(value + selection_length, true);
592 document.SetSelectionEnd(value, true);
594 document.PositionCaret(document.selection_start.line, document.selection_start.pos);
600 [DefaultValue (true)]
601 public virtual bool ShortcutsEnabled {
602 get { return shortcuts_enabled; }
603 set { shortcuts_enabled = value; }
606 [Editor ("System.ComponentModel.Design.MultilineStringEditor, " + Consts.AssemblySystem_Design,
607 "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
610 public override string Text {
612 if (document == null || document.Root == null || document.Root.text == null) {
616 StringBuilder sb = new StringBuilder();
619 for (int i = 1; i <= document.Lines; i++) {
620 line = document.GetLine (i);
621 sb.Append(line.text.ToString ());
624 return sb.ToString();
628 // reset to force a select all next time the box gets focus
629 has_been_focused = false;
634 if ((value != null) && (value != "")) {
638 document.Insert (document.GetLine (1), 0, false, value);
640 document.PositionCaret (document.GetLine (1), 0);
641 document.SetSelectionToCaret (true);
647 CalculateDocument ();
650 // set the var so OnModifiedChanged is not raised
652 OnTextChanged(EventArgs.Empty);
657 public virtual int TextLength {
659 if (document == null || document.Root == null || document.Root.text == null) {
668 [MWFCategory("Behavior")]
669 public bool WordWrap {
675 if (value != word_wrap) {
676 if (document.multiline) {
678 document.Wrap = value;
680 CalculateDocument ();
686 [EditorBrowsable (EditorBrowsableState.Never)]
687 public override ImageLayout BackgroundImageLayout {
688 get { return base.BackgroundImageLayout; }
689 set { base.BackgroundImageLayout = value; }
693 [EditorBrowsable (EditorBrowsableState.Never)]
694 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
695 public new Padding Padding {
696 get { return base.Padding; }
697 set { base.Padding = value; }
700 protected override Cursor DefaultCursor {
701 get { return Cursors.IBeam; }
704 #endregion // Public Instance Properties
706 #region Protected Instance Properties
707 protected override CreateParams CreateParams {
709 return base.CreateParams;
713 protected override System.Drawing.Size DefaultSize {
715 return new Size(100, 20);
720 // Currently our double buffering breaks our scrolling, so don't let people enable this
721 [EditorBrowsable (EditorBrowsableState.Never)]
722 protected override bool DoubleBuffered {
723 get { return false; }
728 #endregion // Protected Instance Properties
730 #region Public Instance Methods
731 public void AppendText(string text)
733 // Save some cycles and only check the Text if we are one line
734 bool is_empty = document.Lines == 1 && Text == String.Empty;
736 document.MoveCaret (CaretDirection.CtrlEnd);
737 document.Insert (document.caret.line, document.caret.pos, false, text);
738 document.MoveCaret (CaretDirection.CtrlEnd);
739 document.SetSelectionToCaret (true);
745 // Avoid the initial focus selecting all when append text is used
747 has_been_focused = true;
749 OnTextChanged(EventArgs.Empty);
752 public void Clear() {
756 public void ClearUndo() {
757 document.undo.Clear();
763 o = new DataObject(DataFormats.Text, SelectedText);
764 if (this is RichTextBox) {
765 o.SetData(DataFormats.Rtf, ((RichTextBox)this).SelectedRtf);
767 Clipboard.SetDataObject(o);
773 o = new DataObject(DataFormats.Text, SelectedText);
774 if (this is RichTextBox) {
775 o.SetData(DataFormats.Rtf, ((RichTextBox)this).SelectedRtf);
777 Clipboard.SetDataObject (o);
779 document.undo.BeginUserAction (Locale.GetText ("Cut"));
780 document.ReplaceSelection (String.Empty, false);
781 document.undo.EndUserAction ();
783 OnTextChanged (EventArgs.Empty);
786 public void Paste() {
787 Paste(Clipboard.GetDataObject(), null, false);
790 public void ScrollToCaret() {
791 if (IsHandleCreated) {
792 CaretMoved(this, EventArgs.Empty);
796 public void Select(int start, int length) {
797 SelectionStart = start;
798 SelectionLength = length;
802 public void SelectAll() {
805 last = document.GetLine(document.Lines);
806 document.SetSelectionStart(document.GetLine(1), 0, false);
807 document.SetSelectionEnd(last, last.text.Length, true);
808 document.PositionCaret (document.selection_end.line, document.selection_end.pos);
809 selection_length = -1;
811 CaretMoved (this, null);
813 document.DisplayCaret ();
816 internal void SelectAllNoScroll ()
820 last = document.GetLine(document.Lines);
821 document.SetSelectionStart(document.GetLine(1), 0, false);
822 document.SetSelectionEnd(last, last.text.Length, false);
823 document.PositionCaret (document.selection_end.line, document.selection_end.pos);
824 selection_length = -1;
826 document.DisplayCaret ();
829 public override string ToString() {
830 return String.Concat (base.ToString (), ", Text: ", Text);
834 document.undo.Undo();
838 public void DeselectAll ()
843 public virtual char GetCharFromPosition (Point p)
846 LineTag tag = document.FindCursor (p.X, p.Y, out index);
848 return (char) 0; // Shouldn't happen
850 if (index >= tag.line.text.Length) {
852 if (tag.line.ending == LineEnding.Wrap) {
853 // If we have wrapped text, we return the first char of the next line
854 Line line = document.GetLine (tag.line.line_no + 1);
856 return line.text [0];
860 if (tag.line.line_no == document.Lines) {
861 // Last line returns the last char
862 return tag.line.text [tag.line.text.Length - 1];
865 // This really shouldn't happen
868 return tag.line.text [index];
871 public virtual int GetCharIndexFromPosition (Point p)
874 LineTag tag = document.FindCursor (p.X, p.Y, out line_index);
878 if (line_index >= tag.line.text.Length) {
880 if (tag.line.ending == LineEnding.Wrap) {
881 // If we have wrapped text, we return the first char of the next line
882 Line line = document.GetLine (tag.line.line_no + 1);
884 return document.LineTagToCharIndex (line, 0);
887 if (tag.line.line_no == document.Lines) {
888 // Last line returns the last char
889 return document.LineTagToCharIndex (tag.line, tag.line.text.Length - 1);
895 return document.LineTagToCharIndex (tag.line, line_index);
898 public virtual Point GetPositionFromCharIndex (int index)
904 document.CharIndexToLineTag (index, out line, out tag, out pos);
906 return new Point ((int) (line.widths [pos] +
907 line.X + document.viewport_x),
908 line.Y + document.viewport_y + tag.shift);
911 public int GetFirstCharIndexFromLine (int line_number)
913 Line line = document.GetLine (line_number + 1);
917 return document.LineTagToCharIndex (line, 0);
920 public int GetFirstCharIndexOfCurrentLine ()
922 return document.LineTagToCharIndex (document.caret.line, 0);
925 #endregion // Public Instance Methods
927 #region Protected Instance Methods
928 protected override void CreateHandle() {
929 CalculateDocument ();
930 base.CreateHandle ();
931 document.AlignCaret();
935 protected override bool IsInputKey(Keys keyData) {
936 if ((keyData & Keys.Alt) != 0) {
937 return base.IsInputKey(keyData);
940 switch (keyData & Keys.KeyCode) {
942 if (accepts_return && document.multiline) {
949 if (accepts_tab && document.multiline) {
950 if ((keyData & Keys.Control) == 0) {
972 protected virtual void OnAcceptsTabChanged(EventArgs e) {
973 EventHandler eh = (EventHandler)(Events [AcceptsTabChangedEvent]);
978 protected virtual void OnAutoSizeChanged(EventArgs e) {
979 EventHandler eh = (EventHandler)(Events [AutoSizeChangedEvent]);
985 protected virtual void OnBorderStyleChanged(EventArgs e) {
986 EventHandler eh = (EventHandler)(Events [BorderStyleChangedEvent]);
991 protected override void OnFontChanged(EventArgs e) {
992 base.OnFontChanged (e);
994 if (auto_size && !document.multiline) {
995 if (PreferredHeight != ClientSize.Height) {
996 Height = PreferredHeight;
1001 protected override void OnHandleCreated(EventArgs e) {
1002 base.OnHandleCreated (e);
1006 protected override void OnHandleDestroyed(EventArgs e) {
1007 base.OnHandleDestroyed (e);
1010 protected virtual void OnHideSelectionChanged(EventArgs e) {
1011 EventHandler eh = (EventHandler)(Events [HideSelectionChangedEvent]);
1016 protected virtual void OnModifiedChanged(EventArgs e) {
1017 EventHandler eh = (EventHandler)(Events [ModifiedChangedEvent]);
1022 protected virtual void OnMultilineChanged(EventArgs e) {
1023 EventHandler eh = (EventHandler)(Events [MultilineChangedEvent]);
1029 protected override void OnPaddingChanged (EventArgs e)
1031 base.OnPaddingChanged (e);
1035 protected virtual void OnReadOnlyChanged(EventArgs e) {
1036 EventHandler eh = (EventHandler)(Events [ReadOnlyChangedEvent]);
1042 protected override bool ProcessCmdKey (ref Message msg, Keys keyData)
1044 return base.ProcessCmdKey (ref msg, keyData);
1047 protected override bool ProcessDialogKey(Keys keyData) {
1048 return base.ProcessDialogKey(keyData);
1051 private bool ProcessKey(Keys keyData) {
1055 control = (Control.ModifierKeys & Keys.Control) != 0;
1056 shift = (Control.ModifierKeys & Keys.Shift) != 0;
1058 if (shortcuts_enabled) {
1059 switch (keyData & Keys.KeyCode) {
1076 return Paste(Clipboard.GetDataObject(), null, true);
1096 Paste(Clipboard.GetDataObject(), null, true);
1116 if (document.selection_visible) {
1117 document.ReplaceSelection("", false);
1119 // DeleteChar only deletes on the line, doesn't do the combine
1120 if (document.CaretPosition >= document.CaretLine.TextLengthWithoutEnding ()) {
1121 if (document.CaretLine.LineNo < document.Lines) {
1124 line = document.GetLine(document.CaretLine.LineNo + 1);
1126 // this line needs to be invalidated before it is combined
1127 // because once it is combined, all it's coordinates will
1129 document.Invalidate (line, 0, line, line.text.Length);
1130 document.Combine(document.CaretLine, line);
1132 document.UpdateView(document.CaretLine,
1138 document.DeleteChar(document.CaretTag, document.CaretPosition, true);
1142 end_pos = document.CaretPosition;
1144 while ((end_pos < document.CaretLine.Text.Length) && !Document.IsWordSeparator(document.CaretLine.Text[end_pos])) {
1148 if (end_pos < document.CaretLine.Text.Length) {
1151 document.DeleteChars(document.CaretTag, document.CaretPosition, end_pos - document.CaretPosition);
1156 OnTextChanged(EventArgs.Empty);
1157 document.AlignCaret();
1158 document.UpdateCaret();
1159 CaretMoved(this, null);
1164 switch (keyData & Keys.KeyCode) {
1167 document.MoveCaret(CaretDirection.WordBack);
1169 if (!document.selection_visible || shift) {
1170 document.MoveCaret(CaretDirection.CharBack);
1172 document.MoveCaret(CaretDirection.SelectionStart);
1177 document.SetSelectionToCaret(true);
1179 document.SetSelectionToCaret(false);
1182 CaretMoved(this, null);
1188 document.MoveCaret(CaretDirection.WordForward);
1190 if (!document.selection_visible || shift) {
1191 document.MoveCaret(CaretDirection.CharForward);
1193 document.MoveCaret(CaretDirection.SelectionEnd);
1197 document.SetSelectionToCaret(true);
1199 document.SetSelectionToCaret(false);
1202 CaretMoved(this, null);
1208 if (document.CaretPosition == 0) {
1209 document.MoveCaret(CaretDirection.LineUp);
1211 document.MoveCaret(CaretDirection.Home);
1214 document.MoveCaret(CaretDirection.LineUp);
1217 if ((Control.ModifierKeys & Keys.Shift) == 0) {
1218 document.SetSelectionToCaret(true);
1220 document.SetSelectionToCaret(false);
1223 CaretMoved(this, null);
1229 if (document.CaretPosition == document.CaretLine.Text.Length) {
1230 document.MoveCaret(CaretDirection.LineDown);
1232 document.MoveCaret(CaretDirection.End);
1235 document.MoveCaret(CaretDirection.LineDown);
1238 if ((Control.ModifierKeys & Keys.Shift) == 0) {
1239 document.SetSelectionToCaret(true);
1241 document.SetSelectionToCaret(false);
1244 CaretMoved(this, null);
1249 if ((Control.ModifierKeys & Keys.Control) != 0) {
1250 document.MoveCaret(CaretDirection.CtrlHome);
1252 document.MoveCaret(CaretDirection.Home);
1255 if ((Control.ModifierKeys & Keys.Shift) == 0) {
1256 document.SetSelectionToCaret(true);
1258 document.SetSelectionToCaret(false);
1261 CaretMoved(this, null);
1266 if ((Control.ModifierKeys & Keys.Control) != 0) {
1267 document.MoveCaret(CaretDirection.CtrlEnd);
1269 document.MoveCaret(CaretDirection.End);
1272 if ((Control.ModifierKeys & Keys.Shift) == 0) {
1273 document.SetSelectionToCaret(true);
1275 document.SetSelectionToCaret(false);
1278 CaretMoved(this, null);
1283 // ignoring accepts_return, fixes bug #76355
1284 if (!read_only && document.multiline && (accepts_return || (FindForm() != null && FindForm().AcceptButton == null) || ((Control.ModifierKeys & Keys.Control) != 0))) {
1287 if (document.selection_visible) {
1288 document.ReplaceSelection("\n", false);
1291 line = document.CaretLine;
1293 document.Split (document.CaretLine, document.CaretTag, document.CaretPosition);
1294 line.ending = LineEnding.Rich;
1295 document.InsertString (line, line.text.Length,
1296 document.LineEndingToString (line.ending));
1297 OnTextChanged(EventArgs.Empty);
1299 document.UpdateView (line, document.Lines - line.line_no, 0);
1300 CaretMoved(this, null);
1307 if (!read_only && accepts_tab && document.multiline) {
1308 document.InsertCharAtCaret ('\t', true);
1310 OnTextChanged(EventArgs.Empty);
1311 CaretMoved(this, null);
1318 if ((Control.ModifierKeys & Keys.Control) != 0) {
1319 document.MoveCaret(CaretDirection.CtrlPgUp);
1321 document.MoveCaret(CaretDirection.PgUp);
1323 document.DisplayCaret ();
1327 case Keys.PageDown: {
1328 if ((Control.ModifierKeys & Keys.Control) != 0) {
1329 document.MoveCaret(CaretDirection.CtrlPgDn);
1331 document.MoveCaret(CaretDirection.PgDn);
1333 document.DisplayCaret ();
1341 private void HandleBackspace(bool control) {
1344 fire_changed = false;
1346 // delete only deletes on the line, doesn't do the combine
1347 if (document.selection_visible) {
1348 document.undo.BeginUserAction (Locale.GetText ("Delete"));
1349 document.ReplaceSelection("", false);
1350 document.undo.EndUserAction ();
1351 fire_changed = true;
1353 document.SetSelectionToCaret(true);
1355 if (document.CaretPosition == 0) {
1356 if (document.CaretLine.LineNo > 1) {
1360 line = document.GetLine(document.CaretLine.LineNo - 1);
1361 new_caret_pos = line.TextLengthWithoutEnding ();
1363 // Invalidate the old line position before we do the combine
1364 document.Invalidate (line, 0, line, line.text.Length);
1365 document.Combine(line, document.CaretLine);
1367 document.UpdateView(line, document.Lines - line.LineNo, 0);
1368 document.PositionCaret(line, new_caret_pos);
1369 document.SetSelectionToCaret (true);
1370 document.UpdateCaret();
1371 fire_changed = true;
1374 if (!control || document.CaretPosition == 0) {
1376 // Move before we delete because the delete will change positions around
1377 // if we cross a wrap border
1378 LineTag tag = document.CaretTag;
1379 int pos = document.CaretPosition;
1380 document.MoveCaret (CaretDirection.CharBack);
1381 document.DeleteChar (tag, pos, false);
1382 document.SetSelectionToCaret (true);
1387 start_pos = document.CaretPosition - 1;
1388 while ((start_pos > 0) && !Document.IsWordSeparator(document.CaretLine.Text[start_pos - 1])) {
1392 document.undo.BeginUserAction (Locale.GetText ("Delete"));
1393 document.DeleteChars(document.CaretTag, start_pos, document.CaretPosition - start_pos);
1394 document.undo.EndUserAction ();
1395 document.PositionCaret(document.CaretLine, start_pos);
1396 document.SetSelectionToCaret (true);
1398 document.UpdateCaret();
1399 fire_changed = true;
1403 OnTextChanged(EventArgs.Empty);
1405 CaretMoved(this, null);
1408 protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) {
1409 // Make sure we don't get sized bigger than we want to be
1412 if (!document.multiline) {
1413 if (height != PreferredHeight) {
1414 requested_height = height;
1415 height = PreferredHeight;
1420 base.SetBoundsCore (x, y, width, height, specified);
1423 protected override void WndProc(ref Message m) {
1424 switch ((Msg)m.Msg) {
1425 case Msg.WM_KEYDOWN: {
1426 if (ProcessKeyMessage(ref m) || ProcessKey((Keys)m.WParam.ToInt32() | XplatUI.State.ModifierKeys)) {
1427 m.Result = IntPtr.Zero;
1437 if (ProcessKeyMessage(ref m)) {
1438 m.Result = IntPtr.Zero;
1446 m.Result = IntPtr.Zero;
1448 ch = m.WParam.ToInt32();
1451 HandleBackspace(true);
1452 } else if (ch >= 32) {
1453 if (document.selection_visible) {
1454 document.ReplaceSelection("", false);
1457 char c = (char)m.WParam;
1458 switch (character_casing) {
1459 case CharacterCasing.Upper:
1460 c = Char.ToUpper((char) m.WParam);
1462 case CharacterCasing.Lower:
1463 c = Char.ToLower((char) m.WParam);
1467 if (document.Length < max_length) {
1468 document.InsertCharAtCaret(c, true);
1472 OnTextChanged(EventArgs.Empty);
1473 CaretMoved(this, null);
1475 XplatUI.AudibleAlert();
1478 } else if (ch == 8) {
1479 HandleBackspace(false);
1485 case Msg.WM_SETFOCUS:
1486 base.WndProc(ref m);
1487 document.CaretHasFocus ();
1490 case Msg.WM_KILLFOCUS:
1491 base.WndProc(ref m);
1492 document.CaretLostFocus ();
1496 base.WndProc(ref m);
1501 #endregion // Protected Instance Methods
1504 static object AcceptsTabChangedEvent = new object ();
1505 static object AutoSizeChangedEvent = new object ();
1506 static object BorderStyleChangedEvent = new object ();
1507 static object HideSelectionChangedEvent = new object ();
1508 static object ModifiedChangedEvent = new object ();
1509 static object MultilineChangedEvent = new object ();
1510 static object ReadOnlyChangedEvent = new object ();
1511 static object HScrolledEvent = new object ();
1512 static object VScrolledEvent = new object ();
1514 public event EventHandler AcceptsTabChanged {
1515 add { Events.AddHandler (AcceptsTabChangedEvent, value); }
1516 remove { Events.RemoveHandler (AcceptsTabChangedEvent, value); }
1520 [EditorBrowsable (EditorBrowsableState.Never)]
1521 public new event EventHandler AutoSizeChanged {
1522 add { Events.AddHandler (AutoSizeChangedEvent, value); }
1523 remove { Events.RemoveHandler (AutoSizeChangedEvent, value); }
1526 public event EventHandler BorderStyleChanged {
1527 add { Events.AddHandler (BorderStyleChangedEvent, value); }
1528 remove { Events.RemoveHandler (BorderStyleChangedEvent, value); }
1531 public event EventHandler HideSelectionChanged {
1532 add { Events.AddHandler (HideSelectionChangedEvent, value); }
1533 remove { Events.RemoveHandler (HideSelectionChangedEvent, value); }
1536 public event EventHandler ModifiedChanged {
1537 add { Events.AddHandler (ModifiedChangedEvent, value); }
1538 remove { Events.RemoveHandler (ModifiedChangedEvent, value); }
1541 public event EventHandler MultilineChanged {
1542 add { Events.AddHandler (MultilineChangedEvent, value); }
1543 remove { Events.RemoveHandler (MultilineChangedEvent, value); }
1546 public event EventHandler ReadOnlyChanged {
1547 add { Events.AddHandler (ReadOnlyChangedEvent, value); }
1548 remove { Events.RemoveHandler (ReadOnlyChangedEvent, value); }
1551 internal event EventHandler HScrolled {
1552 add { Events.AddHandler (HScrolledEvent, value); }
1553 remove { Events.RemoveHandler (HScrolledEvent, value); }
1556 internal event EventHandler VScrolled {
1557 add { Events.AddHandler (VScrolledEvent, value); }
1558 remove { Events.RemoveHandler (VScrolledEvent, value); }
1562 [EditorBrowsable(EditorBrowsableState.Never)]
1563 public new event EventHandler BackgroundImageChanged {
1564 add { base.BackgroundImageChanged += value; }
1565 remove { base.BackgroundImageChanged -= value; }
1570 [EditorBrowsable (EditorBrowsableState.Never)]
1571 public new event EventHandler BackgroundImageLayoutChanged {
1572 add { base.BackgroundImageLayoutChanged += value; }
1573 remove { base.BackgroundImageLayoutChanged -= value; }
1577 [EditorBrowsable (EditorBrowsableState.Always)]
1578 public new event MouseEventHandler MouseClick {
1579 add { base.MouseClick += value; }
1580 remove { base.MouseClick -= value; }
1584 [EditorBrowsable (EditorBrowsableState.Never)]
1585 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
1586 public new event EventHandler PaddingChanged {
1587 add { base.PaddingChanged += value; }
1588 remove { base.PaddingChanged -= value; }
1592 [EditorBrowsable (EditorBrowsableState.Always)]
1595 [EditorBrowsable(EditorBrowsableState.Advanced)]
1597 public new event EventHandler Click {
1598 add { base.Click += value; }
1599 remove { base.Click -= value; }
1602 // XXX should this not manipulate base.Paint?
1604 [EditorBrowsable(EditorBrowsableState.Never)]
1605 public new event PaintEventHandler Paint;
1606 #endregion // Events
1608 #region Private Methods
1609 internal Document Document {
1619 internal bool ShowSelection {
1621 if (show_selection || !hide_selection) {
1629 if (show_selection == value)
1632 show_selection = value;
1633 // Currently InvalidateSelectionArea is commented out so do a full invalidate
1634 document.InvalidateSelectionArea();
1638 internal Graphics CreateGraphicsInternal() {
1639 if (IsHandleCreated) {
1640 return base.CreateGraphics();
1643 return Graphics.FromImage(bmp);
1646 internal override void OnPaintInternal (PaintEventArgs pevent) {
1648 if (backcolor_set || (Enabled && !read_only)) {
1649 pevent.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(BackColor), pevent.ClipRectangle);
1651 pevent.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(ThemeEngine.Current.ColorControl), pevent.ClipRectangle);
1654 // Draw the viewable document
1655 document.Draw(pevent.Graphics, pevent.ClipRectangle);
1658 // OnPaint does not get raised on MS (see bug #80639)
1660 pevent.Handled = true;
1663 private void FixupHeight ()
1666 if (!document.multiline) {
1667 if (PreferredHeight != ClientSize.Height) {
1668 ClientSize = new Size (ClientSize.Width, PreferredHeight);
1674 private bool IsDoubleClick (MouseEventArgs e)
1676 TimeSpan interval = DateTime.Now - click_last;
1677 if (interval.TotalMilliseconds > SystemInformation.DoubleClickTime)
1679 Size dcs = SystemInformation.DoubleClickSize;
1680 if (e.X < click_point_x - dcs.Width / 2 || e.X > click_point_x + dcs.Width / 2)
1682 if (e.Y < click_point_y - dcs.Height / 2 || e.Y > click_point_y + dcs.Height / 2)
1687 private void TextBoxBase_MouseDown (object sender, MouseEventArgs e)
1689 if (e.Button == MouseButtons.Left) {
1691 document.PositionCaret(e.X + document.ViewPortX, e.Y + document.ViewPortY);
1693 if (IsDoubleClick (e)) {
1694 switch (click_mode) {
1695 case CaretSelection.Position:
1697 click_mode = CaretSelection.Word;
1699 case CaretSelection.Word:
1701 if (this is TextBox) {
1702 document.SetSelectionToCaret (true);
1703 click_mode = CaretSelection.Position;
1707 document.ExpandSelection (CaretSelection.Line, false);
1708 click_mode = CaretSelection.Line;
1710 case CaretSelection.Line:
1712 // Gotta do this first because Exanding to a word
1713 // from a line doesn't really work
1714 document.SetSelectionToCaret (true);
1717 click_mode = CaretSelection.Word;
1721 document.SetSelectionToCaret (true);
1722 click_mode = CaretSelection.Position;
1725 click_point_x = e.X;
1726 click_point_y = e.Y;
1727 click_last = DateTime.Now;
1730 if ((e.Button == MouseButtons.Middle) && XplatUI.RunningOnUnix) {
1731 Document.Marker marker;
1733 marker.tag = document.FindCursor(e.X + document.ViewPortX, e.Y + document.ViewPortY, out marker.pos);
1734 marker.line = marker.tag.line;
1735 marker.height = marker.tag.height;
1737 document.SetSelection(marker.line, marker.pos, marker.line, marker.pos);
1738 Paste (Clipboard.GetDataObject (true), null, true);
1743 private void TextBoxBase_MouseUp(object sender, MouseEventArgs e) {
1744 if (e.Button == MouseButtons.Left) {
1745 if (click_mode == CaretSelection.Position) {
1746 document.SetSelectionToCaret(false);
1747 document.DisplayCaret();
1750 if (scroll_timer != null) {
1751 scroll_timer.Enabled = false;
1757 private void PositionControls ()
1759 if (hscroll.Visible) {
1760 //vscroll.Maximum += hscroll.Height;
1761 canvas_height = ClientSize.Height - hscroll.Height;
1763 canvas_height = ClientSize.Height;
1766 if (vscroll.Visible) {
1767 //hscroll.Maximum += vscroll.Width;
1768 canvas_width = ClientSize.Width - vscroll.Width;
1770 canvas_width = ClientSize.Width;
1774 document.ViewPortWidth = canvas_width;
1775 document.ViewPortHeight = canvas_height;
1777 if (canvas_height < 1 || canvas_width < 1)
1780 // We always move them, they just might not be displayed
1781 hscroll.Bounds = new Rectangle (ClientRectangle.Left,
1782 Math.Max (0, ClientRectangle.Height - hscroll.Height),
1783 Math.Max (0, ClientSize.Width - (vscroll.Visible ? vscroll.Width : 0)),
1786 vscroll.Bounds = new Rectangle (Math.Max (0, ClientRectangle.Right - vscroll.Width),
1787 ClientRectangle.Top, vscroll.Width,
1788 Math.Max (0, ClientSize.Height - (hscroll.Visible ? hscroll.Height : 0)));
1792 private void TextBoxBase_SizeChanged(object sender, EventArgs e) {
1793 if (IsHandleCreated)
1794 CalculateDocument ();
1797 private void TextBoxBase_MouseWheel(object sender, MouseEventArgs e) {
1799 if (!vscroll.Enabled) {
1804 vscroll.Value = Math.Min (vscroll.Value + SystemInformation.MouseWheelScrollLines * 5,
1805 Math.Max (0, vscroll.Maximum - document.ViewPortHeight + 1));
1807 vscroll.Value = Math.Max (0, vscroll.Value - SystemInformation.MouseWheelScrollLines * 5);
1810 internal virtual void SelectWord ()
1812 StringBuilder s = document.caret.line.text;
1813 int start = document.caret.pos;
1814 int end = document.caret.pos;
1817 if (document.caret.line.line_no >= document.Lines)
1819 Line line = document.GetLine (document.caret.line.line_no + 1);
1820 document.PositionCaret (line, 0);
1829 // skip whitespace until we hit a word
1830 while (start > 0 && s [start] == ' ')
1833 while (start > 0 && (s [start] != ' '))
1835 if (s [start] == ' ')
1839 if (s [end] == ' ') {
1840 while (end < s.Length && s [end] == ' ')
1843 while (end < s.Length && s [end] != ' ')
1845 while (end < s.Length && s [end] == ' ')
1849 document.SetSelection (document.caret.line, start, document.caret.line, end);
1850 document.PositionCaret (document.selection_end.line, document.selection_end.pos);
1851 document.DisplayCaret();
1854 internal void CalculateDocument()
1856 CalculateScrollBars ();
1857 document.RecalculateDocument (CreateGraphicsInternal ());
1860 if (document.caret.line != null && document.caret.line.Y < document.ViewPortHeight) {
1861 // The window has probably been resized, making the entire thing visible, so
1862 // we need to set the scroll position back to zero.
1869 internal void CalculateScrollBars () {
1870 // FIXME - need separate calculations for center and right alignment
1874 if (document.Width >= document.ViewPortWidth) {
1875 hscroll.SetValues (0, Math.Max (1, document.Width), -1,
1876 document.ViewPortWidth < 0 ? 0 : document.ViewPortWidth);
1877 if (document.multiline)
1878 hscroll.Enabled = true;
1880 hscroll.Enabled = false;
1881 hscroll.Maximum = document.ViewPortWidth;
1884 if (document.Height >= document.ViewPortHeight) {
1885 vscroll.SetValues (0, Math.Max (1, document.Height), -1,
1886 document.ViewPortHeight < 0 ? 0 : document.ViewPortHeight);
1887 if (document.multiline)
1888 vscroll.Enabled = true;
1890 vscroll.Enabled = false;
1891 vscroll.Maximum = document.ViewPortHeight;
1895 switch (scrollbars) {
1896 case RichTextBoxScrollBars.Both:
1897 case RichTextBoxScrollBars.Horizontal:
1898 hscroll.Visible = hscroll.Enabled;
1900 case RichTextBoxScrollBars.ForcedBoth:
1901 case RichTextBoxScrollBars.ForcedHorizontal:
1902 hscroll.Visible = true;
1905 hscroll.Visible = false;
1909 hscroll.Visible = false;
1912 switch (scrollbars) {
1913 case RichTextBoxScrollBars.Both:
1914 case RichTextBoxScrollBars.Vertical:
1915 vscroll.Visible = vscroll.Enabled;
1917 case RichTextBoxScrollBars.ForcedBoth:
1918 case RichTextBoxScrollBars.ForcedVertical:
1919 vscroll.Visible = true;
1922 vscroll.Visible = false;
1926 PositionControls ();
1929 private void document_WidthChanged(object sender, EventArgs e) {
1930 CalculateScrollBars();
1933 private void document_HeightChanged(object sender, EventArgs e) {
1934 CalculateScrollBars();
1937 private void hscroll_ValueChanged(object sender, EventArgs e) {
1940 old_viewport_x = document.ViewPortX;
1941 document.ViewPortX = this.hscroll.Value;
1944 // Before scrolling we want to destroy the caret, then draw a new one after the scroll
1945 // the reason for this is that scrolling changes the coordinates of the caret, and we
1946 // will get tracers if we don't
1949 document.CaretLostFocus ();
1951 if (vscroll.Visible) {
1952 XplatUI.ScrollWindow(this.Handle, new Rectangle(0, 0, ClientSize.Width - vscroll.Width, ClientSize.Height), old_viewport_x - this.hscroll.Value, 0, false);
1954 XplatUI.ScrollWindow(this.Handle, ClientRectangle, old_viewport_x - this.hscroll.Value, 0, false);
1958 document.CaretHasFocus ();
1960 EventHandler eh = (EventHandler)(Events [HScrolledEvent]);
1962 eh (this, EventArgs.Empty);
1965 private void vscroll_ValueChanged(object sender, EventArgs e) {
1968 old_viewport_y = document.ViewPortY;
1969 document.ViewPortY = this.vscroll.Value;
1972 // Before scrolling we want to destroy the caret, then draw a new one after the scroll
1973 // the reason for this is that scrolling changes the coordinates of the caret, and we
1974 // will get tracers if we don't
1977 document.CaretLostFocus ();
1979 if (hscroll.Visible) {
1980 XplatUI.ScrollWindow(this.Handle, new Rectangle(0, 0, ClientSize.Width, ClientSize.Height - hscroll.Height), 0, old_viewport_y - this.vscroll.Value, false);
1982 XplatUI.ScrollWindow(this.Handle, ClientRectangle, 0, old_viewport_y - this.vscroll.Value, false);
1986 document.CaretHasFocus ();
1988 EventHandler eh = (EventHandler)(Events [VScrolledEvent]);
1990 eh (this, EventArgs.Empty);
1993 private void TextBoxBase_MouseMove(object sender, MouseEventArgs e) {
1994 // FIXME - handle auto-scrolling if mouse is to the right/left of the window
1995 if (e.Button == MouseButtons.Left && Capture) {
1996 if (!ClientRectangle.Contains (e.X, e.Y)) {
1997 if (scroll_timer == null) {
1998 scroll_timer = new Timer ();
1999 scroll_timer.Interval = 100;
2000 scroll_timer.Tick += new EventHandler (ScrollTimerTickHandler);
2003 if (!scroll_timer.Enabled) {
2004 scroll_timer.Start ();
2006 // Force the first tick
2007 ScrollTimerTickHandler (null, EventArgs.Empty);
2011 document.PositionCaret(e.X + document.ViewPortX, e.Y + document.ViewPortY);
2012 if (click_mode == CaretSelection.Position) {
2013 document.SetSelectionToCaret(false);
2014 document.DisplayCaret();
2019 private void TextBoxBase_FontOrColorChanged(object sender, EventArgs e) {
2023 document.SuspendRecalc ();
2024 // Font changes apply to the whole document
2025 for (int i = 1; i <= document.Lines; i++) {
2026 line = document.GetLine(i);
2027 LineTag.FormatText(line, 1, line.text.Length, Font,
2028 ThemeEngine.Current.ResPool.GetSolidBrush(ForeColor),
2029 null, FormatSpecified.Font | FormatSpecified.Color);
2031 document.ResumeRecalc (false);
2033 // Make sure the caret height is matching the new font height
2034 document.AlignCaret();
2038 private void ScrollTimerTickHandler (object sender, EventArgs e)
2040 Point pt = Cursor.Position;
2042 pt = PointToClient (pt);
2044 if (pt.X < ClientRectangle.Left) {
2045 document.MoveCaret(CaretDirection.CharBackNoWrap);
2046 document.SetSelectionToCaret(false);
2048 CaretMoved(this, null);
2049 } else if (pt.X > ClientRectangle.Right) {
2050 document.MoveCaret(CaretDirection.CharForwardNoWrap);
2051 document.SetSelectionToCaret(false);
2053 CaretMoved(this, null);
2054 } else if (pt.Y > ClientRectangle.Bottom) {
2055 document.MoveCaret(CaretDirection.LineDown);
2056 document.SetSelectionToCaret(false);
2058 CaretMoved(this, null);
2059 } else if (pt.Y < ClientRectangle.Top) {
2060 document.MoveCaret(CaretDirection.LineUp);
2061 document.SetSelectionToCaret(false);
2063 CaretMoved(this, null);
2067 /// <summary>Ensure the caret is always visible</summary>
2068 internal void CaretMoved(object sender, EventArgs e) {
2072 if (!IsHandleCreated || canvas_width < 1 || canvas_height < 1)
2075 document.MoveCaretToTextTag ();
2076 pos = document.Caret;
2078 //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);
2081 // Horizontal scrolling:
2082 // If the caret moves to the left outside the visible area, we jump the document into view, not just one
2083 // character, but 1/3 of the width of the document
2084 // If the caret moves to the right outside the visible area, we scroll just enough to keep the caret visible
2086 // Handle horizontal scrolling
2087 if (document.CaretLine.alignment == HorizontalAlignment.Left) {
2088 // Check if we moved out of view to the left
2089 if (pos.X < (document.ViewPortX)) {
2091 if ((hscroll.Value - document.ViewPortWidth / 3) >= hscroll.Minimum) {
2092 hscroll.Value -= document.ViewPortWidth / 3;
2094 hscroll.Value = hscroll.Minimum;
2096 } while (hscroll.Value > pos.X);
2099 // Check if we moved out of view to the right
2100 if ((pos.X >= (document.ViewPortWidth + document.ViewPortX)) && (hscroll.Value != hscroll.Maximum)) {
2101 if ((pos.X - document.ViewPortWidth + 1) <= hscroll.Maximum) {
2102 if (pos.X - document.ViewPortWidth >= 0) {
2103 hscroll.Value = pos.X - document.ViewPortWidth + 1;
2108 hscroll.Value = hscroll.Maximum;
2111 } else if (document.CaretLine.alignment == HorizontalAlignment.Right) {
2112 // hscroll.Value = pos.X;
2114 // if ((pos.X > (this.canvas_width + document.ViewPortX)) && (hscroll.Enabled && (hscroll.Value != hscroll.Maximum))) {
2115 // hscroll.Value = hscroll.Maximum;
2118 // FIXME - implement center cursor alignment
2121 if (!document.multiline) {
2125 // Handle vertical scrolling
2126 height = document.CaretLine.Height + 1;
2128 if (pos.Y < document.ViewPortY) {
2129 vscroll.Value = pos.Y;
2132 if ((pos.Y + height) > (document.ViewPortY + canvas_height)) {
2133 vscroll.Value = Math.Min (vscroll.Maximum, pos.Y - canvas_height + height);
2137 internal bool Paste(IDataObject clip, DataFormats.Format format, bool obey_length) {
2143 if (format == null) {
2144 if ((this is RichTextBox) && clip.GetDataPresent(DataFormats.Rtf)) {
2145 format = DataFormats.GetFormat(DataFormats.Rtf);
2146 } else if ((this is RichTextBox) && clip.GetDataPresent (DataFormats.Bitmap)) {
2147 format = DataFormats.GetFormat (DataFormats.Bitmap);
2148 } else if (clip.GetDataPresent(DataFormats.UnicodeText)) {
2149 format = DataFormats.GetFormat(DataFormats.UnicodeText);
2150 } else if (clip.GetDataPresent(DataFormats.Text)) {
2151 format = DataFormats.GetFormat(DataFormats.Text);
2156 if ((format.Name == DataFormats.Rtf) && !(this is RichTextBox)) {
2160 if (!clip.GetDataPresent(format.Name)) {
2165 if (format.Name == DataFormats.Rtf) {
2166 document.undo.BeginUserAction (Locale.GetText ("Paste"));
2167 ((RichTextBox)this).SelectedRtf = (string)clip.GetData(DataFormats.Rtf);
2168 document.undo.EndUserAction ();
2170 } else if (format.Name == DataFormats.Bitmap) {
2171 document.undo.BeginUserAction (Locale.GetText ("Paste"));
2172 // document.InsertImage (document.caret.line, document.caret.pos, (Image) clip.GetData (DataFormats.Bitmap));
2173 document.MoveCaret (CaretDirection.CharForward);
2174 document.undo.EndUserAction ();
2176 } else if (format.Name == DataFormats.UnicodeText) {
2177 s = (string)clip.GetData(DataFormats.UnicodeText);
2178 } else if (format.Name == DataFormats.Text) {
2179 s = (string)clip.GetData(DataFormats.Text);
2185 document.undo.BeginUserAction (Locale.GetText ("Paste"));
2186 this.SelectedText = s;
2187 document.undo.EndUserAction ();
2189 if ((s.Length + document.Length) < max_length) {
2190 document.undo.BeginUserAction (Locale.GetText ("Paste"));
2191 this.SelectedText = s;
2192 document.undo.EndUserAction ();
2193 } else if (document.Length < max_length) {
2194 document.undo.BeginUserAction (Locale.GetText ("Paste"));
2195 this.SelectedText = s.Substring (0, max_length - document.Length);
2196 document.undo.EndUserAction ();
2203 internal abstract Color ChangeBackColor (Color backColor);
2205 internal override bool IsInputCharInternal (char charCode)
2209 #endregion // Private Methods
2212 // This is called just before OnTextChanged is called.
2213 internal virtual void OnTextUpdate ()
2217 protected override void OnTextChanged (EventArgs e)
2219 base.OnTextChanged (e);
2222 public virtual int GetLineFromCharIndex (int index)
2228 document.CharIndexToLineTag (index, out line_out, out tag_out, out pos);
2230 return line_out.LineNo;
2233 protected override void OnMouseUp (MouseEventArgs e)