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:
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
{
40 [DefaultEvent("TextChanged")]
41 [Designer("System.Windows.Forms.Design.TextBoxBaseDesigner, " + Consts
.AssemblySystem_Design
)]
42 public abstract class TextBoxBase
: Control
{
43 #region Local Variables
44 internal HorizontalAlignment alignment
;
45 internal bool accepts_tab
;
46 internal bool accepts_return
;
47 internal bool auto_size
;
48 internal bool backcolor_set
;
49 internal CharacterCasing character_casing
;
51 internal bool hide_selection
;
52 internal int max_length
;
53 internal bool modified
;
54 internal bool multiline
;
55 internal char password_char
;
56 internal bool read_only
;
57 internal bool word_wrap
;
58 internal Document document
;
59 internal LineTag caret_tag
; // tag our cursor is in
60 internal int caret_pos
; // position on the line our cursor is in (can be 0 = beginning of line)
61 internal ImplicitHScrollBar hscroll
;
62 internal ImplicitVScrollBar vscroll
;
63 internal RichTextBoxScrollBars scrollbars
;
64 internal Timer scroll_timer
;
65 internal bool richtext
;
66 internal bool show_selection
; // set to true to always show selection, even if no focus is set
67 internal int selection_length
= -1; // set to the user-specified selection length, or -1 if none
68 internal int requested_height
;
69 internal int canvas_width
;
70 internal int canvas_height
;
71 static internal int track_width
= 2; //
72 static internal int track_border
= 5; //
73 internal DateTime click_last
;
74 internal CaretSelection click_mode
;
77 internal static bool draw_lines
= false;
80 #endregion // Local Variables
82 #region Internal Constructor
83 // Constructor will go when complete, only for testing - pdb
84 internal TextBoxBase() {
85 alignment
= HorizontalAlignment
.Left
;
86 accepts_return
= false;
89 border_style
= BorderStyle
.Fixed3D
;
90 character_casing
= CharacterCasing
.Normal
;
92 hide_selection
= true;
100 show_selection
= false;
101 document
= new Document(this);
102 document
.WidthChanged
+= new EventHandler(document_WidthChanged
);
103 document
.HeightChanged
+= new EventHandler(document_HeightChanged
);
104 //document.CaretMoved += new EventHandler(CaretMoved);
105 document
.Wrap
= false;
106 requested_height
= -1;
107 click_last
= DateTime
.Now
;
108 click_mode
= CaretSelection
.Position
;
109 bmp
= new Bitmap(1, 1, System
.Drawing
.Imaging
.PixelFormat
.Format32bppArgb
);
111 MouseDown
+= new MouseEventHandler(TextBoxBase_MouseDown
);
112 MouseUp
+= new MouseEventHandler(TextBoxBase_MouseUp
);
113 MouseMove
+= new MouseEventHandler(TextBoxBase_MouseMove
);
114 SizeChanged
+= new EventHandler(TextBoxBase_SizeChanged
);
115 FontChanged
+= new EventHandler(TextBoxBase_FontOrColorChanged
);
116 ForeColorChanged
+= new EventHandler(TextBoxBase_FontOrColorChanged
);
117 MouseWheel
+= new MouseEventHandler(TextBoxBase_MouseWheel
);
119 scrollbars
= RichTextBoxScrollBars
.None
;
121 hscroll
= new ImplicitHScrollBar();
122 hscroll
.ValueChanged
+= new EventHandler(hscroll_ValueChanged
);
123 hscroll
.control_style
&= ~ControlStyles
.Selectable
;
124 hscroll
.Enabled
= false;
125 hscroll
.Visible
= false;
126 hscroll
.Maximum
= Int32
.MaxValue
;
128 vscroll
= new ImplicitVScrollBar();
129 vscroll
.ValueChanged
+= new EventHandler(vscroll_ValueChanged
);
130 vscroll
.control_style
&= ~ControlStyles
.Selectable
;
131 vscroll
.Enabled
= false;
132 vscroll
.Visible
= false;
133 vscroll
.Maximum
= Int32
.MaxValue
;
136 this.Controls
.AddImplicit (hscroll
);
137 this.Controls
.AddImplicit (vscroll
);
140 SetStyle(ControlStyles
.UserPaint
| ControlStyles
.StandardClick
, false);
142 SetStyle(ControlStyles
.UseTextForAccessibility
, false);
145 canvas_width
= ClientSize
.Width
;
146 canvas_height
= ClientSize
.Height
;
147 document
.ViewPortWidth
= canvas_width
;
148 document
.ViewPortHeight
= canvas_height
;
150 Cursor
= Cursors
.IBeam
;
152 CalculateScrollBars();
154 #endregion // Internal Constructor
156 #region Private and Internal Methods
157 internal string CaseAdjust(string s
) {
158 if (character_casing
== CharacterCasing
.Normal
) {
161 if (character_casing
== CharacterCasing
.Lower
) {
168 internal override void HandleClick(int clicks
, MouseEventArgs me
) {
169 // MS seems to fire the click event in spite of the styles they set
170 control_style
|= ControlStyles
.StandardClick
| ControlStyles
.StandardDoubleClick
;
171 base.HandleClick (clicks
, me
);
172 control_style ^
= ControlStyles
.StandardClick
| ControlStyles
.StandardDoubleClick
;
175 #endregion // Private and Internal Methods
177 #region Public Instance Properties
178 [DefaultValue(false)]
179 [MWFCategory("Behavior")]
180 public bool AcceptsTab
{
186 if (value != accepts_tab
) {
188 OnAcceptsTabChanged(EventArgs
.Empty
);
195 [RefreshProperties(RefreshProperties
.Repaint
)]
196 [MWFCategory("Behavior")]
197 public virtual bool AutoSize
{
203 if (value != auto_size
) {
206 if (PreferredHeight
!= ClientSize
.Height
) {
207 ClientSize
= new Size(ClientSize
.Width
, PreferredHeight
);
210 OnAutoSizeChanged(EventArgs
.Empty
);
216 public override System
.Drawing
.Color BackColor
{
218 return base.BackColor
;
221 if (value != ThemeEngine
.Current
.ColorWindow
) {
222 backcolor_set
= true;
224 backcolor_set
= false;
226 base.BackColor
= value;
231 [EditorBrowsable(EditorBrowsableState
.Never
)]
232 public override System
.Drawing
.Image BackgroundImage
{
234 return base.BackgroundImage
;
237 base.BackgroundImage
= value;
241 [DefaultValue(BorderStyle
.Fixed3D
)]
243 [MWFCategory("Appearance")]
244 public BorderStyle BorderStyle
{
245 get { return InternalBorderStyle; }
247 InternalBorderStyle
= value;
248 OnBorderStyleChanged(EventArgs
.Empty
);
253 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
254 public bool CanUndo
{
256 return document
.undo
.UndoLevels
!= 0;
261 public override System
.Drawing
.Color ForeColor
{
263 return base.ForeColor
;
266 base.ForeColor
= value;
271 [MWFCategory("Behavior")]
272 public bool HideSelection
{
274 return hide_selection
;
278 if (value != hide_selection
) {
279 hide_selection
= value;
280 OnHideSelectionChanged(EventArgs
.Empty
);
282 if (hide_selection
) {
283 document
.selection_visible
= false;
285 document
.selection_visible
= true;
287 document
.InvalidateSelectionArea();
292 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
293 [Editor("System.Windows.Forms.Design.StringArrayEditor, " + Consts
.AssemblySystem_Design
, typeof(System
.Drawing
.Design
.UITypeEditor
))]
295 [MWFCategory("Appearance")]
296 public string[] Lines
{
301 count
= document
.Lines
;
303 // Handle empty document
304 if ((count
== 1) && (document
.GetLine (1).text
.Length
== 0)) {
305 return new string [0];
308 lines
= new ArrayList ();
313 StringBuilder lt
= new StringBuilder ();
316 line
= document
.GetLine (i
++);
317 lt
.Append (line
.text
.ToString ());
318 } while (line
.soft_break
&& i
< count
);
320 lines
.Add (lt
.ToString ());
323 return (string []) lines
.ToArray (typeof (string));
334 brush
= ThemeEngine
.Current
.ResPool
.GetSolidBrush(this.ForeColor
);
336 document
.NoRecalc
= true;
337 for (i
= 0; i
< l
; i
++) {
339 // Don't add the last line if it is just an empty line feed
340 // the line feed is reflected in the previous line's soft_break = false
341 if (i
== l
- 1 && value [i
].Length
== 0)
344 bool carriage_return
= false;
345 if (value [i
].EndsWith ("\r")) {
346 value [i
] = value [i
].Substring (0, value [i
].Length
- 1);
347 carriage_return
= true;
350 document
.Add(i
+1, CaseAdjust(value[i
]), alignment
, Font
, brush
);
351 if (carriage_return
) {
352 Line line
= document
.GetLine (i
+ 1);
353 line
.carriage_return
= true;
357 document
.NoRecalc
= false;
359 // CalculateDocument();
360 OnTextChanged(EventArgs
.Empty
);
364 [DefaultValue(32767)]
366 [MWFCategory("Behavior")]
367 public virtual int MaxLength
{
369 if (max_length
== 2147483646) { // We don't distinguish between single and multi-line limits
376 if (value != max_length
) {
383 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
384 public bool Modified
{
390 if (value != modified
) {
392 OnModifiedChanged(EventArgs
.Empty
);
397 [DefaultValue(false)]
399 [RefreshProperties(RefreshProperties
.All
)]
400 [MWFCategory("Behavior")]
401 public virtual bool Multiline
{
407 if (value != multiline
) {
409 // Make sure we update our size; the user may have already set the size before going to multiline
410 if (multiline
&& requested_height
!= -1) {
411 Height
= requested_height
;
412 requested_height
= -1;
416 parent
.PerformLayout ();
418 OnMultilineChanged(EventArgs
.Empty
);
421 document
.multiline
= multiline
;
424 document
.Wrap
= word_wrap
;
425 document
.PasswordChar
= "";
428 document
.Wrap
= false;
429 if (this.password_char
!= '\0') {
430 document
.PasswordChar
= password_char
.ToString();
432 document
.PasswordChar
= "";
436 CalculateDocument ();
441 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
442 [EditorBrowsable(EditorBrowsableState
.Advanced
)]
443 public int PreferredHeight
{
445 return this.Font
.Height
+ 7; // FIXME - consider border style as well
449 [DefaultValue(false)]
450 [MWFCategory("Behavior")]
451 public bool ReadOnly
{
457 if (value != read_only
) {
459 OnReadOnlyChanged(EventArgs
.Empty
);
465 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
466 public virtual string SelectedText
{
468 return document
.GetSelection();
472 document
.ReplaceSelection(CaseAdjust(value), false);
475 OnTextChanged(EventArgs
.Empty
);
480 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
481 public virtual int SelectionLength
{
483 int res
= document
.SelectionLength ();
491 throw new ArgumentException(String
.Format("{0} is not a valid value", value), "value");
500 selection_length
= value;
502 start
= document
.LineTagToCharIndex(document
.selection_start
.line
, document
.selection_start
.pos
);
504 document
.CharIndexToLineTag(start
+ value, out line
, out tag
, out pos
);
505 document
.SetSelectionEnd(line
, pos
);
506 document
.PositionCaret(line
, pos
);
508 selection_length
= -1;
510 document
.SetSelectionEnd(document
.selection_start
.line
, document
.selection_start
.pos
);
511 document
.PositionCaret(document
.selection_start
.line
, document
.selection_start
.pos
);
517 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
518 public int SelectionStart
{
522 index
= document
.LineTagToCharIndex(document
.selection_start
.line
, document
.selection_start
.pos
);
528 document
.SetSelectionStart(value);
529 if (selection_length
> -1 ) {
530 document
.SetSelectionEnd(value + selection_length
);
532 document
.SetSelectionEnd(value);
534 document
.PositionCaret(document
.selection_start
.line
, document
.selection_start
.pos
);
540 public override string Text
{
542 if (document
== null || document
.Root
== null || document
.Root
.text
== null) {
547 return document
.Root
.text
.ToString();
552 sb
= new StringBuilder();
555 for (i
= 1; i
< document
.Lines
; i
++) {
556 if (line
!= null && !line
.soft_break
)
557 sb
.Append (Environment
.NewLine
);
558 line
= document
.GetLine (i
);
559 sb
.Append(line
.text
.ToString());
560 if (line
.carriage_return
)
563 sb
.Append(document
.GetLine(document
.Lines
).text
.ToString());
564 return sb
.ToString();
572 if ((value != null) && (value != "")) {
578 lines
= value.Split(new char[] {'\n'}
);
582 document
.PositionCaret (document
.GetLine (1), 0);
583 document
.SetSelectionToCaret (true);
588 document
.Add(1, CaseAdjust(value), alignment
, Font
, ThemeEngine
.Current
.ResPool
.GetSolidBrush(ForeColor
));
591 document
.PositionCaret (document
.GetLine (1), 0);
592 document
.SetSelectionToCaret (true);
601 OnTextChanged(EventArgs
.Empty
);
606 public virtual int TextLength
{
608 if (document
== null || document
.Root
== null || document
.Root
.text
== null) {
613 return document
.Root
.text
.Length
;
619 for (i
= 1; i
< document
.Lines
; i
++) {
620 total
+= document
.GetLine(i
).text
.Length
+ Environment
.NewLine
.Length
;
622 total
+= document
.GetLine(i
).text
.Length
;
631 [MWFCategory("Behavior")]
632 public bool WordWrap
{
638 if (value != word_wrap
) {
641 document
.Wrap
= value;
646 #endregion // Public Instance Properties
648 #region Protected Instance Properties
649 protected override CreateParams CreateParams
{
651 return base.CreateParams
;
655 protected override System
.Drawing
.Size DefaultSize
{
657 return new Size(100, 20);
660 #endregion // Protected Instance Properties
662 #region Public Instance Methods
663 public void AppendText(string text
) {
666 document
.MoveCaret(CaretDirection
.CtrlEnd
);
667 document
.Insert (document
.caret
.line
, document
.caret
.tag
, document
.caret
.pos
, false, text
);
670 document
.MoveCaret(CaretDirection
.CtrlEnd
);
671 document
.InsertStringAtCaret(text
, true);
676 document
.MoveCaret(CaretDirection
.CtrlEnd
);
677 document
.SetSelectionToCaret (true);
679 OnTextChanged(EventArgs
.Empty
);
682 public void Clear() {
686 public void ClearUndo() {
687 document
.undo
.Clear();
693 o
= new DataObject(DataFormats
.Text
, SelectedText
);
694 if (this is RichTextBox
) {
695 o
.SetData(DataFormats
.Rtf
, ((RichTextBox
)this).SelectedRtf
);
697 Clipboard
.SetDataObject(o
);
703 o
= new DataObject(DataFormats
.Text
, SelectedText
);
704 if (this is RichTextBox
) {
705 o
.SetData(DataFormats
.Rtf
, ((RichTextBox
)this).SelectedRtf
);
707 Clipboard
.SetDataObject(o
);
708 document
.ReplaceSelection("", false);
711 public void Paste() {
712 Paste(Clipboard
.GetDataObject(), null, false);
715 public void ScrollToCaret() {
716 if (IsHandleCreated
) {
717 CaretMoved(this, EventArgs
.Empty
);
721 public void Select(int start
, int length
) {
722 SelectionStart
= start
;
723 SelectionLength
= length
;
727 public void SelectAll() {
730 last
= document
.GetLine(document
.Lines
);
731 document
.SetSelectionStart(document
.GetLine(1), 0);
732 document
.SetSelectionEnd(last
, last
.text
.Length
);
733 selection_length
= -1;
736 public override string ToString() {
737 return String
.Concat (base.ToString (), ", Text: ", Text
);
741 document
.undo
.Undo();
743 #endregion // Public Instance Methods
745 #region Protected Instance Methods
746 protected override void CreateHandle() {
747 base.CreateHandle ();
748 document
.AlignCaret();
752 protected override bool IsInputKey(Keys keyData
) {
753 if ((keyData
& Keys
.Alt
) != 0) {
754 return base.IsInputKey(keyData
);
757 switch (keyData
& Keys
.KeyCode
) {
759 if (multiline
&& accepts_return
) {
766 if (accepts_tab
&& multiline
) {
767 if ((keyData
& Keys
.Control
) == 0) {
789 protected virtual void OnAcceptsTabChanged(EventArgs e
) {
790 EventHandler eh
= (EventHandler
)(Events
[AcceptsTabChangedEvent
]);
795 protected virtual void OnAutoSizeChanged(EventArgs e
) {
796 EventHandler eh
= (EventHandler
)(Events
[AutoSizeChangedEvent
]);
801 protected virtual void OnBorderStyleChanged(EventArgs e
) {
802 EventHandler eh
= (EventHandler
)(Events
[BorderStyleChangedEvent
]);
807 protected override void OnFontChanged(EventArgs e
) {
808 base.OnFontChanged (e
);
810 if (auto_size
&& !multiline
) {
811 if (PreferredHeight
!= ClientSize
.Height
) {
812 Height
= PreferredHeight
;
817 protected override void OnHandleCreated(EventArgs e
) {
818 base.OnHandleCreated (e
);
821 protected override void OnHandleDestroyed(EventArgs e
) {
822 base.OnHandleDestroyed (e
);
825 protected virtual void OnHideSelectionChanged(EventArgs e
) {
826 EventHandler eh
= (EventHandler
)(Events
[HideSelectionChangedEvent
]);
831 protected virtual void OnModifiedChanged(EventArgs e
) {
832 EventHandler eh
= (EventHandler
)(Events
[ModifiedChangedEvent
]);
837 protected virtual void OnMultilineChanged(EventArgs e
) {
838 EventHandler eh
= (EventHandler
)(Events
[MultilineChangedEvent
]);
843 protected virtual void OnReadOnlyChanged(EventArgs e
) {
844 EventHandler eh
= (EventHandler
)(Events
[ReadOnlyChangedEvent
]);
849 protected override bool ProcessDialogKey(Keys keyData
) {
850 return base.ProcessDialogKey(keyData
);
853 private bool ProcessKey(Keys keyData
) {
857 control
= (Control
.ModifierKeys
& Keys
.Control
) != 0;
858 shift
= (Control
.ModifierKeys
& Keys
.Shift
) != 0;
860 switch (keyData
& Keys
.KeyCode
) {
861 case Keys
.X
: { // Cut (Ctrl-X)
869 case Keys
.C
: { // Copy (Ctrl-C)
877 case Keys
.V
: { // Paste (Ctrl-V)
879 return Paste(Clipboard
.GetDataObject(), null, true);
884 case Keys
.Z
: { // Undo (Ctrl-Z)
892 case Keys
.A
: { // Select All (Ctrl-A)
902 document
.MoveCaret(CaretDirection
.WordBack
);
904 if (!document
.selection_visible
|| shift
) {
905 document
.MoveCaret(CaretDirection
.CharBack
);
907 document
.MoveCaret(CaretDirection
.SelectionStart
);
912 document
.SetSelectionToCaret(true);
914 document
.SetSelectionToCaret(false);
917 CaretMoved(this, null);
923 document
.MoveCaret(CaretDirection
.WordForward
);
925 if (!document
.selection_visible
|| shift
) {
926 document
.MoveCaret(CaretDirection
.CharForward
);
928 document
.MoveCaret(CaretDirection
.SelectionEnd
);
932 document
.SetSelectionToCaret(true);
934 document
.SetSelectionToCaret(false);
937 CaretMoved(this, null);
943 if (document
.CaretPosition
== 0) {
944 document
.MoveCaret(CaretDirection
.LineUp
);
946 document
.MoveCaret(CaretDirection
.Home
);
949 document
.MoveCaret(CaretDirection
.LineUp
);
952 if ((Control
.ModifierKeys
& Keys
.Shift
) == 0) {
953 document
.SetSelectionToCaret(true);
955 document
.SetSelectionToCaret(false);
958 CaretMoved(this, null);
964 if (document
.CaretPosition
== document
.CaretLine
.Text
.Length
) {
965 document
.MoveCaret(CaretDirection
.LineDown
);
967 document
.MoveCaret(CaretDirection
.End
);
970 document
.MoveCaret(CaretDirection
.LineDown
);
973 if ((Control
.ModifierKeys
& Keys
.Shift
) == 0) {
974 document
.SetSelectionToCaret(true);
976 document
.SetSelectionToCaret(false);
979 CaretMoved(this, null);
984 if ((Control
.ModifierKeys
& Keys
.Control
) != 0) {
985 document
.MoveCaret(CaretDirection
.CtrlHome
);
987 document
.MoveCaret(CaretDirection
.Home
);
990 if ((Control
.ModifierKeys
& Keys
.Shift
) == 0) {
991 document
.SetSelectionToCaret(true);
993 document
.SetSelectionToCaret(false);
996 CaretMoved(this, null);
1001 if ((Control
.ModifierKeys
& Keys
.Control
) != 0) {
1002 document
.MoveCaret(CaretDirection
.CtrlEnd
);
1004 document
.MoveCaret(CaretDirection
.End
);
1007 if ((Control
.ModifierKeys
& Keys
.Shift
) == 0) {
1008 document
.SetSelectionToCaret(true);
1010 document
.SetSelectionToCaret(false);
1013 CaretMoved(this, null);
1018 // ignoring accepts_return, fixes bug #76355
1019 if (!read_only
&& multiline
&& (accepts_return
|| (FindForm() != null && FindForm().AcceptButton
== null) || ((Control
.ModifierKeys
& Keys
.Control
) != 0))) {
1022 if (document
.selection_visible
) {
1023 document
.ReplaceSelection("", false);
1026 line
= document
.CaretLine
;
1028 document
.Split(document
.CaretLine
, document
.CaretTag
, document
.CaretPosition
, false);
1029 OnTextChanged(EventArgs
.Empty
);
1030 document
.UpdateView(line
, 2, 0);
1031 document
.MoveCaret(CaretDirection
.CharForward
);
1032 document
.SetSelectionToCaret(true);
1033 CaretMoved(this, null);
1040 if (!read_only
&& accepts_tab
&& multiline
) {
1041 document
.InsertChar(document
.CaretLine
, document
.CaretPosition
, '\t');
1042 if (document
.selection_visible
) {
1043 document
.ReplaceSelection("", false);
1045 document
.SetSelectionToCaret(true);
1047 OnTextChanged(EventArgs
.Empty
);
1048 CaretMoved(this, null);
1056 Paste(Clipboard
.GetDataObject(), null, true);
1065 // FIXME - need overwrite/insert toggle?
1070 if ((Control
.ModifierKeys
& Keys
.Control
) != 0) {
1071 document
.MoveCaret(CaretDirection
.CtrlPgUp
);
1073 document
.MoveCaret(CaretDirection
.PgUp
);
1078 case Keys
.PageDown
: {
1079 if ((Control
.ModifierKeys
& Keys
.Control
) != 0) {
1080 document
.MoveCaret(CaretDirection
.CtrlPgDn
);
1082 document
.MoveCaret(CaretDirection
.PgDn
);
1097 if (document
.selection_visible
) {
1098 document
.ReplaceSelection("", false);
1100 // DeleteChar only deletes on the line, doesn't do the combine
1101 if (document
.CaretPosition
== document
.CaretLine
.Text
.Length
) {
1102 if (document
.CaretLine
.LineNo
< document
.Lines
) {
1105 line
= document
.GetLine(document
.CaretLine
.LineNo
+ 1);
1106 document
.Combine(document
.CaretLine
, line
);
1107 document
.UpdateView(document
.CaretLine
, 2, 0);
1113 check_first
= document
.GetLine(document
.CaretLine
.LineNo
);
1114 check_second
= document
.GetLine(check_first
.line_no
+ 1);
1116 Console
.WriteLine("Post-UpdateView: Y of first line: {0}, second line: {1}", check_first
.Y
, check_second
.Y
);
1119 // Caret doesn't move
1123 document
.DeleteChar(document
.CaretTag
, document
.CaretPosition
, true);
1127 end_pos
= document
.CaretPosition
;
1129 while ((end_pos
< document
.CaretLine
.Text
.Length
) && !Document
.IsWordSeparator(document
.CaretLine
.Text
[end_pos
])) {
1133 if (end_pos
< document
.CaretLine
.Text
.Length
) {
1136 document
.DeleteChars(document
.CaretTag
, document
.CaretPosition
, end_pos
- document
.CaretPosition
);
1141 OnTextChanged(EventArgs
.Empty
);
1142 document
.AlignCaret();
1143 document
.UpdateCaret();
1144 CaretMoved(this, null);
1151 private void HandleBackspace(bool control
) {
1154 fire_changed
= false;
1156 // delete only deletes on the line, doesn't do the combine
1157 if (document
.selection_visible
) {
1158 document
.ReplaceSelection("", false);
1159 fire_changed
= true;
1161 document
.SetSelectionToCaret(true);
1163 if (document
.CaretPosition
== 0) {
1164 if (document
.CaretLine
.LineNo
> 1) {
1168 line
= document
.GetLine(document
.CaretLine
.LineNo
- 1);
1169 new_caret_pos
= line
.text
.Length
;
1171 document
.Combine(line
, document
.CaretLine
);
1172 document
.UpdateView(line
, 1, 0);
1173 document
.PositionCaret(line
, new_caret_pos
);
1174 //document.MoveCaret(CaretDirection.CharForward);
1175 document
.UpdateCaret();
1176 fire_changed
= true;
1179 if (!control
|| document
.CaretPosition
== 0) {
1180 document
.DeleteChar(document
.CaretTag
, document
.CaretPosition
, false);
1181 document
.MoveCaret(CaretDirection
.CharBack
);
1185 start_pos
= document
.CaretPosition
- 1;
1187 while ((start_pos
> 0) && !Document
.IsWordSeparator(document
.CaretLine
.Text
[start_pos
- 1])) {
1190 document
.DeleteChars(document
.CaretTag
, start_pos
, document
.CaretPosition
- start_pos
);
1191 document
.PositionCaret(document
.CaretLine
, start_pos
);
1193 document
.UpdateCaret();
1194 fire_changed
= true;
1197 OnTextChanged(EventArgs
.Empty
);
1199 CaretMoved(this, null);
1202 protected override void SetBoundsCore(int x
, int y
, int width
, int height
, BoundsSpecified specified
) {
1203 // Make sure we don't get sized bigger than we want to be
1206 if (height
!= PreferredHeight
) {
1207 requested_height
= height
;
1208 height
= PreferredHeight
;
1209 specified
|= BoundsSpecified
.Height
;
1214 base.SetBoundsCore (x
, y
, width
, height
, specified
);
1217 protected override void WndProc(ref Message m
) {
1218 switch ((Msg
)m
.Msg
) {
1219 case Msg
.WM_KEYDOWN
: {
1220 if (ProcessKeyMessage(ref m
) || ProcessKey((Keys
)m
.WParam
.ToInt32() | XplatUI
.State
.ModifierKeys
)) {
1221 m
.Result
= IntPtr
.Zero
;
1231 if (ProcessKeyMessage(ref m
)) {
1232 m
.Result
= IntPtr
.Zero
;
1240 m
.Result
= IntPtr
.Zero
;
1242 ch
= m
.WParam
.ToInt32();
1245 HandleBackspace(true);
1246 } else if (ch
>= 32) {
1247 if (document
.selection_visible
) {
1248 document
.ReplaceSelection("", false);
1251 char c
= (char)m
.WParam
;
1252 switch (character_casing
) {
1253 case CharacterCasing
.Upper
:
1254 c
= Char
.ToUpper((char) m
.WParam
);
1256 case CharacterCasing
.Lower
:
1257 c
= Char
.ToLower((char) m
.WParam
);
1261 if (document
.Length
< max_length
) {
1262 document
.InsertCharAtCaret(c
, true);
1263 OnTextChanged(EventArgs
.Empty
);
1264 CaretMoved(this, null);
1266 XplatUI
.AudibleAlert();
1269 } else if (ch
== 8) {
1270 HandleBackspace(false);
1277 base.WndProc(ref m
);
1283 #endregion // Protected Instance Methods
1286 static object AcceptsTabChangedEvent
= new object ();
1287 static object AutoSizeChangedEvent
= new object ();
1288 static object BorderStyleChangedEvent
= new object ();
1289 static object HideSelectionChangedEvent
= new object ();
1290 static object ModifiedChangedEvent
= new object ();
1291 static object MultilineChangedEvent
= new object ();
1292 static object ReadOnlyChangedEvent
= new object ();
1293 static object HScrolledEvent
= new object ();
1294 static object VScrolledEvent
= new object ();
1296 public event EventHandler AcceptsTabChanged
{
1297 add { Events.AddHandler (AcceptsTabChangedEvent, value); }
1298 remove { Events.RemoveHandler (AcceptsTabChangedEvent, value); }
1301 public event EventHandler AutoSizeChanged
{
1302 add { Events.AddHandler (AutoSizeChangedEvent, value); }
1303 remove { Events.RemoveHandler (AutoSizeChangedEvent, value); }
1306 public event EventHandler BorderStyleChanged
{
1307 add { Events.AddHandler (BorderStyleChangedEvent, value); }
1308 remove { Events.RemoveHandler (BorderStyleChangedEvent, value); }
1311 public event EventHandler HideSelectionChanged
{
1312 add { Events.AddHandler (HideSelectionChangedEvent, value); }
1313 remove { Events.RemoveHandler (HideSelectionChangedEvent, value); }
1316 public event EventHandler ModifiedChanged
{
1317 add { Events.AddHandler (ModifiedChangedEvent, value); }
1318 remove { Events.RemoveHandler (ModifiedChangedEvent, value); }
1321 public event EventHandler MultilineChanged
{
1322 add { Events.AddHandler (MultilineChangedEvent, value); }
1323 remove { Events.RemoveHandler (MultilineChangedEvent, value); }
1326 public event EventHandler ReadOnlyChanged
{
1327 add { Events.AddHandler (ReadOnlyChangedEvent, value); }
1328 remove { Events.RemoveHandler (ReadOnlyChangedEvent, value); }
1331 internal event EventHandler HScrolled
{
1332 add { Events.AddHandler (HScrolledEvent, value); }
1333 remove { Events.RemoveHandler (HScrolledEvent, value); }
1336 internal event EventHandler VScrolled
{
1337 add { Events.AddHandler (VScrolledEvent, value); }
1338 remove { Events.RemoveHandler (VScrolledEvent, value); }
1342 [EditorBrowsable(EditorBrowsableState
.Never
)]
1343 public new event EventHandler BackgroundImageChanged
{
1344 add { base.BackgroundImageChanged += value; }
1345 remove { base.BackgroundImageChanged -= value; }
1348 [EditorBrowsable(EditorBrowsableState
.Advanced
)]
1349 public new event EventHandler Click
{
1350 add { base.Click += value; }
1351 remove { base.Click -= value; }
1354 // XXX should this not manipulate base.Paint?
1356 [EditorBrowsable(EditorBrowsableState
.Never
)]
1357 public new event PaintEventHandler Paint
;
1358 #endregion // Events
1360 #region Private Methods
1361 internal Document Document
{
1371 internal bool ShowSelection
{
1373 if (show_selection
) {
1381 if (show_selection
== value)
1384 show_selection
= value;
1385 // Currently InvalidateSelectionArea is commented out so do a full invalidate
1386 document
.InvalidateSelectionArea();
1390 internal Graphics
CreateGraphicsInternal() {
1391 if (IsHandleCreated
) {
1392 return base.CreateGraphics();
1395 return Graphics
.FromImage(bmp
);
1402 internal override void OnPaintInternal (PaintEventArgs pevent
) {
1404 if (backcolor_set
|| (Enabled
&& !read_only
)) {
1405 pevent
.Graphics
.FillRectangle(ThemeEngine
.Current
.ResPool
.GetSolidBrush(BackColor
), pevent
.ClipRectangle
);
1407 pevent
.Graphics
.FillRectangle(ThemeEngine
.Current
.ResPool
.GetSolidBrush(ThemeEngine
.Current
.ColorControl
), pevent
.ClipRectangle
);
1409 pevent
.Graphics
.TextRenderingHint
=TextRenderingHint
.AntiAlias
;
1411 // Draw the viewable document
1412 document
.Draw(pevent
.Graphics
, pevent
.ClipRectangle
);
1414 Rectangle rect
= ClientRectangle
;
1417 //pevent.Graphics.DrawRectangle(ThemeEngine.Current.ResPool.GetPen(ThemeEngine.Current.ColorControlDark), rect);
1426 p
= new Pen(Color
.Red
, 1);
1428 // First, figure out from what line to what line we need to draw
1429 start
= document
.GetLineByPixel(pevent
.ClipRectangle
.Top
- document
.ViewPortY
, false).line_no
;
1430 end
= document
.GetLineByPixel(pevent
.ClipRectangle
.Bottom
- document
.ViewPortY
, false).line_no
;
1432 //Console.WriteLine("Starting drawing on line '{0}'", document.GetLine(start));
1433 //Console.WriteLine("Ending drawing on line '{0}'", document.GetLine(end));
1436 while (line_no
<= end
) {
1437 line
= document
.GetLine(line_no
);
1440 for (int i
= 0; i
< line
.text
.Length
; i
++) {
1441 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
);
1450 internal override void OnGotFocusInternal (EventArgs e
)
1452 document
.CaretHasFocus ();
1453 base.OnGotFocusInternal (e
);
1456 internal override void OnLostFocusInternal (EventArgs e
)
1458 document
.CaretLostFocus ();
1459 base.OnLostFocusInternal (e
);
1462 private void TextBoxBase_MouseDown(object sender
, MouseEventArgs e
) {
1463 if (e
.Button
== MouseButtons
.Left
) {
1466 interval
= DateTime
.Now
- click_last
;
1467 document
.PositionCaret(e
.X
+ document
.ViewPortX
, e
.Y
+ document
.ViewPortY
);
1469 // Handle place caret/select word/select line behaviour
1470 if (e
.Clicks
== 1) {
1471 if (SystemInformation
.DoubleClickTime
< interval
.TotalMilliseconds
) {
1473 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
));
1475 document
.SetSelectionToCaret(true);
1476 click_mode
= CaretSelection
.Position
;
1477 } else if (this is RichTextBox
) {
1479 Console
.WriteLine("Tripple Click Selecting line");
1481 document
.ExpandSelection(CaretSelection
.Line
, false);
1482 click_mode
= CaretSelection
.Line
;
1484 document
.SetSelectionToCaret(true);
1487 // We select the line if the word is already selected, and vice versa
1488 if (click_mode
!= CaretSelection
.Word
) {
1489 if (click_mode
== CaretSelection
.Line
) {
1490 document
.Invalidate(document
.selection_start
.line
, 0, document
.selection_start
.line
, document
.selection_start
.line
.text
.Length
);
1492 click_mode
= CaretSelection
.Word
;
1495 } else if (this is RichTextBox
) {
1496 click_mode
= CaretSelection
.Line
;
1497 document
.ExpandSelection(CaretSelection
.Line
, false); // Setting initial selection
1502 click_last
= DateTime
.Now
;
1506 if ((e
.Button
== MouseButtons
.Middle
) && (((int)Environment
.OSVersion
.Platform
== 4) || ((int)Environment
.OSVersion
.Platform
== 128))) {
1507 Document
.Marker marker
;
1509 marker
.tag
= document
.FindCursor(e
.X
+ document
.ViewPortX
, e
.Y
+ document
.ViewPortY
, out marker
.pos
);
1510 marker
.line
= marker
.tag
.line
;
1511 marker
.height
= marker
.tag
.height
;
1513 document
.SetSelection(marker
.line
, marker
.pos
, marker
.line
, marker
.pos
);
1514 Paste (Clipboard
.GetDataObject (true), null, true);
1523 if (e
.Button
== MouseButtons
.Right
) {
1524 draw_lines
= !draw_lines
;
1526 Console
.WriteLine("SelectedText: {0}, length {1}", this.SelectedText
, this.SelectionLength
);
1527 Console
.WriteLine("Selection start: {0}", this.SelectionStart
);
1529 this.SelectionStart
= 10;
1530 this.SelectionLength
= 5;
1535 tag
= document
.FindTag(e
.X
+ document
.ViewPortX
, e
.Y
+ document
.ViewPortY
, out pos
, false);
1537 Console
.WriteLine("Click found tag {0}, character {1}", tag
, pos
);
1540 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;
1541 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;
1542 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;
1543 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;
1544 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;
1545 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;
1552 // Update/Recalculate what we see
1553 document
.UpdateView(line
, 0);
1555 // Make sure our caret is properly positioned and sized
1556 document
.AlignCaret();
1560 private void TextBoxBase_MouseUp(object sender
, MouseEventArgs e
) {
1561 if (e
.Button
== MouseButtons
.Left
) {
1562 if (click_mode
== CaretSelection
.Position
) {
1563 document
.SetSelectionToCaret(false);
1564 document
.DisplayCaret();
1567 if (scroll_timer
!= null) {
1568 scroll_timer
.Enabled
= false;
1574 private void PositionControls ()
1576 if (hscroll
.Visible
) {
1577 //vscroll.Maximum += hscroll.Height;
1578 canvas_height
= ClientSize
.Height
- hscroll
.Height
;
1580 canvas_height
= ClientSize
.Height
;
1583 if (vscroll
.Visible
) {
1584 //hscroll.Maximum += vscroll.Width;
1585 canvas_width
= ClientSize
.Width
- vscroll
.Width
;
1587 canvas_width
= ClientSize
.Width
;
1591 document
.ViewPortWidth
= canvas_width
;
1592 document
.ViewPortHeight
= canvas_height
;
1594 // We always move them, they just might not be displayed
1595 hscroll
.Bounds
= new Rectangle (ClientRectangle
.Left
, ClientRectangle
.Height
- hscroll
.Height
, ClientSize
.Width
- (vscroll
.Visible
? vscroll
.Width
: 0), hscroll
.Height
);
1596 vscroll
.Bounds
= new Rectangle (ClientRectangle
.Right
- vscroll
.Width
, ClientRectangle
.Top
, vscroll
.Width
, ClientSize
.Height
- (hscroll
.Visible
? hscroll
.Height
: 0));
1600 private void TextBoxBase_SizeChanged(object sender
, EventArgs e
) {
1601 CalculateDocument();
1604 private void TextBoxBase_MouseWheel(object sender
, MouseEventArgs e
) {
1608 if (!vscroll
.Enabled
) {
1613 vscroll
.Value
= Math
.Min (vscroll
.Value
+ SystemInformation
.MouseWheelScrollLines
, vscroll
.Maximum
- document
.ViewPortHeight
+ 1);
1615 vscroll
.Value
= Math
.Max (0, vscroll
.Value
- SystemInformation
.MouseWheelScrollLines
);
1618 internal virtual void SelectWord ()
1620 StringBuilder s
= document
.caret
.line
.text
;
1621 int start
= document
.caret
.pos
;
1622 int end
= document
.caret
.pos
;
1625 if (document
.caret
.line
.line_no
>= document
.Lines
)
1627 Line line
= document
.GetLine (document
.caret
.line
.line_no
+ 1);
1628 document
.PositionCaret (line
, 0);
1637 // skip whitespace until we hit a word
1638 while (start
> 0 && s
[start
] == ' ')
1641 while (start
> 0 && (s
[start
] != ' '))
1643 if (s
[start
] == ' ')
1647 if (s
[end
] == ' ') {
1648 while (end
< s
.Length
&& s
[end
] == ' ')
1651 while (end
< s
.Length
&& s
[end
] != ' ')
1653 while (end
< s
.Length
&& s
[end
] == ' ')
1657 document
.SetSelection (document
.caret
.line
, start
, document
.caret
.line
, end
);
1660 internal void CalculateDocument() {
1661 if (!IsHandleCreated
) {
1664 document
.RecalculateDocument(CreateGraphicsInternal());
1665 CalculateScrollBars();
1669 internal void CalculateScrollBars () {
1670 // FIXME - need separate calculations for center and right alignment
1673 PositionControls ();
1677 if (document
.Width
>= document
.ViewPortWidth
) {
1678 hscroll
.SetValues (0, Math
.Max (1, document
.Width
), -1,
1679 document
.ViewPortWidth
< 0 ? 0 : document
.ViewPortWidth
);
1680 hscroll
.Enabled
= true;
1682 hscroll
.Enabled
= false;
1683 hscroll
.Maximum
= document
.ViewPortWidth
;
1686 if (document
.Height
>= document
.ViewPortHeight
) {
1687 vscroll
.SetValues (0, Math
.Max (1, document
.Height
), -1,
1688 document
.ViewPortHeight
< 0 ? 0 : document
.ViewPortHeight
);
1689 vscroll
.Enabled
= true;
1691 vscroll
.Enabled
= false;
1692 vscroll
.Maximum
= document
.ViewPortHeight
;
1697 if ((scrollbars
& RichTextBoxScrollBars
.Horizontal
) != 0) {
1698 if (((scrollbars
& RichTextBoxScrollBars
.ForcedHorizontal
) != 0) || hscroll
.Enabled
) {
1699 hscroll
.Visible
= true;
1701 hscroll
.Visible
= false;
1704 hscroll
.Visible
= false;
1708 if ((scrollbars
& RichTextBoxScrollBars
.Vertical
) != 0) {
1709 if (((scrollbars
& RichTextBoxScrollBars
.ForcedVertical
) != 0) || vscroll
.Enabled
) {
1710 vscroll
.Visible
= true;
1712 vscroll
.Visible
= false;
1715 vscroll
.Visible
= false;
1718 PositionControls ();
1721 private void document_WidthChanged(object sender
, EventArgs e
) {
1722 CalculateScrollBars();
1725 private void document_HeightChanged(object sender
, EventArgs e
) {
1726 CalculateScrollBars();
1729 private void hscroll_ValueChanged(object sender
, EventArgs e
) {
1732 old_viewport_x
= document
.ViewPortX
;
1733 document
.ViewPortX
= this.hscroll
.Value
;
1735 if (vscroll
.Visible
) {
1736 XplatUI
.ScrollWindow(this.Handle
, new Rectangle(0, 0, ClientSize
.Width
- vscroll
.Width
, ClientSize
.Height
), old_viewport_x
- this.hscroll
.Value
, 0, false);
1738 XplatUI
.ScrollWindow(this.Handle
, ClientRectangle
, old_viewport_x
- this.hscroll
.Value
, 0, false);
1740 document
.UpdateCaret();
1742 EventHandler eh
= (EventHandler
)(Events
[HScrolledEvent
]);
1744 eh (this, EventArgs
.Empty
);
1747 private void vscroll_ValueChanged(object sender
, EventArgs e
) {
1750 old_viewport_y
= document
.ViewPortY
;
1751 document
.ViewPortY
= this.vscroll
.Value
;
1753 if (hscroll
.Visible
) {
1754 XplatUI
.ScrollWindow(this.Handle
, new Rectangle(0, 0, ClientSize
.Width
, ClientSize
.Height
- hscroll
.Height
), 0, old_viewport_y
- this.vscroll
.Value
, false);
1756 XplatUI
.ScrollWindow(this.Handle
, ClientRectangle
, 0, old_viewport_y
- this.vscroll
.Value
, false);
1758 document
.UpdateCaret();
1760 EventHandler eh
= (EventHandler
)(Events
[VScrolledEvent
]);
1762 eh (this, EventArgs
.Empty
);
1765 private void TextBoxBase_MouseMove(object sender
, MouseEventArgs e
) {
1766 // FIXME - handle auto-scrolling if mouse is to the right/left of the window
1768 if (!ClientRectangle
.Contains (e
.X
, e
.Y
)) {
1769 if (scroll_timer
== null) {
1770 scroll_timer
= new Timer ();
1771 scroll_timer
.Interval
= 100;
1772 scroll_timer
.Tick
+= new EventHandler (ScrollTimerTickHandler
);
1775 if (!scroll_timer
.Enabled
) {
1776 scroll_timer
.Start ();
1778 // Force the first tick
1779 ScrollTimerTickHandler (null, EventArgs
.Empty
);
1785 document
.PositionCaret(e
.X
+ document
.ViewPortX
, e
.Y
+ document
.ViewPortY
);
1786 if (click_mode
== CaretSelection
.Position
) {
1787 document
.SetSelectionToCaret(false);
1788 document
.DisplayCaret();
1793 private void TextBoxBase_FontOrColorChanged(object sender
, EventArgs e
) {
1797 // Font changes apply to the whole document
1798 for (int i
= 1; i
<= document
.Lines
; i
++) {
1799 line
= document
.GetLine(i
);
1800 LineTag
.FormatText(line
, 1, line
.text
.Length
, Font
, ThemeEngine
.Current
.ResPool
.GetSolidBrush(ForeColor
));
1801 document
.UpdateView(line
, 0);
1803 // Make sure the caret height is matching the new font height
1804 document
.AlignCaret();
1808 private void ScrollTimerTickHandler (object sender
, EventArgs e
)
1810 Point pt
= Cursor
.Position
;
1812 pt
= PointToClient (pt
);
1814 if (pt
.X
< ClientRectangle
.Left
) {
1815 document
.MoveCaret(CaretDirection
.CharBackNoWrap
);
1816 document
.SetSelectionToCaret(false);
1818 CaretMoved(this, null);
1819 } else if (pt
.X
> ClientRectangle
.Right
) {
1820 document
.MoveCaret(CaretDirection
.CharForwardNoWrap
);
1821 document
.SetSelectionToCaret(false);
1823 CaretMoved(this, null);
1824 } else if (pt
.Y
> ClientRectangle
.Bottom
) {
1825 document
.MoveCaret(CaretDirection
.LineDown
);
1826 document
.SetSelectionToCaret(false);
1828 CaretMoved(this, null);
1829 } else if (pt
.Y
< ClientRectangle
.Top
) {
1830 document
.MoveCaret(CaretDirection
.LineUp
);
1831 document
.SetSelectionToCaret(false);
1833 CaretMoved(this, null);
1837 /// <summary>Ensure the caret is always visible</summary>
1838 internal void CaretMoved(object sender
, EventArgs e
) {
1842 pos
= document
.Caret
;
1843 //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);
1846 // Horizontal scrolling:
1847 // If the caret moves to the left outside the visible area, we jump the document into view, not just one
1848 // character, but 1/3 of the width of the document
1849 // If the caret moves to the right outside the visible area, we scroll just enough to keep the caret visible
1851 // Handle horizontal scrolling
1852 if (document
.CaretLine
.alignment
== HorizontalAlignment
.Left
) {
1853 // Check if we moved out of view to the left
1854 if (pos
.X
< (document
.ViewPortX
)) {
1856 if ((hscroll
.Value
- document
.ViewPortWidth
/ 3) >= hscroll
.Minimum
) {
1857 hscroll
.Value
-= document
.ViewPortWidth
/ 3;
1859 hscroll
.Value
= hscroll
.Minimum
;
1861 } while (hscroll
.Value
> pos
.X
);
1864 // Check if we moved out of view to the right
1865 if ((pos
.X
>= (document
.ViewPortWidth
+ document
.ViewPortX
)) && (hscroll
.Value
!= hscroll
.Maximum
)) {
1866 if ((pos
.X
- document
.ViewPortWidth
+ 1) <= hscroll
.Maximum
) {
1867 if (pos
.X
- document
.ViewPortWidth
>= 0) {
1868 hscroll
.Value
= pos
.X
- document
.ViewPortWidth
+ 1;
1873 hscroll
.Value
= hscroll
.Maximum
;
1876 } else if (document
.CaretLine
.alignment
== HorizontalAlignment
.Right
) {
1877 // hscroll.Value = pos.X;
1879 // if ((pos.X > (this.canvas_width + document.ViewPortX)) && (hscroll.Enabled && (hscroll.Value != hscroll.Maximum))) {
1880 // hscroll.Value = hscroll.Maximum;
1883 // FIXME - implement center cursor alignment
1890 // Handle vertical scrolling
1891 height
= document
.CaretLine
.Height
+ 1;
1893 if (pos
.Y
< document
.ViewPortY
) {
1894 vscroll
.Value
= pos
.Y
;
1897 if ((pos
.Y
+ height
) > (document
.ViewPortY
+ canvas_height
)) {
1898 vscroll
.Value
= pos
.Y
- canvas_height
+ height
;
1902 internal bool Paste(IDataObject clip
, DataFormats
.Format format
, bool obey_length
) {
1908 if (format
== null) {
1909 if ((this is RichTextBox
) && clip
.GetDataPresent(DataFormats
.Rtf
)) {
1910 format
= DataFormats
.GetFormat(DataFormats
.Rtf
);
1911 } else if (clip
.GetDataPresent(DataFormats
.UnicodeText
)) {
1912 format
= DataFormats
.GetFormat(DataFormats
.UnicodeText
);
1913 } else if (clip
.GetDataPresent(DataFormats
.Text
)) {
1914 format
= DataFormats
.GetFormat(DataFormats
.Text
);
1919 if ((format
.Name
== DataFormats
.Rtf
) && !(this is RichTextBox
)) {
1923 if (!clip
.GetDataPresent(format
.Name
)) {
1928 if (format
.Name
== DataFormats
.Rtf
) {
1929 ((RichTextBox
)this).SelectedRtf
= (string)clip
.GetData(DataFormats
.Rtf
);
1931 } else if (format
.Name
== DataFormats
.UnicodeText
) {
1932 s
= (string)clip
.GetData(DataFormats
.UnicodeText
);
1933 } else if (format
.Name
== DataFormats
.Text
) {
1934 s
= (string)clip
.GetData(DataFormats
.Text
);
1940 this.SelectedText
= s
;
1942 if ((s
.Length
+ document
.Length
) < max_length
) {
1943 this.SelectedText
= s
;
1944 } else if (document
.Length
< max_length
) {
1945 this.SelectedText
= s
.Substring(0, max_length
- document
.Length
);
1951 #endregion // Private Methods