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) 2005-2006 Novell, Inc. (http://www.novell.com)
23 // Peter Bartok <pbartok@novell.com>
30 using System
.Collections
;
31 using System
.ComponentModel
;
35 using RTF
=System
.Windows
.Forms
.RTF
;
37 namespace System
.Windows
.Forms
{
38 public class RichTextBox
: TextBoxBase
{
39 #region Local Variables
40 internal bool auto_word_select
;
41 internal int bullet_indent
;
42 internal bool can_redo
;
43 internal bool detect_urls
;
44 internal string redo_action_name
;
45 internal int margin_right
;
46 internal string undo_action_name
;
49 private RTF
.TextMap rtf_text_map
;
50 private int rtf_skip_width
;
51 private int rtf_skip_count
;
52 private StringBuilder rtf_line
;
53 private SolidBrush rtf_color
;
54 private RTF
.Font rtf_rtffont
;
55 private int rtf_rtffont_size
;
56 private FontStyle rtf_rtfstyle
;
57 private HorizontalAlignment rtf_rtfalign
;
58 private int rtf_cursor_x
;
59 private int rtf_cursor_y
;
60 private int rtf_chars
;
61 #endregion // Local Variables
63 #region Public Constructors
64 public RichTextBox() {
65 accepts_return
= true;
66 auto_word_select
= false;
70 max_length
= Int32
.MaxValue
;
71 redo_action_name
= string.Empty
;
73 undo_action_name
= string.Empty
;
75 base.Multiline
= true;
76 document
.CRLFSize
= 1;
78 scrollbars
= RichTextBoxScrollBars
.Both
;
79 alignment
= HorizontalAlignment
.Left
;
80 LostFocus
+= new EventHandler(RichTextBox_LostFocus
);
81 GotFocus
+= new EventHandler(RichTextBox_GotFocus
);
82 BackColor
= ThemeEngine
.Current
.ColorWindow
;
83 ForeColor
= ThemeEngine
.Current
.ColorWindowText
;
84 base.HScrolled
+= new EventHandler(RichTextBox_HScrolled
);
85 base.VScrolled
+= new EventHandler(RichTextBox_VScrolled
);
87 #endregion // Public Constructors
89 #region Private & Internal Methods
90 private void RichTextBox_LostFocus(object sender
, EventArgs e
) {
95 private void RichTextBox_GotFocus(object sender
, EventArgs e
) {
99 #endregion // Private & Internal Methods
101 #region Public Instance Properties
102 public override bool AllowDrop
{
104 return base.AllowDrop
;
108 base.AllowDrop
= value;
112 [DefaultValue(false)]
114 public override bool AutoSize
{
120 base.AutoSize
= value;
124 [DefaultValue(false)]
125 public bool AutoWordSelection
{
127 return auto_word_select
;
131 auto_word_select
= true;
136 [EditorBrowsable(EditorBrowsableState
.Never
)]
137 public override System
.Drawing
.Image BackgroundImage
{
139 return background_image
;
143 base.BackgroundImage
= value;
149 public int BulletIndent
{
151 return bullet_indent
;
155 bullet_indent
= value;
160 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
161 public bool CanRedo
{
168 public bool DetectUrls
{
178 public override Font Font
{
189 if (PreferredHeight
!= Height
) {
190 Height
= PreferredHeight
;
196 // Font changes always set the whole doc to that font
197 start
= document
.GetLine(1);
198 end
= document
.GetLine(document
.Lines
);
199 document
.FormatText(start
, 1, end
, end
.text
.Length
+ 1, base.Font
, new SolidBrush(this.ForeColor
));
204 public override Color ForeColor
{
206 return base.ForeColor
;
210 base.ForeColor
= value;
214 [DefaultValue(Int32
.MaxValue
)]
215 public override int MaxLength
{
217 return base.max_length
;
221 base.max_length
= value;
226 public override bool Multiline
{
232 base.Multiline
= value;
237 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
239 public string RedoActionName
{
241 return redo_action_name
;
247 [MonoTODO("Teach TextControl.RecalculateLine to consider the right margin as well")]
248 public int RightMargin
{
254 margin_right
= value;
260 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
266 start_line
= document
.GetLine(1);
267 end_line
= document
.GetLine(document
.Lines
);
268 return GenerateRTF(start_line
, 0, end_line
, end_line
.text
.Length
).ToString();
275 data
= new MemoryStream(Encoding
.ASCII
.GetBytes(value), false);
277 InsertRTFFromStream(data
, 0, 1);
285 [DefaultValue(RichTextBoxScrollBars
.Both
)]
287 public RichTextBoxScrollBars ScrollBars
{
299 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
300 public string SelectedRtf
{
302 return GenerateRTF(document
.selection_start
.line
, document
.selection_start
.pos
, document
.selection_end
.line
, document
.selection_end
.pos
).ToString();
314 if (document
.selection_visible
) {
315 document
.ReplaceSelection("");
318 sel_start
= document
.LineTagToCharIndex(document
.selection_start
.line
, document
.selection_start
.pos
);
320 data
= new MemoryStream(Encoding
.ASCII
.GetBytes(value), false);
321 InsertRTFFromStream(data
, document
.selection_start
.pos
, document
.selection_start
.line
.line_no
, out x
, out y
, out chars
);
324 document
.CharIndexToLineTag(sel_start
+ chars
+ (y
- document
.selection_start
.line
.line_no
) * 2, out line
, out tag
, out sel_start
);
325 document
.SetSelection(line
, sel_start
);
326 document
.PositionCaret(line
, sel_start
);
327 document
.DisplayCaret();
329 OnTextChanged(EventArgs
.Empty
);
335 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
336 public override string SelectedText
{
338 return base.SelectedText
;
342 base.SelectedText
= value;
347 [DefaultValue(HorizontalAlignment
.Left
)]
348 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
349 public HorizontalAlignment SelectionAlignment
{
351 HorizontalAlignment align
;
356 start
= document
.ParagraphStart(document
.selection_start
.line
);
357 align
= start
.alignment
;
359 end
= document
.ParagraphEnd(document
.selection_end
.line
);
364 if (line
.alignment
!= align
) {
365 return HorizontalAlignment
.Left
;
371 line
= document
.GetLine(line
.line_no
+ 1);
382 start
= document
.ParagraphStart(document
.selection_start
.line
);
384 end
= document
.ParagraphEnd(document
.selection_end
.line
);
389 line
.alignment
= value;
394 line
= document
.GetLine(line
.line_no
+ 1);
396 this.CalculateDocument();
401 [DefaultValue(false)]
402 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
404 public bool SelectionBullet
{
415 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
417 public int SelectionCharOffset
{
427 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
428 public Color SelectionColor
{
435 start
= document
.selection_start
.tag
;
436 end
= document
.selection_end
.tag
;
437 color
= ((SolidBrush
)document
.selection_start
.tag
.color
).Color
;
441 if (!color
.Equals(((SolidBrush
)tag
.color
).Color
)) {
449 tag
= document
.NextTag(tag
);
460 FontDefinition attributes
;
464 attributes
= new FontDefinition();
465 attributes
.color
= value;
467 sel_start
= document
.LineTagToCharIndex(document
.selection_start
.line
, document
.selection_start
.pos
);
468 sel_end
= document
.LineTagToCharIndex(document
.selection_end
.line
, document
.selection_end
.pos
);
470 document
.FormatText(document
.selection_start
.line
, document
.selection_start
.pos
+ 1, document
.selection_end
.line
, document
.selection_end
.pos
+ 1, attributes
);
472 document
.CharIndexToLineTag(sel_start
, out document
.selection_start
.line
, out document
.selection_start
.tag
, out document
.selection_start
.pos
);
473 document
.CharIndexToLineTag(sel_end
, out document
.selection_end
.line
, out document
.selection_end
.tag
, out document
.selection_end
.pos
);
475 document
.UpdateView(document
.selection_start
.line
, 0);
476 document
.AlignCaret();
481 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
482 public Font SelectionFont
{
489 start
= document
.selection_start
.tag
;
490 end
= document
.selection_end
.tag
;
491 font
= document
.selection_start
.tag
.font
;
495 if (!font
.Equals(tag
.font
)) {
503 tag
= document
.NextTag(tag
);
514 FontDefinition attributes
;
518 attributes
= new FontDefinition();
519 attributes
.font_obj
= value;
521 sel_start
= document
.LineTagToCharIndex(document
.selection_start
.line
, document
.selection_start
.pos
);
522 sel_end
= document
.LineTagToCharIndex(document
.selection_end
.line
, document
.selection_end
.pos
);
524 document
.FormatText(document
.selection_start
.line
, document
.selection_start
.pos
+ 1, document
.selection_end
.line
, document
.selection_end
.pos
+ 1, attributes
);
526 document
.CharIndexToLineTag(sel_start
, out document
.selection_start
.line
, out document
.selection_start
.tag
, out document
.selection_start
.pos
);
527 document
.CharIndexToLineTag(sel_end
, out document
.selection_end
.line
, out document
.selection_end
.tag
, out document
.selection_end
.pos
);
529 document
.UpdateView(document
.selection_start
.line
, 0);
530 document
.AlignCaret();
537 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
539 public int SelectionHangingIndent
{
550 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
552 public int SelectionIndent
{
562 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
563 public override int SelectionLength
{
565 return base.SelectionLength
;
569 base.SelectionLength
= value;
574 [DefaultValue(false)]
575 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
577 public bool SelectionProtected
{
588 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
590 public int SelectionRightIndent
{
600 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
602 public int[] SelectionTabs
{
612 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
613 public RichTextBoxSelectionTypes SelectionType
{
615 if (document
.selection_start
== document
.selection_end
) {
616 return RichTextBoxSelectionTypes
.Empty
;
620 if (SelectedText
.Length
> 1) {
621 return RichTextBoxSelectionTypes
.MultiChar
| RichTextBoxSelectionTypes
.Text
;
624 return RichTextBoxSelectionTypes
.Text
;
628 [DefaultValue(false)]
630 public bool ShowSelectionMargin
{
640 public override string Text
{
651 public override int TextLength
{
653 return base.TextLength
;
658 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
659 public string UndoActionName
{
661 return document
.undo
.UndoName
;
667 public float ZoomFactor
{
676 #endregion // Public Instance Properties
678 #region Protected Instance Properties
679 protected override CreateParams CreateParams
{
681 return base.CreateParams
;
685 protected override Size DefaultSize
{
687 return new Size(100, 96);
690 #endregion // Protected Instance Properties
692 #region Public Instance Methods
693 public bool CanPaste(DataFormats
.Format clipFormat
) {
694 if ((clipFormat
.Name
== DataFormats
.Rtf
) ||
695 (clipFormat
.Name
== DataFormats
.Text
) ||
696 (clipFormat
.Name
== DataFormats
.UnicodeText
)) {
702 public int Find(char[] characterSet
) {
703 return Find(characterSet
, -1, -1);
706 public int Find(char[] characterSet
, int start
) {
707 return Find(characterSet
, start
, -1);
710 public int Find(char[] characterSet
, int start
, int end
) {
711 Document
.Marker start_mark
;
712 Document
.Marker end_mark
;
713 Document
.Marker result
;
716 document
.GetMarker(out start_mark
, true);
722 start_mark
= new Document
.Marker();
724 document
.CharIndexToLineTag(start
, out line
, out tag
, out pos
);
725 start_mark
.line
= line
;
726 start_mark
.tag
= tag
;
727 start_mark
.pos
= pos
;
731 document
.GetMarker(out end_mark
, false);
737 end_mark
= new Document
.Marker();
739 document
.CharIndexToLineTag(end
, out line
, out tag
, out pos
);
740 end_mark
.line
= line
;
745 if (document
.FindChars(characterSet
, start_mark
, end_mark
, out result
)) {
746 return document
.LineTagToCharIndex(result
.line
, result
.pos
);
752 public int Find(string str
) {
753 return Find(str
, -1, -1, RichTextBoxFinds
.None
);
756 public int Find(string str
, int start
, int end
, RichTextBoxFinds options
) {
757 Document
.Marker start_mark
;
758 Document
.Marker end_mark
;
759 Document
.Marker result
;
762 document
.GetMarker(out start_mark
, true);
768 start_mark
= new Document
.Marker();
770 document
.CharIndexToLineTag(start
, out line
, out tag
, out pos
);
772 start_mark
.line
= line
;
773 start_mark
.tag
= tag
;
774 start_mark
.pos
= pos
;
778 document
.GetMarker(out end_mark
, false);
784 end_mark
= new Document
.Marker();
786 document
.CharIndexToLineTag(end
, out line
, out tag
, out pos
);
788 end_mark
.line
= line
;
793 if (document
.Find(str
, start_mark
, end_mark
, out result
, options
)) {
794 return document
.LineTagToCharIndex(result
.line
, result
.pos
);
800 public int Find(string str
, int start
, RichTextBoxFinds options
) {
801 return Find(str
, start
, -1, options
);
804 public int Find(string str
, RichTextBoxFinds options
) {
805 return Find(str
, -1, -1, options
);
808 public char GetCharFromPosition(Point pt
) {
812 PointToTagPos(pt
, out tag
, out pos
);
814 if (pos
>= tag
.line
.text
.Length
) {
818 return tag
.line
.text
[pos
];
822 public int GetCharIndexFromPosition(Point pt
) {
826 PointToTagPos(pt
, out tag
, out pos
);
828 return document
.LineTagToCharIndex(tag
.line
, pos
);
831 public int GetLineFromCharIndex(int index
) {
836 document
.CharIndexToLineTag(index
, out line
, out tag
, out pos
);
838 return line
.LineNo
- 1;
841 public Point
GetPositionFromCharIndex(int index
) {
846 document
.CharIndexToLineTag(index
, out line
, out tag
, out pos
);
848 return new Point((int)line
.widths
[pos
] + 1, line
.Y
+ 1);
851 public void LoadFile(System
.IO
.Stream data
, RichTextBoxStreamType fileType
) {
854 // FIXME - ignoring unicode
855 if (fileType
== RichTextBoxStreamType
.PlainText
) {
861 sb
= new StringBuilder((int)data
.Length
);
862 buffer
= new byte[1024];
866 throw new IOException("Not enough memory to load document");
870 while (count
< data
.Length
) {
871 count
+= data
.Read(buffer
, count
, 1024);
874 base.Text
= sb
.ToString();
878 InsertRTFFromStream(data
, 0, 1);
881 [MonoTODO("Make smarter RTF detection?")]
882 public void LoadFile(string path
) {
883 if (path
.EndsWith(".rtf")) {
884 LoadFile(path
, RichTextBoxStreamType
.RichText
);
886 LoadFile(path
, RichTextBoxStreamType
.PlainText
);
890 public void LoadFile(string path
, RichTextBoxStreamType fileType
) {
896 data
= new FileStream(path
, FileMode
.Open
, FileAccess
.Read
, FileShare
.Read
, 1024);
897 LoadFile(data
, fileType
);
901 throw new IOException("Could not open file " + path
);
911 public void Paste(DataFormats
.Format clipFormat
) {
912 base.Paste(Clipboard
.GetDataObject(), clipFormat
, false);
919 public void SaveFile(Stream data
, RichTextBoxStreamType fileType
) {
925 if (fileType
== RichTextBoxStreamType
.UnicodePlainText
) {
926 encoding
= Encoding
.Unicode
;
928 encoding
= Encoding
.ASCII
;
932 case RichTextBoxStreamType
.PlainText
:
933 case RichTextBoxStreamType
.TextTextOleObjs
:
934 case RichTextBoxStreamType
.UnicodePlainText
: {
936 bytes
= encoding
.GetBytes(document
.Root
.text
.ToString());
937 data
.Write(bytes
, 0, bytes
.Length
);
941 for (i
= 1; i
< document
.Lines
; i
++) {
942 bytes
= encoding
.GetBytes(document
.GetLine(i
).text
.ToString() + Environment
.NewLine
);
943 data
.Write(bytes
, 0, bytes
.Length
);
945 bytes
= encoding
.GetBytes(document
.GetLine(document
.Lines
).text
.ToString());
946 data
.Write(bytes
, 0, bytes
.Length
);
951 // If we're here we're saving RTF
958 start_line
= document
.GetLine(1);
959 end_line
= document
.GetLine(document
.Lines
);
960 rtf
= GenerateRTF(start_line
, 0, end_line
, end_line
.text
.Length
);
962 bytes
= new Byte
[4096];
964 // Let's chunk it so we don't use up all memory...
965 for (i
= 0; i
< total
; i
+= 1024) {
966 if ((i
+ 1024) < total
) {
967 current
= encoding
.GetBytes(rtf
.ToString(i
, 1024), 0, 1024, bytes
, 0);
970 current
= encoding
.GetBytes(rtf
.ToString(i
, current
), 0, current
, bytes
, 0);
972 data
.Write(bytes
, 0, current
);
976 public void SaveFile(string path
) {
977 if (path
.EndsWith(".rtf")) {
978 SaveFile(path
, RichTextBoxStreamType
.RichText
);
980 SaveFile(path
, RichTextBoxStreamType
.PlainText
);
984 public void SaveFile(string path
, RichTextBoxStreamType fileType
) {
990 data
= new FileStream(path
, FileMode
.Create
, FileAccess
.Write
, FileShare
.None
, 1024, false);
991 SaveFile(data
, fileType
);
995 // throw new IOException("Could not write document to file " + path);
1005 #endregion // Public Instance Methods
1007 #region Protected Instance Methods
1008 protected virtual object CreateRichEditOleCallback() {
1009 throw new NotImplementedException();
1012 protected override void OnBackColorChanged(EventArgs e
) {
1013 base.OnBackColorChanged (e
);
1016 protected virtual void OnContentsResized(ContentsResizedEventArgs e
) {
1017 if (ContentsResized
!= null) {
1018 ContentsResized(this, e
);
1022 protected override void OnContextMenuChanged(EventArgs e
) {
1023 base.OnContextMenuChanged (e
);
1026 protected override void OnHandleCreated(EventArgs e
) {
1027 base.OnHandleCreated (e
);
1030 protected override void OnHandleDestroyed(EventArgs e
) {
1031 base.OnHandleDestroyed (e
);
1034 protected virtual void OnHScroll(EventArgs e
) {
1035 if (HScroll
!= null) {
1040 [MonoTODO("Determine when to call this")]
1041 protected virtual void OnImeChange(EventArgs e
) {
1042 if (ImeChange
!= null) {
1047 protected virtual void OnLinkClicked(LinkClickedEventArgs e
) {
1048 if (LinkClicked
!= null) {
1049 LinkClicked(this, e
);
1053 protected virtual void OnProtected(EventArgs e
) {
1054 if (Protected
!= null) {
1059 protected override void OnRightToLeftChanged(EventArgs e
) {
1060 base.OnRightToLeftChanged (e
);
1063 protected virtual void OnSelectionChanged(EventArgs e
) {
1064 if (SelectionChanged
!= null) {
1065 SelectionChanged(this, e
);
1069 protected override void OnSystemColorsChanged(EventArgs e
) {
1070 base.OnSystemColorsChanged (e
);
1073 protected override void OnTextChanged(EventArgs e
) {
1074 base.OnTextChanged (e
);
1077 protected virtual void OnVScroll(EventArgs e
) {
1078 if (VScroll
!= null) {
1083 protected override void WndProc(ref Message m
) {
1084 base.WndProc (ref m
);
1086 #endregion // Protected Instance Methods
1090 [EditorBrowsable(EditorBrowsableState
.Never
)]
1091 public event EventHandler BackgroundImageChanged
;
1093 public event ContentsResizedEventHandler ContentsResized
;
1096 [EditorBrowsable(EditorBrowsableState
.Never
)]
1097 public event EventHandler DoubleClick
;
1100 [EditorBrowsable(EditorBrowsableState
.Never
)]
1101 public event DragEventHandler DragDrop
{
1103 base.DragDrop
+= value;
1107 base.DragDrop
-= value;
1112 [EditorBrowsable(EditorBrowsableState
.Never
)]
1113 public event DragEventHandler DragEnter
{
1115 base.DragEnter
+= value;
1119 base.DragEnter
-= value;
1124 [EditorBrowsable(EditorBrowsableState
.Never
)]
1125 public event EventHandler DragLeave
{
1127 base.DragLeave
+= value;
1131 base.DragLeave
-= value;
1137 [EditorBrowsable(EditorBrowsableState
.Never
)]
1138 public event DragEventHandler DragOver
{
1140 base.DragOver
+= value;
1144 base.DragOver
-= value;
1150 [EditorBrowsable(EditorBrowsableState
.Never
)]
1151 public event GiveFeedbackEventHandler GiveFeedback
;
1153 public event EventHandler HScroll
;
1154 public event EventHandler ImeChange
;
1155 public event LinkClickedEventHandler LinkClicked
;
1156 public event EventHandler Protected
;
1159 [EditorBrowsable(EditorBrowsableState
.Never
)]
1160 public event QueryContinueDragEventHandler QueryContinueDrag
;
1161 public event EventHandler SelectionChanged
;
1162 public event EventHandler VScroll
;
1163 #endregion // Events
1165 #region Private Methods
1166 private void HandleControl(RTF
.RTF rtf
) {
1167 // Console.WriteLine ("HANDLING MAJOR: {0} MINOR: {1}", rtf.Major, rtf.Minor);
1169 case RTF
.Major
.Unicode
: {
1171 case Minor
.UnicodeCharBytes
: {
1172 rtf_skip_width
= rtf
.Param
;
1176 case Minor
.UnicodeChar
: {
1177 rtf_skip_count
+= rtf_skip_width
;
1178 rtf_line
.Append((char)rtf
.Param
);
1185 case RTF
.Major
.Destination
: {
1186 // Console.Write("[Got Destination control {0}]", rtf.Minor);
1191 case RTF
.Major
.CharAttr
: {
1193 case Minor
.ForeColor
: {
1194 System
.Windows
.Forms
.RTF
.Color color
;
1196 color
= System
.Windows
.Forms
.RTF
.Color
.GetColor(rtf
, rtf
.Param
);
1197 if (color
!= null) {
1198 FlushText(rtf
, false);
1199 if (color
.Red
== -1 && color
.Green
== -1 && color
.Blue
== -1) {
1200 this.rtf_color
= new SolidBrush(ForeColor
);
1202 this.rtf_color
= new SolidBrush(Color
.FromArgb(color
.Red
, color
.Green
, color
.Blue
));
1208 case Minor
.FontSize
: {
1209 FlushText(rtf
, false);
1210 this.rtf_rtffont_size
= rtf
.Param
/ 2;
1214 case Minor
.FontNum
: {
1215 System
.Windows
.Forms
.RTF
.Font font
;
1217 font
= System
.Windows
.Forms
.RTF
.Font
.GetFont(rtf
, rtf
.Param
);
1219 FlushText(rtf
, false);
1220 this.rtf_rtffont
= font
;
1226 FlushText(rtf
, false);
1227 rtf_rtfstyle
= FontStyle
.Regular
;
1232 FlushText(rtf
, false);
1233 if (rtf
.Param
== RTF
.RTF
.NoParam
) {
1234 rtf_rtfstyle
|= FontStyle
.Bold
;
1236 rtf_rtfstyle
&= ~FontStyle
.Bold
;
1241 case Minor
.Italic
: {
1242 FlushText(rtf
, false);
1243 if (rtf
.Param
== RTF
.RTF
.NoParam
) {
1244 rtf_rtfstyle
|= FontStyle
.Italic
;
1246 rtf_rtfstyle
&= ~FontStyle
.Italic
;
1251 case Minor
.StrikeThru
: {
1252 FlushText(rtf
, false);
1253 if (rtf
.Param
== RTF
.RTF
.NoParam
) {
1254 rtf_rtfstyle
|= FontStyle
.Strikeout
;
1256 rtf_rtfstyle
&= ~FontStyle
.Strikeout
;
1261 case Minor
.Underline
: {
1262 FlushText(rtf
, false);
1263 if (rtf
.Param
== RTF
.RTF
.NoParam
) {
1264 rtf_rtfstyle
|= FontStyle
.Underline
;
1266 rtf_rtfstyle
= rtf_rtfstyle
& ~FontStyle
.Underline
;
1271 case Minor
.NoUnderline
: {
1272 FlushText(rtf
, false);
1273 rtf_rtfstyle
&= ~FontStyle
.Underline
;
1280 case RTF
.Major
.SpecialChar
: {
1281 //Console.Write("[Got SpecialChar control {0}]", rtf.Minor);
1288 private void SpecialChar(RTF
.RTF rtf
) {
1295 FlushText(rtf
, true);
1304 case Minor
.NoBrkSpace
: {
1310 rtf_line
.Append ("\t");
1311 // FlushText (rtf, false);
1315 case Minor
.NoReqHyphen
:
1316 case Minor
.NoBrkHyphen
: {
1317 rtf_line
.Append ("-");
1318 // FlushText (rtf, false);
1322 case Minor
.Bullet
: {
1323 Console
.WriteLine("*");
1327 case Minor
.WidowCtrl
:
1330 case Minor
.EmDash
: {
1331 rtf_line
.Append ("\u2014");
1335 case Minor
.EnDash
: {
1336 rtf_line
.Append ("\u2013");
1340 case Minor.LQuote: {
1341 Console.Write("\u2018");
1345 case Minor.RQuote: {
1346 Console.Write("\u2019");
1350 case Minor.LDblQuote: {
1351 Console.Write("\u201C");
1355 case Minor.RDblQuote: {
1356 Console.Write("\u201D");
1361 // Console.WriteLine ("skipped special char: {0}", rtf.Minor);
1368 private void HandleText(RTF
.RTF rtf
) {
1369 if (rtf_skip_count
> 0) {
1374 if ((RTF
.StandardCharCode
)rtf
.Minor
!= RTF
.StandardCharCode
.nothing
) {
1375 rtf_line
.Append(rtf_text_map
[(RTF
.StandardCharCode
)rtf
.Minor
]);
1377 if ((int)rtf
.Major
> 31 && (int)rtf
.Major
< 128) {
1378 rtf_line
.Append((char)rtf
.Major
);
1380 //rtf_line.Append((char)rtf.Major);
1381 Console
.Write("[Literal:0x{0:X2}]", (int)rtf
.Major
);
1386 private void FlushText(RTF
.RTF rtf
, bool newline
) {
1390 length
= rtf_line
.Length
;
1391 if (!newline
&& (length
== 0)) {
1395 if (rtf_rtffont
== null) {
1396 // First font in table is default
1397 rtf_rtffont
= System
.Windows
.Forms
.RTF
.Font
.GetFont(rtf
, 0);
1400 font
= new Font(rtf_rtffont
.Name
, rtf_rtffont_size
, rtf_rtfstyle
);
1402 if (rtf_color
== null) {
1403 System
.Windows
.Forms
.RTF
.Color color
;
1405 // First color in table is default
1406 color
= System
.Windows
.Forms
.RTF
.Color
.GetColor(rtf
, 0);
1408 if ((color
== null) || (color
.Red
== -1 && color
.Green
== -1 && color
.Blue
== -1)) {
1409 rtf_color
= new SolidBrush(ForeColor
);
1411 rtf_color
= new SolidBrush(Color
.FromArgb(color
.Red
, color
.Green
, color
.Blue
));
1415 rtf_chars
+= rtf_line
.Length
;
1417 if (rtf_cursor_x
== 0) {
1418 document
.Add(rtf_cursor_y
, rtf_line
.ToString(), rtf_rtfalign
, font
, rtf_color
);
1422 line
= document
.GetLine(rtf_cursor_y
);
1423 if (rtf_line
.Length
> 0) {
1424 document
.InsertString(line
, rtf_cursor_x
, rtf_line
.ToString());
1425 document
.FormatText(line
, rtf_cursor_x
+ 1, line
, rtf_cursor_x
+ 1 + length
, font
, rtf_color
); // FormatText is 1-based
1428 document
.Split(line
, rtf_cursor_x
+ length
);
1436 rtf_cursor_x
+= length
;
1438 rtf_line
.Length
= 0; // Empty line
1441 private void InsertRTFFromStream(Stream data
, int cursor_x
, int cursor_y
) {
1446 InsertRTFFromStream(data
, cursor_x
, cursor_y
, out x
, out y
, out chars
);
1449 private void InsertRTFFromStream(Stream data
, int cursor_x
, int cursor_y
, out int to_x
, out int to_y
, out int chars
) {
1452 rtf
= new RTF
.RTF(data
);
1455 rtf
.ClassCallback
[RTF
.TokenClass
.Text
] = new RTF
.ClassDelegate(HandleText
);
1456 rtf
.ClassCallback
[RTF
.TokenClass
.Control
] = new RTF
.ClassDelegate(HandleControl
);
1460 rtf_line
= new StringBuilder();
1462 rtf_rtffont_size
= (int)this.Font
.Size
;
1463 rtf_rtfalign
= HorizontalAlignment
.Left
;
1464 rtf_rtfstyle
= FontStyle
.Regular
;
1466 rtf_cursor_x
= cursor_x
;
1467 rtf_cursor_y
= cursor_y
;
1469 rtf
.DefaultFont(this.Font
.Name
);
1471 rtf_text_map
= new RTF
.TextMap();
1472 RTF
.TextMap
.SetupStandardTable(rtf_text_map
.Table
);
1474 document
.NoRecalc
= true;
1477 rtf
.Read(); // That's it
1478 FlushText(rtf
, false);
1481 catch (RTF
.RTFException e
) {
1482 // Seems to be plain text or broken RTF
1483 Console
.WriteLine("RTF Parsing failure: {0}", e
.Message
);
1486 to_x
= rtf_cursor_x
;
1487 to_y
= rtf_cursor_y
;
1490 document
.RecalculateDocument(CreateGraphicsInternal(), cursor_y
, document
.Lines
, false);
1491 document
.NoRecalc
= false;
1493 document
.Invalidate(document
.GetLine(cursor_y
), 0, document
.GetLine(document
.Lines
), -1);
1496 private void RichTextBox_HScrolled(object sender
, EventArgs e
) {
1500 private void RichTextBox_VScrolled(object sender
, EventArgs e
) {
1504 private void PointToTagPos(Point pt
, out LineTag tag
, out int pos
) {
1509 if (p
.X
>= document
.ViewPortWidth
) {
1510 p
.X
= document
.ViewPortWidth
- 1;
1511 } else if (p
.X
< 0) {
1515 if (p
.Y
>= document
.ViewPortHeight
) {
1516 p
.Y
= document
.ViewPortHeight
- 1;
1517 } else if (p
.Y
< 0) {
1521 tag
= document
.FindCursor(p
.X
+ document
.ViewPortX
, p
.Y
+ document
.ViewPortY
, out pos
);
1524 private void EmitRTFFontProperties(StringBuilder rtf
, int prev_index
, int font_index
, Font prev_font
, Font font
) {
1525 if (prev_index
!= font_index
) {
1526 rtf
.Append(String
.Format("\\f{0}", font_index
)); // Font table entry
1529 if ((prev_font
== null) || (prev_font
.Size
!= font
.Size
)) {
1530 rtf
.Append(String
.Format("\\fs{0}", (int)(font
.Size
* 2))); // Font size
1533 if ((prev_font
== null) || (font
.Bold
!= prev_font
.Bold
)) {
1537 if (prev_font
!= null) {
1543 if ((prev_font
== null) || (font
.Italic
!= prev_font
.Italic
)) {
1547 if (prev_font
!= null) {
1553 if ((prev_font
== null) || (font
.Strikeout
!= prev_font
.Strikeout
)) {
1554 if (font
.Strikeout
) {
1555 rtf
.Append("\\strike");
1557 if (prev_font
!= null) {
1558 rtf
.Append("\\strike0");
1563 if ((prev_font
== null) || (font
.Underline
!= prev_font
.Underline
)) {
1564 if (font
.Underline
) {
1567 if (prev_font
!= null) {
1568 rtf
.Append("\\ul0");
1574 [MonoTODO("Emit unicode and other special characters properly")]
1575 private void EmitRTFText(StringBuilder rtf
, string text
) {
1579 // start_pos and end_pos are 0-based
1580 private StringBuilder
GenerateRTF(Line start_line
, int start_pos
, Line end_line
, int end_pos
) {
1594 sb
= new StringBuilder();
1595 fonts
= new ArrayList(10);
1596 colors
= new ArrayList(10);
1598 // Two runs, first we parse to determine tables;
1599 // and unlike most of our processing here we work on tags
1602 line_no
= start_line
.line_no
;
1605 // Add default font and color; to optimize document content we don't
1606 // use this.Font and this.ForeColor but the font/color from the first tag
1607 tag
= LineTag
.FindTag(start_line
, pos
);
1609 color
= ((SolidBrush
)tag
.color
).Color
;
1610 fonts
.Add(font
.Name
);
1613 while (line_no
<= end_line
.line_no
) {
1614 line
= document
.GetLine(line_no
);
1615 tag
= LineTag
.FindTag(line
, pos
);
1617 if (line_no
!= end_line
.line_no
) {
1618 line_len
= line
.text
.Length
;
1623 while (pos
< line_len
) {
1624 if (tag
.font
.Name
!= font
.Name
) {
1626 if (!fonts
.Contains(font
.Name
)) {
1627 fonts
.Add(font
.Name
);
1631 if (((SolidBrush
)tag
.color
).Color
!= color
) {
1632 color
= ((SolidBrush
)tag
.color
).Color
;
1633 if (!colors
.Contains(color
)) {
1638 pos
= tag
.start
+ tag
.length
- 1;
1645 // We have the tables, emit the header
1646 sb
.Append("{\\rtf1\\ansi");
1647 sb
.Append("\\ansicpg1252"); // FIXME - is this correct?
1650 sb
.Append(String
.Format("\\deff{0}", fonts
.IndexOf(this.Font
.Name
)));
1653 sb
.Append("\\deflang1033\n"); // FIXME - always 1033?
1655 // Emit the font table
1656 sb
.Append("{\\fonttbl");
1657 for (i
= 0; i
< fonts
.Count
; i
++) {
1658 sb
.Append(String
.Format("{{\\f{0}", i
)); // {Font
1659 sb
.Append("\\fnil"); // Family
1660 sb
.Append("\\fcharset0 "); // Charset ANSI<space>
1661 sb
.Append((string)fonts
[i
]); // Font name
1662 sb
.Append(";}"); // }
1666 // Emit the color table (if needed)
1667 if ((colors
.Count
> 1) || ((((Color
)colors
[0]).R
!= this.ForeColor
.R
) || (((Color
)colors
[0]).G
!= this.ForeColor
.G
) || (((Color
)colors
[0]).B
!= this.ForeColor
.B
))) {
1668 sb
.Append("{\\colortbl "); // Header and NO! default color
1669 for (i
= 0; i
< colors
.Count
; i
++) {
1670 sb
.Append(String
.Format("\\red{0}", ((Color
)colors
[i
]).R
));
1671 sb
.Append(String
.Format("\\green{0}", ((Color
)colors
[i
]).G
));
1672 sb
.Append(String
.Format("\\blue{0}", ((Color
)colors
[i
]).B
));
1678 sb
.Append("{\\*\\generator Mono RichTextBox;}");
1679 // Emit initial paragraph settings
1680 tag
= LineTag
.FindTag(start_line
, start_pos
);
1681 sb
.Append("\\pard"); // Reset to default paragraph properties
1682 EmitRTFFontProperties(sb
, -1, fonts
.IndexOf(tag
.font
.Name
), null, tag
.font
); // Font properties
1683 sb
.Append(" "); // Space separator
1686 color
= (Color
)colors
[0];
1688 line_no
= start_line
.line_no
;
1691 while (line_no
<= end_line
.line_no
) {
1692 line
= document
.GetLine(line_no
);
1693 tag
= LineTag
.FindTag(line
, pos
);
1695 if (line_no
!= end_line
.line_no
) {
1696 line_len
= line
.text
.Length
;
1701 while (pos
< line_len
) {
1704 if (tag
.font
!= font
) {
1705 EmitRTFFontProperties(sb
, fonts
.IndexOf(font
.Name
), fonts
.IndexOf(tag
.font
.Name
), font
, tag
.font
);
1709 if (((SolidBrush
)tag
.color
).Color
!= color
) {
1710 color
= ((SolidBrush
)tag
.color
).Color
;
1711 sb
.Append(String
.Format("\\cf{0}", colors
.IndexOf(color
)));
1713 if (length
!= sb
.Length
) {
1714 sb
.Append(" "); // Emit space to separate keywords from text
1717 // Emit the string itself
1718 if (line_no
!= end_line
.line_no
) {
1719 EmitRTFText(sb
, tag
.line
.text
.ToString(pos
, tag
.start
+ tag
.length
- pos
- 1));
1721 if (end_pos
< (tag
.start
+ tag
.length
- 1)) {
1722 // Emit partial tag only, end_pos is inside this tag
1723 EmitRTFText(sb
, tag
.line
.text
.ToString(pos
, end_pos
- pos
));
1725 EmitRTFText(sb
, tag
.line
.text
.ToString(pos
, tag
.start
+ tag
.length
- pos
- 1));
1729 pos
= tag
.start
+ tag
.length
- 1;
1732 if (pos
>= line
.text
.Length
) {
1733 if (!line
.soft_break
) {
1734 sb
.Append("\\par\n");
1745 #endregion // Private Methods