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
;
33 using System
.Drawing
.Imaging
;
36 using System
.Runtime
.InteropServices
;
37 using RTF
=System
.Windows
.Forms
.RTF
;
39 namespace System
.Windows
.Forms
{
41 [ClassInterface (ClassInterfaceType
.AutoDispatch
)]
42 [Docking (DockingBehavior
.Ask
)]
44 [Designer ("System.Windows.Forms.Design.RichTextBoxDesigner, " + Consts
.AssemblySystem_Design
, "System.ComponentModel.Design.IDesigner")]
46 public class RichTextBox
: TextBoxBase
{
47 #region Local Variables
48 internal bool auto_word_select
;
49 internal int bullet_indent
;
50 internal bool detect_urls
;
51 internal int margin_right
;
53 private StringBuilder rtf_line
;
55 private RtfSectionStyle rtf_style
; // Replaces individual style
56 // properties so we can revert
57 private Stack rtf_section_stack
;
59 private RTF
.TextMap rtf_text_map
;
60 private int rtf_skip_count
;
61 private int rtf_cursor_x
;
62 private int rtf_cursor_y
;
63 private int rtf_chars
;
66 private bool enable_auto_drag_drop
;
67 private RichTextBoxLanguageOptions language_option
;
68 private bool rich_text_shortcuts_enabled
;
69 private Color selection_back_color
;
71 #endregion // Local Variables
73 #region Public Constructors
74 public RichTextBox() {
75 accepts_return
= true;
77 auto_word_select
= false;
79 base.MaxLength
= Int32
.MaxValue
;
82 base.Multiline
= true;
83 document
.CRLFSize
= 1;
84 shortcuts_enabled
= true;
85 base.EnableLinks
= true;
88 rtf_style
= new RtfSectionStyle ();
89 rtf_section_stack
= null;
91 scrollbars
= RichTextBoxScrollBars
.Both
;
92 alignment
= HorizontalAlignment
.Left
;
93 LostFocus
+= new EventHandler(RichTextBox_LostFocus
);
94 GotFocus
+= new EventHandler(RichTextBox_GotFocus
);
95 BackColor
= ThemeEngine
.Current
.ColorWindow
;
97 backcolor_set
= false;
98 language_option
= RichTextBoxLanguageOptions
.AutoFontSizeAdjust
;
99 rich_text_shortcuts_enabled
= true;
100 selection_back_color
= DefaultBackColor
;
102 ForeColor
= ThemeEngine
.Current
.ColorWindowText
;
104 base.HScrolled
+= new EventHandler(RichTextBox_HScrolled
);
105 base.VScrolled
+= new EventHandler(RichTextBox_VScrolled
);
108 SetStyle (ControlStyles
.StandardDoubleClick
, false);
111 #endregion // Public Constructors
113 #region Private & Internal Methods
115 internal override void HandleLinkClicked (LinkRectangle link
)
117 OnLinkClicked (new LinkClickedEventArgs (link
.LinkTag
.LinkText
));
120 internal override Color
ChangeBackColor (Color backColor
)
122 if (backColor
== Color
.Empty
) {
124 backcolor_set
= false;
126 backColor
= SystemColors
.Window
;
129 backColor
= SystemColors
.Window
;
135 internal override void RaiseSelectionChanged()
137 OnSelectionChanged (EventArgs
.Empty
);
140 private void RichTextBox_LostFocus(object sender
, EventArgs e
) {
144 private void RichTextBox_GotFocus(object sender
, EventArgs e
) {
147 #endregion // Private & Internal Methods
149 #region Public Instance Properties
153 public override bool AllowDrop
{
155 return base.AllowDrop
;
159 base.AllowDrop
= value;
163 [DefaultValue(false)]
165 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Visible
)]
166 [RefreshProperties (RefreshProperties
.Repaint
)]
167 [EditorBrowsable (EditorBrowsableState
.Never
)]
172 public override bool AutoSize
{
178 base.AutoSize
= value;
182 [MonoTODO ("Value not respected, always true")]
183 [DefaultValue(false)]
184 public bool AutoWordSelection
{
185 get { return auto_word_select; }
186 set { auto_word_select = value; }
190 [EditorBrowsable(EditorBrowsableState
.Never
)]
191 public override System
.Drawing
.Image BackgroundImage
{
192 get { return base.BackgroundImage; }
193 set { base.BackgroundImage = value; }
198 [EditorBrowsable (EditorBrowsableState
.Never
)]
199 public override ImageLayout BackgroundImageLayout
{
200 get { return base.BackgroundImageLayout; }
201 set { base.BackgroundImageLayout = value; }
207 public int BulletIndent
{
209 return bullet_indent
;
213 bullet_indent
= value;
218 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
219 public bool CanRedo
{
221 return document
.undo
.CanRedo
;
226 public bool DetectUrls
{
227 get { return base.EnableLinks; }
228 set { base.EnableLinks = value; }
233 [DefaultValue (false)]
234 public bool EnableAutoDragDrop
{
235 get { return enable_auto_drag_drop; }
236 set { enable_auto_drag_drop = value; }
240 public override Font Font
{
251 if (PreferredHeight
!= Height
) {
252 Height
= PreferredHeight
;
258 // Font changes always set the whole doc to that font
259 start
= document
.GetLine(1);
260 end
= document
.GetLine(document
.Lines
);
261 document
.FormatText(start
, 1, end
, end
.text
.Length
+ 1, base.Font
, Color
.Empty
, Color
.Empty
, FormatSpecified
.Font
);
266 public override Color ForeColor
{
268 return base.ForeColor
;
272 base.ForeColor
= value;
279 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
280 public RichTextBoxLanguageOptions LanguageOption
{
281 get { return language_option; }
282 set { language_option = value; }
286 [DefaultValue(Int32
.MaxValue
)]
287 public override int MaxLength
{
288 get { return base.MaxLength; }
289 set { base.MaxLength = value; }
293 public override bool Multiline
{
295 return base.Multiline
;
299 base.Multiline
= value;
304 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
306 public string RedoActionName
{
308 return document
.undo
.RedoActionName
;
315 [DefaultValue (true)]
316 [EditorBrowsable (EditorBrowsableState
.Never
)]
317 public bool RichTextShortcutsEnabled
{
318 get { return rich_text_shortcuts_enabled; }
319 set { rich_text_shortcuts_enabled = value; }
325 [MonoTODO("Teach TextControl.RecalculateLine to consider the right margin as well")]
326 public int RightMargin
{
332 margin_right
= value;
337 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
339 [RefreshProperties (RefreshProperties
.All
)]
348 start_line
= document
.GetLine(1);
349 end_line
= document
.GetLine(document
.Lines
);
350 return GenerateRTF(start_line
, 0, end_line
, end_line
.text
.Length
).ToString();
357 data
= new MemoryStream(Encoding
.ASCII
.GetBytes(value), false);
359 InsertRTFFromStream(data
, 0, 1);
367 [DefaultValue(RichTextBoxScrollBars
.Both
)]
369 public RichTextBoxScrollBars ScrollBars
{
375 if (!Enum
.IsDefined (typeof (RichTextBoxScrollBars
), value))
376 throw new InvalidEnumArgumentException ("value", (int) value,
377 typeof (RichTextBoxScrollBars
));
379 if (value != scrollbars
) {
381 CalculateDocument ();
388 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
389 public string SelectedRtf
{
391 return GenerateRTF(document
.selection_start
.line
, document
.selection_start
.pos
, document
.selection_end
.line
, document
.selection_end
.pos
).ToString();
403 if (document
.selection_visible
) {
404 document
.ReplaceSelection("", false);
407 sel_start
= document
.LineTagToCharIndex(document
.selection_start
.line
, document
.selection_start
.pos
);
409 data
= new MemoryStream(Encoding
.ASCII
.GetBytes(value), false);
410 InsertRTFFromStream(data
, document
.selection_start
.pos
, document
.selection_start
.line
.line_no
, out x
, out y
, out chars
);
413 document
.CharIndexToLineTag(sel_start
+ chars
+ (y
- document
.selection_start
.line
.line_no
) * 2, out line
, out tag
, out sel_start
);
414 document
.SetSelection(line
, sel_start
);
415 document
.PositionCaret(line
, sel_start
);
416 document
.DisplayCaret();
418 OnTextChanged(EventArgs
.Empty
);
424 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
425 public override string SelectedText
{
427 return base.SelectedText
;
431 base.SelectedText
= value;
436 [DefaultValue(HorizontalAlignment
.Left
)]
437 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
438 public HorizontalAlignment SelectionAlignment
{
440 HorizontalAlignment align
;
445 start
= document
.ParagraphStart(document
.selection_start
.line
);
446 align
= start
.alignment
;
448 end
= document
.ParagraphEnd(document
.selection_end
.line
);
453 if (line
.alignment
!= align
) {
454 return HorizontalAlignment
.Left
;
460 line
= document
.GetLine(line
.line_no
+ 1);
471 start
= document
.ParagraphStart(document
.selection_start
.line
);
473 end
= document
.ParagraphEnd(document
.selection_end
.line
);
478 line
.alignment
= value;
483 line
= document
.GetLine(line
.line_no
+ 1);
485 this.CalculateDocument();
492 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
493 public Color SelectionBackColor
{
494 get { return selection_back_color; }
495 set { selection_back_color = value; }
500 [DefaultValue(false)]
501 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
503 public bool SelectionBullet
{
514 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
516 public int SelectionCharOffset
{
526 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
527 public Color SelectionColor
{
534 if (selection_length
> 0) {
535 start
= document
.selection_start
.line
.FindTag (document
.selection_start
.pos
+ 1);
536 end
= document
.selection_start
.line
.FindTag (document
.selection_end
.pos
);
538 start
= document
.selection_start
.line
.FindTag (document
.selection_start
.pos
);
545 while (tag
!= null) {
547 if (!color
.Equals (tag
.Color
))
553 tag
= document
.NextTag (tag
);
560 if (value == Color
.Empty
)
561 value = DefaultForeColor
;
566 sel_start
= document
.LineTagToCharIndex(document
.selection_start
.line
, document
.selection_start
.pos
);
567 sel_end
= document
.LineTagToCharIndex(document
.selection_end
.line
, document
.selection_end
.pos
);
569 document
.FormatText (document
.selection_start
.line
, document
.selection_start
.pos
+ 1,
570 document
.selection_end
.line
, document
.selection_end
.pos
+ 1, null,
571 value, Color
.Empty
, FormatSpecified
.Color
);
573 document
.CharIndexToLineTag(sel_start
, out document
.selection_start
.line
, out document
.selection_start
.tag
, out document
.selection_start
.pos
);
574 document
.CharIndexToLineTag(sel_end
, out document
.selection_end
.line
, out document
.selection_end
.tag
, out document
.selection_end
.pos
);
576 document
.UpdateView(document
.selection_start
.line
, 0);
578 //Re-Align the caret in case its changed size or position
579 //probably not necessary here
580 document
.AlignCaret(false);
585 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
586 public Font SelectionFont
{
593 if (selection_length
> 0) {
594 start
= document
.selection_start
.line
.FindTag (document
.selection_start
.pos
+ 1);
595 end
= document
.selection_start
.line
.FindTag (document
.selection_end
.pos
);
597 start
= document
.selection_start
.line
.FindTag (document
.selection_start
.pos
);
603 if (selection_length
> 1) {
605 while (tag
!= null) {
607 if (!font
.Equals(tag
.Font
))
613 tag
= document
.NextTag (tag
);
624 sel_start
= document
.LineTagToCharIndex(document
.selection_start
.line
, document
.selection_start
.pos
);
625 sel_end
= document
.LineTagToCharIndex(document
.selection_end
.line
, document
.selection_end
.pos
);
627 document
.FormatText (document
.selection_start
.line
, document
.selection_start
.pos
+ 1,
628 document
.selection_end
.line
, document
.selection_end
.pos
+ 1, value,
629 Color
.Empty
, Color
.Empty
, FormatSpecified
.Font
);
631 document
.CharIndexToLineTag(sel_start
, out document
.selection_start
.line
, out document
.selection_start
.tag
, out document
.selection_start
.pos
);
632 document
.CharIndexToLineTag(sel_end
, out document
.selection_end
.line
, out document
.selection_end
.tag
, out document
.selection_end
.pos
);
634 document
.UpdateView(document
.selection_start
.line
, 0);
635 //Re-Align the caret in case its changed size or position
636 Document
.AlignCaret (false);
643 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
645 public int SelectionHangingIndent
{
656 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
658 public int SelectionIndent
{
668 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
669 public override int SelectionLength
{
671 return base.SelectionLength
;
675 base.SelectionLength
= value;
680 [DefaultValue(false)]
681 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
683 public bool SelectionProtected
{
694 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
696 public int SelectionRightIndent
{
706 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
708 public int[] SelectionTabs
{
718 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
719 public RichTextBoxSelectionTypes SelectionType
{
721 if (document
.selection_start
== document
.selection_end
) {
722 return RichTextBoxSelectionTypes
.Empty
;
726 if (SelectedText
.Length
> 1) {
727 return RichTextBoxSelectionTypes
.MultiChar
| RichTextBoxSelectionTypes
.Text
;
730 return RichTextBoxSelectionTypes
.Text
;
734 [DefaultValue(false)]
736 public bool ShowSelectionMargin
{
747 [RefreshProperties (RefreshProperties
.All
)]
749 public override string Text
{
760 public override int TextLength
{
762 return base.TextLength
;
767 [DesignerSerializationVisibility(DesignerSerializationVisibility
.Hidden
)]
768 public string UndoActionName
{
770 return document
.undo
.UndoActionName
;
776 public float ZoomFactor
{
785 #endregion // Public Instance Properties
787 #region Protected Instance Properties
788 protected override CreateParams CreateParams
{
790 return base.CreateParams
;
794 protected override Size DefaultSize
{
796 return new Size(100, 96);
799 #endregion // Protected Instance Properties
801 #region Public Instance Methods
802 public bool CanPaste(DataFormats
.Format clipFormat
) {
803 if ((clipFormat
.Name
== DataFormats
.Rtf
) ||
804 (clipFormat
.Name
== DataFormats
.Text
) ||
805 (clipFormat
.Name
== DataFormats
.UnicodeText
)) {
811 public int Find(char[] characterSet
) {
812 return Find(characterSet
, -1, -1);
815 public int Find(char[] characterSet
, int start
) {
816 return Find(characterSet
, start
, -1);
819 public int Find(char[] characterSet
, int start
, int end
) {
820 Document
.Marker start_mark
;
821 Document
.Marker end_mark
;
822 Document
.Marker result
;
825 document
.GetMarker(out start_mark
, true);
831 start_mark
= new Document
.Marker();
833 document
.CharIndexToLineTag(start
, out line
, out tag
, out pos
);
834 start_mark
.line
= line
;
835 start_mark
.tag
= tag
;
836 start_mark
.pos
= pos
;
840 document
.GetMarker(out end_mark
, false);
846 end_mark
= new Document
.Marker();
848 document
.CharIndexToLineTag(end
, out line
, out tag
, out pos
);
849 end_mark
.line
= line
;
854 if (document
.FindChars(characterSet
, start_mark
, end_mark
, out result
)) {
855 return document
.LineTagToCharIndex(result
.line
, result
.pos
);
861 public int Find(string str
) {
862 return Find(str
, -1, -1, RichTextBoxFinds
.None
);
865 public int Find(string str
, int start
, int end
, RichTextBoxFinds options
) {
866 Document
.Marker start_mark
;
867 Document
.Marker end_mark
;
868 Document
.Marker result
;
871 document
.GetMarker(out start_mark
, true);
877 start_mark
= new Document
.Marker();
879 document
.CharIndexToLineTag(start
, out line
, out tag
, out pos
);
881 start_mark
.line
= line
;
882 start_mark
.tag
= tag
;
883 start_mark
.pos
= pos
;
887 document
.GetMarker(out end_mark
, false);
893 end_mark
= new Document
.Marker();
895 document
.CharIndexToLineTag(end
, out line
, out tag
, out pos
);
897 end_mark
.line
= line
;
902 if (document
.Find(str
, start_mark
, end_mark
, out result
, options
)) {
903 return document
.LineTagToCharIndex(result
.line
, result
.pos
);
909 public int Find(string str
, int start
, RichTextBoxFinds options
) {
910 return Find(str
, start
, -1, options
);
913 public int Find(string str
, RichTextBoxFinds options
) {
914 return Find(str
, -1, -1, options
);
919 public char GetCharFromPosition(Point pt
) {
923 PointToTagPos(pt
, out tag
, out pos
);
925 if (pos
>= tag
.Line
.text
.Length
) {
929 return tag
.Line
.text
[pos
];
932 internal override char GetCharFromPositionInternal (Point p
)
937 PointToTagPos (p
, out tag
, out pos
);
939 if (pos
>= tag
.Line
.text
.Length
)
942 return tag
.Line
.text
[pos
];
950 int GetCharIndexFromPosition(Point pt
) {
954 PointToTagPos(pt
, out tag
, out pos
);
956 return document
.LineTagToCharIndex(tag
.Line
, pos
);
963 int GetLineFromCharIndex(int index
) {
968 document
.CharIndexToLineTag(index
, out line
, out tag
, out pos
);
970 return line
.LineNo
- 1;
977 Point
GetPositionFromCharIndex(int index
) {
982 document
.CharIndexToLineTag(index
, out line
, out tag
, out pos
);
983 return new Point(line
.X
+ (int)line
.widths
[pos
] + document
.OffsetX
- document
.ViewPortX
,
984 line
.Y
+ document
.OffsetY
- document
.ViewPortY
);
987 public void LoadFile(System
.IO
.Stream data
, RichTextBoxStreamType fileType
) {
991 // FIXME - ignoring unicode
992 if (fileType
== RichTextBoxStreamType
.PlainText
) {
997 sb
= new StringBuilder ((int) data
.Length
);
998 buffer
= new char [1024];
1000 throw new IOException("Not enough memory to load document");
1003 StreamReader sr
= new StreamReader (data
, Encoding
.Default
, true);
1004 int charsRead
= sr
.Read (buffer
, 0, buffer
.Length
);
1005 while (charsRead
> 0) {
1006 sb
.Append (buffer
, 0, charsRead
);
1007 charsRead
= sr
.Read (buffer
, 0, buffer
.Length
);
1009 base.Text
= sb
.ToString();
1013 InsertRTFFromStream(data
, 0, 1);
1015 document
.PositionCaret (document
.GetLine (1), 0);
1016 document
.SetSelectionToCaret (true);
1020 [MonoTODO("Make smarter RTF detection?")]
1021 public void LoadFile(string path
) {
1022 if (path
.EndsWith(".rtf")) {
1023 LoadFile(path
, RichTextBoxStreamType
.RichText
);
1025 LoadFile(path
, RichTextBoxStreamType
.PlainText
);
1029 public void LoadFile(string path
, RichTextBoxStreamType fileType
) {
1036 data
= new FileStream(path
, FileMode
.Open
, FileAccess
.Read
, FileShare
.Read
, 1024);
1038 LoadFile(data
, fileType
);
1041 catch (Exception ex
) {
1042 throw new IOException("Could not open file " + path
, ex
);
1052 public void Paste(DataFormats
.Format clipFormat
) {
1053 base.Paste(Clipboard
.GetDataObject(), clipFormat
, false);
1058 if (document
.undo
.Redo ())
1059 OnTextChanged (EventArgs
.Empty
);
1062 public void SaveFile(Stream data
, RichTextBoxStreamType fileType
) {
1068 if (fileType
== RichTextBoxStreamType
.UnicodePlainText
) {
1069 encoding
= Encoding
.Unicode
;
1071 encoding
= Encoding
.ASCII
;
1075 case RichTextBoxStreamType
.PlainText
:
1076 case RichTextBoxStreamType
.TextTextOleObjs
:
1077 case RichTextBoxStreamType
.UnicodePlainText
: {
1079 bytes
= encoding
.GetBytes(document
.Root
.text
.ToString());
1080 data
.Write(bytes
, 0, bytes
.Length
);
1084 for (i
= 1; i
< document
.Lines
; i
++) {
1085 bytes
= encoding
.GetBytes(document
.GetLine(i
).text
.ToString() + Environment
.NewLine
);
1086 data
.Write(bytes
, 0, bytes
.Length
);
1088 bytes
= encoding
.GetBytes(document
.GetLine(document
.Lines
).text
.ToString());
1089 data
.Write(bytes
, 0, bytes
.Length
);
1094 // If we're here we're saving RTF
1101 start_line
= document
.GetLine(1);
1102 end_line
= document
.GetLine(document
.Lines
);
1103 rtf
= GenerateRTF(start_line
, 0, end_line
, end_line
.text
.Length
);
1105 bytes
= new Byte
[4096];
1107 // Let's chunk it so we don't use up all memory...
1108 for (i
= 0; i
< total
; i
+= 1024) {
1109 if ((i
+ 1024) < total
) {
1110 current
= encoding
.GetBytes(rtf
.ToString(i
, 1024), 0, 1024, bytes
, 0);
1112 current
= total
- i
;
1113 current
= encoding
.GetBytes(rtf
.ToString(i
, current
), 0, current
, bytes
, 0);
1115 data
.Write(bytes
, 0, current
);
1119 public void SaveFile(string path
) {
1120 if (path
.EndsWith(".rtf")) {
1121 SaveFile(path
, RichTextBoxStreamType
.RichText
);
1123 SaveFile(path
, RichTextBoxStreamType
.PlainText
);
1127 public void SaveFile(string path
, RichTextBoxStreamType fileType
) {
1133 data
= new FileStream(path
, FileMode
.Create
, FileAccess
.Write
, FileShare
.None
, 1024, false);
1134 SaveFile(data
, fileType
);
1138 // throw new IOException("Could not write document to file " + path);
1149 [EditorBrowsable (EditorBrowsableState
.Never
)]
1150 public new void DrawToBitmap (Bitmap bitmap
, Rectangle targetBounds
)
1152 Graphics dc
= Graphics
.FromImage (bitmap
);
1154 Draw (dc
, targetBounds
);
1158 #endregion // Public Instance Methods
1160 #region Protected Instance Methods
1161 protected virtual object CreateRichEditOleCallback() {
1162 throw new NotImplementedException();
1165 protected override void OnBackColorChanged(EventArgs e
) {
1166 base.OnBackColorChanged (e
);
1169 protected virtual void OnContentsResized(ContentsResizedEventArgs e
) {
1170 ContentsResizedEventHandler eh
= (ContentsResizedEventHandler
)(Events
[ContentsResizedEvent
]);
1175 protected override void OnContextMenuChanged(EventArgs e
) {
1176 base.OnContextMenuChanged (e
);
1179 protected override void OnHandleCreated(EventArgs e
) {
1180 base.OnHandleCreated (e
);
1183 protected override void OnHandleDestroyed(EventArgs e
) {
1184 base.OnHandleDestroyed (e
);
1187 protected virtual void OnHScroll(EventArgs e
) {
1188 EventHandler eh
= (EventHandler
)(Events
[HScrollEvent
]);
1193 [MonoTODO("Determine when to call this")]
1194 protected virtual void OnImeChange(EventArgs e
) {
1195 EventHandler eh
= (EventHandler
)(Events
[ImeChangeEvent
]);
1200 protected virtual void OnLinkClicked(LinkClickedEventArgs e
) {
1201 LinkClickedEventHandler eh
= (LinkClickedEventHandler
)(Events
[LinkClickedEvent
]);
1206 protected virtual void OnProtected(EventArgs e
) {
1207 EventHandler eh
= (EventHandler
)(Events
[ProtectedEvent
]);
1212 protected override void OnRightToLeftChanged(EventArgs e
) {
1213 base.OnRightToLeftChanged (e
);
1216 protected virtual void OnSelectionChanged(EventArgs e
) {
1217 EventHandler eh
= (EventHandler
)(Events
[SelectionChangedEvent
]);
1223 protected override void OnSystemColorsChanged(EventArgs e
) {
1224 base.OnSystemColorsChanged (e
);
1227 protected override void OnTextChanged(EventArgs e
) {
1228 base.OnTextChanged (e
);
1232 protected virtual void OnVScroll(EventArgs e
) {
1233 EventHandler eh
= (EventHandler
)(Events
[VScrollEvent
]);
1238 protected override void WndProc(ref Message m
) {
1239 base.WndProc (ref m
);
1243 protected override bool ProcessCmdKey (ref Message m
, Keys keyData
)
1245 return base.ProcessCmdKey (ref m
, keyData
);
1248 #endregion // Protected Instance Methods
1251 static object ContentsResizedEvent
= new object ();
1252 static object HScrollEvent
= new object ();
1253 static object ImeChangeEvent
= new object ();
1254 static object LinkClickedEvent
= new object ();
1255 static object ProtectedEvent
= new object ();
1256 static object SelectionChangedEvent
= new object ();
1257 static object VScrollEvent
= new object ();
1260 [EditorBrowsable(EditorBrowsableState
.Never
)]
1261 public new event EventHandler BackgroundImageChanged
{
1262 add { base.BackgroundImageChanged += value; }
1263 remove { base.BackgroundImageChanged -= value; }
1268 [EditorBrowsable (EditorBrowsableState
.Never
)]
1269 public new event EventHandler BackgroundImageLayoutChanged
{
1270 add { base.BackgroundImageLayoutChanged += value; }
1271 remove { base.BackgroundImageLayoutChanged -= value; }
1275 public event ContentsResizedEventHandler ContentsResized
{
1276 add { Events.AddHandler (ContentsResizedEvent, value); }
1277 remove { Events.RemoveHandler (ContentsResizedEvent, value); }
1282 [EditorBrowsable(EditorBrowsableState
.Never
)]
1283 public new event EventHandler DoubleClick
{
1284 add { base.DoubleClick += value; }
1285 remove { base.DoubleClick -= value; }
1291 [EditorBrowsable(EditorBrowsableState
.Never
)]
1293 public new event DragEventHandler DragDrop
{
1294 add { base.DragDrop += value; }
1295 remove { base.DragDrop -= value; }
1300 [EditorBrowsable(EditorBrowsableState
.Never
)]
1302 public new event DragEventHandler DragEnter
{
1303 add { base.DragEnter += value; }
1304 remove { base.DragEnter -= value; }
1308 [EditorBrowsable(EditorBrowsableState
.Never
)]
1309 public new event EventHandler DragLeave
{
1310 add { base.DragLeave += value; }
1311 remove { base.DragLeave -= value; }
1316 [EditorBrowsable(EditorBrowsableState
.Never
)]
1317 public new event DragEventHandler DragOver
{
1318 add { base.DragOver += value; }
1319 remove { base.DragOver -= value; }
1324 [EditorBrowsable(EditorBrowsableState
.Never
)]
1325 public new event GiveFeedbackEventHandler GiveFeedback
{
1326 add { base.GiveFeedback += value; }
1327 remove { base.GiveFeedback -= value; }
1330 public event EventHandler HScroll
{
1331 add { Events.AddHandler (HScrollEvent, value); }
1332 remove { Events.RemoveHandler (HScrollEvent, value); }
1335 public event EventHandler ImeChange
{
1336 add { Events.AddHandler (ImeChangeEvent, value); }
1337 remove { Events.RemoveHandler (ImeChangeEvent, value); }
1340 public event LinkClickedEventHandler LinkClicked
{
1341 add { Events.AddHandler (LinkClickedEvent, value); }
1342 remove { Events.RemoveHandler (LinkClickedEvent, value); }
1345 public event EventHandler Protected
{
1346 add { Events.AddHandler (ProtectedEvent, value); }
1347 remove { Events.RemoveHandler (ProtectedEvent, value); }
1351 [EditorBrowsable(EditorBrowsableState
.Never
)]
1352 public new event QueryContinueDragEventHandler QueryContinueDrag
{
1353 add { base.QueryContinueDrag += value; }
1354 remove { base.QueryContinueDrag -= value; }
1357 [MonoTODO("Currently does not ever fire")]
1358 public event EventHandler SelectionChanged
{
1359 add { Events.AddHandler (SelectionChangedEvent, value); }
1360 remove { Events.RemoveHandler (SelectionChangedEvent, value); }
1363 public event EventHandler VScroll
{
1364 add { Events.AddHandler (VScrollEvent, value); }
1365 remove { Events.RemoveHandler (VScrollEvent, value); }
1367 #endregion // Events
1369 #region Private Methods
1371 internal override void SelectWord ()
1373 document
.ExpandSelection(CaretSelection
.Word
, false);
1376 private class RtfSectionStyle
: ICloneable
{
1377 internal Color rtf_color
;
1378 internal RTF
.Font rtf_rtffont
;
1379 internal int rtf_rtffont_size
;
1380 internal FontStyle rtf_rtfstyle
;
1381 internal HorizontalAlignment rtf_rtfalign
;
1382 internal int rtf_par_line_left_indent
;
1383 internal bool rtf_visible
;
1384 internal int rtf_skip_width
;
1386 public object Clone ()
1388 RtfSectionStyle new_style
= new RtfSectionStyle ();
1390 new_style
.rtf_color
= rtf_color
;
1391 new_style
.rtf_par_line_left_indent
= rtf_par_line_left_indent
;
1392 new_style
.rtf_rtfalign
= rtf_rtfalign
;
1393 new_style
.rtf_rtffont
= rtf_rtffont
;
1394 new_style
.rtf_rtffont_size
= rtf_rtffont_size
;
1395 new_style
.rtf_rtfstyle
= rtf_rtfstyle
;
1396 new_style
.rtf_visible
= rtf_visible
;
1397 new_style
.rtf_skip_width
= rtf_skip_width
;
1403 // To allow us to keep track of the sections and revert formatting
1404 // as we go in and out of sections of the document.
1405 private void HandleGroup (RTF
.RTF rtf
)
1407 //start group - save the current formatting on to a stack
1408 //end group - go back to the formatting at the current group
1409 if (rtf_section_stack
== null) {
1410 rtf_section_stack
= new Stack ();
1413 if (rtf
.Major
== RTF
.Major
.BeginGroup
) {
1414 rtf_section_stack
.Push (rtf_style
.Clone ());
1415 //spec specifies resetting unicode ignore at begin group as an attempt at error
1418 } else if (rtf
.Major
== RTF
.Major
.EndGroup
) {
1419 if (rtf_section_stack
.Count
> 0) {
1420 FlushText (rtf
, false);
1422 rtf_style
= (RtfSectionStyle
) rtf_section_stack
.Pop ();
1427 [MonoTODO("Add QuadJust support for justified alignment")]
1428 private void HandleControl(RTF
.RTF rtf
) {
1430 case RTF
.Major
.Unicode
: {
1432 case RTF
.Minor
.UnicodeCharBytes
: {
1433 rtf_style
.rtf_skip_width
= rtf
.Param
;
1437 case RTF
.Minor
.UnicodeChar
: {
1438 FlushText (rtf
, false);
1439 rtf_skip_count
+= rtf_style
.rtf_skip_width
;
1440 rtf_line
.Append((char)rtf
.Param
);
1447 case RTF
.Major
.Destination
: {
1448 // Console.Write("[Got Destination control {0}]", rtf.Minor);
1453 case RTF
.Major
.PictAttr
:
1454 if (rtf
.Picture
!= null && rtf
.Picture
.IsValid ()) {
1455 Line line
= document
.GetLine (rtf_cursor_y
);
1456 document
.InsertPicture (line
, 0, rtf
.Picture
);
1459 FlushText (rtf
, true);
1464 case RTF
.Major
.CharAttr
: {
1466 case RTF
.Minor
.ForeColor
: {
1467 System
.Windows
.Forms
.RTF
.Color color
;
1469 color
= System
.Windows
.Forms
.RTF
.Color
.GetColor(rtf
, rtf
.Param
);
1471 if (color
!= null) {
1472 FlushText(rtf
, false);
1473 if (color
.Red
== -1 && color
.Green
== -1 && color
.Blue
== -1) {
1474 this.rtf_style
.rtf_color
= ForeColor
;
1476 this.rtf_style
.rtf_color
= Color
.FromArgb(color
.Red
, color
.Green
, color
.Blue
);
1478 FlushText (rtf
, false);
1483 case RTF
.Minor
.FontSize
: {
1484 FlushText(rtf
, false);
1485 this.rtf_style
.rtf_rtffont_size
= rtf
.Param
/ 2;
1489 case RTF
.Minor
.FontNum
: {
1490 System
.Windows
.Forms
.RTF
.Font font
;
1492 font
= System
.Windows
.Forms
.RTF
.Font
.GetFont(rtf
, rtf
.Param
);
1494 FlushText(rtf
, false);
1495 this.rtf_style
.rtf_rtffont
= font
;
1500 case RTF
.Minor
.Plain
: {
1501 FlushText(rtf
, false);
1502 rtf_style
.rtf_rtfstyle
= FontStyle
.Regular
;
1506 case RTF
.Minor
.Bold
: {
1507 FlushText(rtf
, false);
1508 if (rtf
.Param
== RTF
.RTF
.NoParam
) {
1509 rtf_style
.rtf_rtfstyle
|= FontStyle
.Bold
;
1511 rtf_style
.rtf_rtfstyle
&= ~FontStyle
.Bold
;
1516 case RTF
.Minor
.Italic
: {
1517 FlushText(rtf
, false);
1518 if (rtf
.Param
== RTF
.RTF
.NoParam
) {
1519 rtf_style
.rtf_rtfstyle
|= FontStyle
.Italic
;
1521 rtf_style
.rtf_rtfstyle
&= ~FontStyle
.Italic
;
1526 case RTF
.Minor
.StrikeThru
: {
1527 FlushText(rtf
, false);
1528 if (rtf
.Param
== RTF
.RTF
.NoParam
) {
1529 rtf_style
.rtf_rtfstyle
|= FontStyle
.Strikeout
;
1531 rtf_style
.rtf_rtfstyle
&= ~FontStyle
.Strikeout
;
1536 case RTF
.Minor
.Underline
: {
1537 FlushText(rtf
, false);
1538 if (rtf
.Param
== RTF
.RTF
.NoParam
) {
1539 rtf_style
.rtf_rtfstyle
|= FontStyle
.Underline
;
1541 rtf_style
.rtf_rtfstyle
= rtf_style
.rtf_rtfstyle
& ~FontStyle
.Underline
;
1546 case RTF
.Minor
.Invisible
: {
1547 FlushText (rtf
, false);
1548 rtf_style
.rtf_visible
= false;
1552 case RTF
.Minor
.NoUnderline
: {
1553 FlushText(rtf
, false);
1554 rtf_style
.rtf_rtfstyle
&= ~FontStyle
.Underline
;
1561 case RTF
.Major
.ParAttr
: {
1562 switch (rtf
.Minor
) {
1564 case RTF
.Minor
.ParDef
:
1565 FlushText (rtf
, false);
1566 rtf_style
.rtf_par_line_left_indent
= 0;
1567 rtf_style
.rtf_rtfalign
= HorizontalAlignment
.Left
;
1570 case RTF
.Minor
.LeftIndent
:
1571 rtf_style
.rtf_par_line_left_indent
= (int) (((float) rtf
.Param
/ 1440.0F
) * CreateGraphics ().DpiX
+ 0.5F
);
1574 case RTF
.Minor
.QuadCenter
:
1575 FlushText (rtf
, false);
1576 rtf_style
.rtf_rtfalign
= HorizontalAlignment
.Center
;
1579 case RTF
.Minor
.QuadJust
:
1580 FlushText (rtf
, false);
1581 rtf_style
.rtf_rtfalign
= HorizontalAlignment
.Center
;
1584 case RTF
.Minor
.QuadLeft
:
1585 FlushText (rtf
, false);
1586 rtf_style
.rtf_rtfalign
= HorizontalAlignment
.Left
;
1589 case RTF
.Minor
.QuadRight
:
1590 FlushText (rtf
, false);
1591 rtf_style
.rtf_rtfalign
= HorizontalAlignment
.Right
;
1597 case RTF
.Major
.SpecialChar
: {
1598 //Console.Write("[Got SpecialChar control {0}]", rtf.Minor);
1605 private void SpecialChar(RTF
.RTF rtf
) {
1607 case RTF
.Minor
.Page
:
1608 case RTF
.Minor
.Sect
:
1610 case RTF
.Minor
.Line
:
1611 case RTF
.Minor
.Par
: {
1612 FlushText(rtf
, true);
1616 case RTF
.Minor
.Cell
: {
1621 case RTF
.Minor
.NoBrkSpace
: {
1626 case RTF
.Minor
.Tab
: {
1627 rtf_line
.Append ("\t");
1628 // FlushText (rtf, false);
1632 case RTF
.Minor
.NoReqHyphen
:
1633 case RTF
.Minor
.NoBrkHyphen
: {
1634 rtf_line
.Append ("-");
1635 // FlushText (rtf, false);
1639 case RTF
.Minor
.Bullet
: {
1640 Console
.WriteLine("*");
1644 case RTF
.Minor
.WidowCtrl
:
1647 case RTF
.Minor
.EmDash
: {
1648 rtf_line
.Append ("\u2014");
1652 case RTF
.Minor
.EnDash
: {
1653 rtf_line
.Append ("\u2013");
1657 case RTF.Minor.LQuote: {
1658 Console.Write("\u2018");
1662 case RTF.Minor.RQuote: {
1663 Console.Write("\u2019");
1667 case RTF.Minor.LDblQuote: {
1668 Console.Write("\u201C");
1672 case RTF.Minor.RDblQuote: {
1673 Console.Write("\u201D");
1678 // Console.WriteLine ("skipped special char: {0}", rtf.Minor);
1685 private void HandleText(RTF
.RTF rtf
) {
1686 string str
= rtf
.EncodedText
;
1688 //todo - simplistically skips characters, should skip bytes?
1689 if (rtf_skip_count
> 0 && str
.Length
> 0) {
1690 int iToRemove
= Math
.Min (rtf_skip_count
, str
.Length
);
1692 str
= str
.Substring (iToRemove
);
1693 rtf_skip_count
-=iToRemove
;
1697 if ((RTF.StandardCharCode)rtf.Minor != RTF.StandardCharCode.nothing) {
1698 rtf_line.Append(rtf_text_map[(RTF.StandardCharCode)rtf.Minor]);
1700 if ((int)rtf.Major > 31 && (int)rtf.Major < 128) {
1701 rtf_line.Append((char)rtf.Major);
1703 //rtf_line.Append((char)rtf.Major);
1704 Console.Write("[Literal:0x{0:X2}]", (int)rtf.Major);
1709 if (rtf_style
.rtf_visible
)
1710 rtf_line
.Append (str
);
1713 private void FlushText(RTF
.RTF rtf
, bool newline
) {
1717 length
= rtf_line
.Length
;
1718 if (!newline
&& (length
== 0)) {
1722 if (rtf_style
.rtf_rtffont
== null) {
1723 // First font in table is default
1724 rtf_style
.rtf_rtffont
= System
.Windows
.Forms
.RTF
.Font
.GetFont (rtf
, 0);
1727 font
= new Font (rtf_style
.rtf_rtffont
.Name
, rtf_style
.rtf_rtffont_size
, rtf_style
.rtf_rtfstyle
);
1729 if (rtf_style
.rtf_color
== Color
.Empty
) {
1730 System
.Windows
.Forms
.RTF
.Color color
;
1732 // First color in table is default
1733 color
= System
.Windows
.Forms
.RTF
.Color
.GetColor (rtf
, 0);
1735 if ((color
== null) || (color
.Red
== -1 && color
.Green
== -1 && color
.Blue
== -1)) {
1736 rtf_style
.rtf_color
= ForeColor
;
1738 rtf_style
.rtf_color
= Color
.FromArgb (color
.Red
, color
.Green
, color
.Blue
);
1743 rtf_chars
+= rtf_line
.Length
;
1747 if (rtf_cursor_x
== 0) {
1748 if (newline
&& rtf_line
.ToString ().EndsWith ("\n") == false)
1749 rtf_line
.Append ("\n");
1751 document
.Add (rtf_cursor_y
, rtf_line
.ToString (), rtf_style
.rtf_rtfalign
, font
, rtf_style
.rtf_color
,
1752 newline
? LineEnding
.Rich
: LineEnding
.Wrap
);
1753 if (rtf_style
.rtf_par_line_left_indent
!= 0) {
1754 Line line
= document
.GetLine (rtf_cursor_y
);
1755 line
.indent
= rtf_style
.rtf_par_line_left_indent
;
1760 line
= document
.GetLine (rtf_cursor_y
);
1761 line
.indent
= rtf_style
.rtf_par_line_left_indent
;
1762 if (rtf_line
.Length
> 0) {
1763 document
.InsertString (line
, rtf_cursor_x
, rtf_line
.ToString ());
1764 document
.FormatText (line
, rtf_cursor_x
+ 1, line
, rtf_cursor_x
+ 1 + length
,
1765 font
, rtf_style
.rtf_color
, Color
.Empty
,
1766 FormatSpecified
.Font
| FormatSpecified
.Color
);
1769 document
.Split (line
, rtf_cursor_x
+ length
);
1770 line
= document
.GetLine (rtf_cursor_y
);
1771 line
.ending
= LineEnding
.Rich
;
1773 if (line
.Text
.EndsWith ("\n") == false)
1782 rtf_cursor_x
+= length
;
1784 rtf_line
.Length
= 0; // Empty line
1787 private void InsertRTFFromStream(Stream data
, int cursor_x
, int cursor_y
) {
1792 InsertRTFFromStream(data
, cursor_x
, cursor_y
, out x
, out y
, out chars
);
1795 private void InsertRTFFromStream(Stream data
, int cursor_x
, int cursor_y
, out int to_x
, out int to_y
, out int chars
) {
1798 rtf
= new RTF
.RTF(data
);
1801 rtf
.ClassCallback
[RTF
.TokenClass
.Text
] = new RTF
.ClassDelegate(HandleText
);
1802 rtf
.ClassCallback
[RTF
.TokenClass
.Control
] = new RTF
.ClassDelegate(HandleControl
);
1803 rtf
.ClassCallback
[RTF
.TokenClass
.Group
] = new RTF
.ClassDelegate(HandleGroup
);
1806 rtf_line
= new StringBuilder();
1807 rtf_style
.rtf_color
= Color
.Empty
;
1808 rtf_style
.rtf_rtffont_size
= (int)this.Font
.Size
;
1809 rtf_style
.rtf_rtfalign
= HorizontalAlignment
.Left
;
1810 rtf_style
.rtf_rtfstyle
= FontStyle
.Regular
;
1811 rtf_style
.rtf_rtffont
= null;
1812 rtf_style
.rtf_visible
= true;
1813 rtf_style
.rtf_skip_width
= 1;
1814 rtf_cursor_x
= cursor_x
;
1815 rtf_cursor_y
= cursor_y
;
1817 rtf
.DefaultFont(this.Font
.Name
);
1819 rtf_text_map
= new RTF
.TextMap();
1820 RTF
.TextMap
.SetupStandardTable(rtf_text_map
.Table
);
1822 document
.SuspendRecalc ();
1825 rtf
.Read(); // That's it
1826 FlushText(rtf
, false);
1831 catch (RTF
.RTFException e
) {
1835 // Seems to be plain text or broken RTF
1836 Console
.WriteLine("RTF Parsing failure: {0}", e
.Message
);
1839 to_x
= rtf_cursor_x
;
1840 to_y
= rtf_cursor_y
;
1843 // clear the section stack if it was used
1844 if (rtf_section_stack
!= null)
1845 rtf_section_stack
.Clear();
1847 document
.RecalculateDocument(CreateGraphicsInternal(), cursor_y
, document
.Lines
, false);
1848 document
.ResumeRecalc (true);
1850 document
.Invalidate (document
.GetLine(cursor_y
), 0, document
.GetLine(document
.Lines
), -1);
1853 private void RichTextBox_HScrolled(object sender
, EventArgs e
) {
1857 private void RichTextBox_VScrolled(object sender
, EventArgs e
) {
1861 private void PointToTagPos(Point pt
, out LineTag tag
, out int pos
) {
1866 if (p
.X
>= document
.ViewPortWidth
) {
1867 p
.X
= document
.ViewPortWidth
- 1;
1868 } else if (p
.X
< 0) {
1872 if (p
.Y
>= document
.ViewPortHeight
) {
1873 p
.Y
= document
.ViewPortHeight
- 1;
1874 } else if (p
.Y
< 0) {
1878 tag
= document
.FindCursor(p
.X
+ document
.ViewPortX
, p
.Y
+ document
.ViewPortY
, out pos
);
1881 private void EmitRTFFontProperties(StringBuilder rtf
, int prev_index
, int font_index
, Font prev_font
, Font font
) {
1882 if (prev_index
!= font_index
) {
1883 rtf
.Append(String
.Format("\\f{0}", font_index
)); // Font table entry
1886 if ((prev_font
== null) || (prev_font
.Size
!= font
.Size
)) {
1887 rtf
.Append(String
.Format("\\fs{0}", (int)(font
.Size
* 2))); // Font size
1890 if ((prev_font
== null) || (font
.Bold
!= prev_font
.Bold
)) {
1894 if (prev_font
!= null) {
1900 if ((prev_font
== null) || (font
.Italic
!= prev_font
.Italic
)) {
1904 if (prev_font
!= null) {
1910 if ((prev_font
== null) || (font
.Strikeout
!= prev_font
.Strikeout
)) {
1911 if (font
.Strikeout
) {
1912 rtf
.Append("\\strike");
1914 if (prev_font
!= null) {
1915 rtf
.Append("\\strike0");
1920 if ((prev_font
== null) || (font
.Underline
!= prev_font
.Underline
)) {
1921 if (font
.Underline
) {
1924 if (prev_font
!= null) {
1925 rtf
.Append("\\ul0");
1931 [MonoTODO("Emit unicode and other special characters properly")]
1932 private void EmitRTFText(StringBuilder rtf
, string text
) {
1936 // start_pos and end_pos are 0-based
1937 private StringBuilder
GenerateRTF(Line start_line
, int start_pos
, Line end_line
, int end_pos
) {
1951 sb
= new StringBuilder();
1952 fonts
= new ArrayList(10);
1953 colors
= new ArrayList(10);
1955 // Two runs, first we parse to determine tables;
1956 // and unlike most of our processing here we work on tags
1959 line_no
= start_line
.line_no
;
1962 // Add default font and color; to optimize document content we don't
1963 // use this.Font and this.ForeColor but the font/color from the first tag
1964 tag
= LineTag
.FindTag(start_line
, pos
);
1967 fonts
.Add(font
.Name
);
1970 while (line_no
<= end_line
.line_no
) {
1971 line
= document
.GetLine(line_no
);
1972 tag
= LineTag
.FindTag(line
, pos
);
1974 if (line_no
!= end_line
.line_no
) {
1975 line_len
= line
.text
.Length
;
1980 while (pos
< line_len
) {
1981 if (tag
.Font
.Name
!= font
.Name
) {
1983 if (!fonts
.Contains(font
.Name
)) {
1984 fonts
.Add(font
.Name
);
1988 if (tag
.Color
!= color
) {
1990 if (!colors
.Contains(color
)) {
1995 pos
= tag
.Start
+ tag
.Length
- 1;
2002 // We have the tables, emit the header
2003 sb
.Append("{\\rtf1\\ansi");
2004 sb
.Append("\\ansicpg1252"); // FIXME - is this correct?
2007 sb
.Append(String
.Format("\\deff{0}", fonts
.IndexOf(this.Font
.Name
)));
2010 sb
.Append("\\deflang1033\n"); // FIXME - always 1033?
2012 // Emit the font table
2013 sb
.Append("{\\fonttbl");
2014 for (i
= 0; i
< fonts
.Count
; i
++) {
2015 sb
.Append(String
.Format("{{\\f{0}", i
)); // {Font
2016 sb
.Append("\\fnil"); // Family
2017 sb
.Append("\\fcharset0 "); // Charset ANSI<space>
2018 sb
.Append((string)fonts
[i
]); // Font name
2019 sb
.Append(";}"); // }
2023 // Emit the color table (if needed)
2024 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
))) {
2025 sb
.Append("{\\colortbl "); // Header and NO! default color
2026 for (i
= 0; i
< colors
.Count
; i
++) {
2027 sb
.Append(String
.Format("\\red{0}", ((Color
)colors
[i
]).R
));
2028 sb
.Append(String
.Format("\\green{0}", ((Color
)colors
[i
]).G
));
2029 sb
.Append(String
.Format("\\blue{0}", ((Color
)colors
[i
]).B
));
2035 sb
.Append("{\\*\\generator Mono RichTextBox;}");
2036 // Emit initial paragraph settings
2037 tag
= LineTag
.FindTag(start_line
, start_pos
);
2038 sb
.Append("\\pard"); // Reset to default paragraph properties
2039 EmitRTFFontProperties(sb
, -1, fonts
.IndexOf(tag
.Font
.Name
), null, tag
.Font
); // Font properties
2040 sb
.Append(" "); // Space separator
2043 color
= (Color
)colors
[0];
2045 line_no
= start_line
.line_no
;
2048 while (line_no
<= end_line
.line_no
) {
2049 line
= document
.GetLine(line_no
);
2050 tag
= LineTag
.FindTag(line
, pos
);
2052 if (line_no
!= end_line
.line_no
) {
2053 line_len
= line
.text
.Length
;
2058 while (pos
< line_len
) {
2061 if (tag
.Font
!= font
) {
2062 EmitRTFFontProperties(sb
, fonts
.IndexOf(font
.Name
), fonts
.IndexOf(tag
.Font
.Name
), font
, tag
.Font
);
2066 if (tag
.Color
!= color
) {
2068 sb
.Append(String
.Format("\\cf{0}", colors
.IndexOf(color
)));
2070 if (length
!= sb
.Length
) {
2071 sb
.Append(" "); // Emit space to separate keywords from text
2074 // Emit the string itself
2075 if (line_no
!= end_line
.line_no
) {
2076 EmitRTFText(sb
, tag
.Line
.text
.ToString(pos
, tag
.Start
+ tag
.Length
- pos
- 1));
2078 if (end_pos
< (tag
.Start
+ tag
.Length
- 1)) {
2079 // Emit partial tag only, end_pos is inside this tag
2080 EmitRTFText(sb
, tag
.Line
.text
.ToString(pos
, end_pos
- pos
));
2082 EmitRTFText(sb
, tag
.Line
.text
.ToString(pos
, tag
.Start
+ tag
.Length
- pos
- 1));
2086 pos
= tag
.Start
+ tag
.Length
- 1;
2089 if (pos
>= line
.text
.Length
) {
2090 if (line
.ending
!= LineEnding
.Wrap
) {
2091 sb
.Append("\\par\n");
2102 #endregion // Private Methods