Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/mcs
diff options
context:
space:
mode:
authorPeter Dennis Bartok <pbartok@mono-cvs.ximian.com>2006-02-27 06:03:22 +0300
committerPeter Dennis Bartok <pbartok@mono-cvs.ximian.com>2006-02-27 06:03:22 +0300
commitda39ca5f6c4cee5624e7aa0ee98f46ec60dea950 (patch)
tree9fc4a468132b91181b8499d39888f80cc700f1a5 /mcs
parent18507258077a3e563e1ec795786c96e20170b6f9 (diff)
2006-02-26 Peter Dennis Bartok <pbartok@novell.com>
* RichTextBox.cs: - SelectionColor and SelectionFont methods no longer set absolute styles. Instead, the keep font or color respectively (This resolves a long-standing FIXME in the code) - When flushing RTF text, the insert code now considers text trailing behind the insertion point (Fixes the bug where when replacing the selected text via SelectedRTF the remainder of the line behind the selection would stay on the first insertion line) * TextBoxBase.cs: - AppendText now updates the selection points after inserting text - AppendText now ensures that the last tag (sometimes 0-length) of the document is used for the style information (Fixes part of bug #77220) * TextControl.cs: - Created new FontDefiniton class to allow describing partial style changes - StreamLine() now takes a lines argument, to allow it to decide whether an encountered zero-length tag is the last in the document (which must be kept to not loose the font/color contained in it, for later appends) - Created Combine() and Split() methods for Marker structs, to support marker updates due to reformatted documents (soft line wraps) - Implemented Document.CaretTag setter - Fixed MoveCaret(CtrlEnd) handling, now moves to the last character of the last line (Not the cause, but also exposed by bug #77220) - Added LineTag argument to InsertString method, to allow callers to force a certain tag to be used (required to force use of the trailing zero-length tag of a document) - Now updating markers in Combine(), to avoid stale tag markers - Added some method descriptions to aid maintenance - Implemented new FormatText concept, allowing additive/subtractive formatting by only specifying the components that are to be changed. This was needed for resolving the RTB.SelectedColor/ RTB.SelectedFont fixmes - Added Break() support method to allow breaking up linetags (used for partial formatting) - Added GenerateTextFormat() method. It is used for partial formatting and allows to generate a full font/color from given attributes and an existing tag. svn path=/trunk/mcs/; revision=57322
Diffstat (limited to 'mcs')
-rw-r--r--mcs/class/Managed.Windows.Forms/System.Windows.Forms/ChangeLog43
-rw-r--r--mcs/class/Managed.Windows.Forms/System.Windows.Forms/RichTextBox.cs27
-rw-r--r--mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextBoxBase.cs13
-rw-r--r--mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextControl.cs255
4 files changed, 306 insertions, 32 deletions
diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ChangeLog b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ChangeLog
index 3a48f3f3034..45e8122e17e 100644
--- a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ChangeLog
+++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ChangeLog
@@ -1,3 +1,46 @@
+2006-02-26 Peter Dennis Bartok <pbartok@novell.com>
+
+ * RichTextBox.cs:
+ - SelectionColor and SelectionFont methods no longer set absolute
+ styles. Instead, the keep font or color respectively (This
+ resolves a long-standing FIXME in the code)
+ - When flushing RTF text, the insert code now considers text trailing
+ behind the insertion point (Fixes the bug where when replacing
+ the selected text via SelectedRTF the remainder of the line behind
+ the selection would stay on the first insertion line)
+ * TextBoxBase.cs:
+ - AppendText now updates the selection points after inserting text
+ - AppendText now ensures that the last tag (sometimes 0-length) of
+ the document is used for the style information (Fixes part of
+ bug #77220)
+ * TextControl.cs:
+ - Created new FontDefiniton class to allow describing partial style
+ changes
+ - StreamLine() now takes a lines argument, to allow it to decide
+ whether an encountered zero-length tag is the last in the document
+ (which must be kept to not loose the font/color contained in it,
+ for later appends)
+ - Created Combine() and Split() methods for Marker structs, to
+ support marker updates due to reformatted documents (soft line
+ wraps)
+ - Implemented Document.CaretTag setter
+ - Fixed MoveCaret(CtrlEnd) handling, now moves to the last character
+ of the last line (Not the cause, but also exposed by bug #77220)
+ - Added LineTag argument to InsertString method, to allow callers
+ to force a certain tag to be used (required to force use of the
+ trailing zero-length tag of a document)
+ - Now updating markers in Combine(), to avoid stale tag markers
+ - Added some method descriptions to aid maintenance
+ - Implemented new FormatText concept, allowing additive/subtractive
+ formatting by only specifying the components that are to be
+ changed. This was needed for resolving the RTB.SelectedColor/
+ RTB.SelectedFont fixmes
+ - Added Break() support method to allow breaking up linetags (used
+ for partial formatting)
+ - Added GenerateTextFormat() method. It is used for partial
+ formatting and allows to generate a full font/color from given
+ attributes and an existing tag.
+
2006-02-26 Jackson Harper <jackson@ximian.com>
* XplatUIX11.cs: Use the correct caption height.
diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/RichTextBox.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/RichTextBox.cs
index 4259fb6b797..6662c87d5dd 100644
--- a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/RichTextBox.cs
+++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/RichTextBox.cs
@@ -17,7 +17,7 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+// Copyright (c) 2005-2006 Novell, Inc. (http://www.novell.com)
//
// Authors:
// Peter Bartok <pbartok@novell.com>
@@ -425,13 +425,17 @@ namespace System.Windows.Forms {
}
set {
- int sel_start;
- int sel_end;
+ FontDefinition attributes;
+ int sel_start;
+ int sel_end;
+
+ attributes = new FontDefinition();
+ attributes.color = value;
sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
-Console.WriteLine("FIXME - SelectionColor should not alter font");
- document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos + 1, document.selection_start.tag.font, new SolidBrush(value));
+
+ document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos + 1, attributes);
document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
@@ -475,13 +479,17 @@ Console.WriteLine("FIXME - SelectionColor should not alter font");
}
set {
- int sel_start;
- int sel_end;
+ FontDefinition attributes;
+ int sel_start;
+ int sel_end;
+
+ attributes = new FontDefinition();
+ attributes.font_obj = value;
sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
- document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos + 1, value, document.selection_start.tag.color);
+ document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos + 1, attributes);
document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
@@ -1299,6 +1307,9 @@ Console.WriteLine("FIXME - SelectionColor should not alter font");
line = document.GetLine(rtf_cursor_y);
document.InsertString(line, rtf_cursor_x, rtf_line.ToString());
document.FormatText(line, rtf_cursor_x + 1, line, rtf_cursor_x + 1 + length, font, rtf_color); // FormatText is 1-based
+ if (newline && (line.text.Length > (rtf_cursor_x + 1 + length))) {
+ document.Split(line, rtf_cursor_x + length);
+ }
}
if (newline) {
diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextBoxBase.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextBoxBase.cs
index 37206a41b72..bf884756d6d 100644
--- a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextBoxBase.cs
+++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextBoxBase.cs
@@ -572,15 +572,24 @@ namespace System.Windows.Forms {
if (multiline) {
// Grab the formatting for the last element
document.MoveCaret(CaretDirection.CtrlEnd);
- document.Insert(document.CaretLine, document.CaretPosition, text);
+ // grab the end tag
+ if (document.CaretTag.next != null) {
+ document.CaretTag = document.CaretTag.next;
+ }
+ document.Insert(document.CaretLine, document.CaretTag, document.CaretPosition, false, text);
CalculateDocument();
- document.MoveCaret(CaretDirection.CtrlEnd);
} else {
document.MoveCaret(CaretDirection.CtrlEnd);
document.InsertStringAtCaret(text, true);
+
Invalidate();
}
+
+ document.MoveCaret(CaretDirection.CtrlEnd);
+ document.SetSelectionStart(document.CaretLine, document.CaretPosition);
+ document.SetSelectionEnd(document.CaretLine, document.CaretPosition);
+
OnTextChanged(EventArgs.Empty);
}
diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextControl.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextControl.cs
index 1c22fd316bc..1d0dbf49381 100644
--- a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextControl.cs
+++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextControl.cs
@@ -63,6 +63,21 @@ namespace System.Windows.Forms {
Line // Selection=Line under caret
}
+ internal class FontDefinition {
+ internal String face;
+ internal int size;
+ internal FontStyle add_style;
+ internal FontStyle remove_style;
+ internal Color color;
+ internal Font font_obj;
+
+ internal FontDefinition() {
+ face = null;
+ size = 0;
+ color = Color.Empty;
+ }
+ }
+
internal enum CaretDirection {
CharForward, // Move a char to the right
CharBack, // Move a char to the left
@@ -279,7 +294,7 @@ namespace System.Windows.Forms {
}
}
- internal void Streamline() {
+ internal void Streamline(int lines) {
LineTag current;
LineTag next;
@@ -300,16 +315,17 @@ namespace System.Windows.Forms {
}
while (next != null) {
- // Take out 0 length tags
+ // Take out 0 length tags unless it's the last tag in the document
if (next.length == 0) {
- current.next = next.next;
- if (current.next != null) {
- current.next.previous = current;
+ if ((next.next != null) || (line_no != lines)) {
+ current.next = next.next;
+ if (current.next != null) {
+ current.next.previous = current;
+ }
+ next = current.next;
+ continue;
}
- next = current.next;
- continue;
}
-
if (current.Combine(next)) {
next = current.next;
continue;
@@ -670,6 +686,19 @@ namespace System.Windows.Forms {
return false;
}
+ public void Combine(Line move_to_line, int move_to_line_length) {
+ line = move_to_line;
+ pos += move_to_line_length;
+ tag = LineTag.FindTag(line, pos);
+ }
+
+ // This is for future use, right now Document.Split does it by hand, with some added shortcut logic
+ public void Split(Line move_to_line, int split_at) {
+ line = move_to_line;
+ pos -= split_at;
+ tag = LineTag.FindTag(line, pos);
+ }
+
public override bool Equals(object obj) {
return this==(Marker)obj;
}
@@ -810,6 +839,10 @@ namespace System.Windows.Forms {
get {
return caret.tag;
}
+
+ set {
+ caret.tag = value;
+ }
}
internal int CRLFSize {
@@ -1528,8 +1561,8 @@ namespace System.Windows.Forms {
case CaretDirection.CtrlEnd: {
caret.line = GetLine(lines);
- caret.pos = 0;
- caret.tag = caret.line.tags;
+ caret.pos = caret.line.text.Length;
+ caret.tag = LineTag.FindTag(caret.line, caret.pos);
UpdateCaret();
return;
@@ -1815,20 +1848,21 @@ namespace System.Windows.Forms {
}
internal void Insert(Line line, int pos, string s) {
- Insert(line, pos, false, s);
+ Insert(line, null, pos, false, s);
}
// Insert multi-line text at the given position; use formatting at insertion point for inserted text
- internal void Insert(Line line, int pos, bool update_caret, string s) {
+ internal void Insert(Line line, LineTag tag, int pos, bool update_caret, string s) {
int i;
int base_line;
string[] ins;
int insert_lines;
- LineTag tag;
// The formatting at the insertion point is used for the inserted text
- tag = LineTag.FindTag(line, pos);
+ if (tag == null) {
+ tag = LineTag.FindTag(line, pos);
+ }
base_line = line.line_no;
@@ -1849,7 +1883,7 @@ namespace System.Windows.Forms {
}
// Insert the first line
- InsertString(line, pos, ins[0]);
+ InsertString(tag, pos, ins[0]);
if (insert_lines > 1) {
for (i = 1; i < insert_lines; i++) {
@@ -2056,7 +2090,7 @@ namespace System.Windows.Forms {
line.recalc = true;
if (streamline) {
- line.Streamline();
+ line.Streamline(lines);
}
UpdateView(line, pos);
@@ -2116,7 +2150,7 @@ namespace System.Windows.Forms {
}
line.recalc = true;
if (streamline) {
- line.Streamline();
+ line.Streamline(lines);
}
UpdateView(line, pos);
@@ -2164,7 +2198,21 @@ namespace System.Windows.Forms {
// Mop up
first.recalc = true;
first.height = 0; // This forces RecalcDocument/UpdateView to redraw from this line on
- first.Streamline();
+ first.Streamline(lines);
+
+ // Update Caret, Selection, etc
+ if (caret.line == second) {
+ caret.Combine(first, shift);
+ }
+ if (selection_anchor.line == second) {
+ selection_anchor.Combine(first, shift);
+ }
+ if (selection_start.line == second) {
+ selection_start.Combine(first, shift);
+ }
+ if (selection_end.line == second) {
+ selection_end.Combine(first, shift);
+ }
#if Debug
Line check_first;
@@ -2204,6 +2252,9 @@ namespace System.Windows.Forms {
Split(line, tag, pos, false);
}
+ ///<summary>Split line at given tag and position into two lines</summary>
+ ///<param name="soft">True if the split should be marked as 'soft', indicating that it can be contracted
+ ///if more space becomes available on previous line</param>
internal void Split(Line line, LineTag tag, int pos, bool soft) {
LineTag new_tag;
Line new_line;
@@ -2991,7 +3042,7 @@ namespace System.Windows.Forms {
}
}
- Insert(selection_start.line, selection_start.pos, true, s);
+ Insert(selection_start.line, null, selection_start.pos, true, s);
selection_end.line = selection_start.line;
selection_end.pos = selection_start.pos;
@@ -3317,6 +3368,34 @@ namespace System.Windows.Forms {
}
}
+ /// <summary>Re-format areas of the document in specified font and color</summary>
+ /// <param name="start_pos">1-based start position on start_line</param>
+ /// <param name="end_pos">1-based end position on end_line </param>
+ /// <param name="font">Font specifying attributes</param>
+ /// <param name="color">Color (or NULL) to apply</param>
+ /// <param name="apply">Attributes from font and color to apply</param>
+ internal void FormatText(Line start_line, int start_pos, Line end_line, int end_pos, FontDefinition attributes) {
+ Line l;
+
+ // First, format the first line
+ if (start_line != end_line) {
+ // First line
+ LineTag.FormatText(start_line, start_pos, start_line.text.Length - start_pos + 1, attributes);
+
+ // Format last line
+ LineTag.FormatText(end_line, 1, end_pos - 1, attributes);
+
+ // Now all the lines inbetween
+ for (int i = start_line.line_no + 1; i < end_line.line_no; i++) {
+ l = GetLine(i);
+ LineTag.FormatText(l, 1, l.text.Length, attributes);
+ }
+ } else {
+ // Special case, single line
+ LineTag.FormatText(start_line, start_pos, end_pos - start_pos, attributes);
+ }
+ }
+
internal void RecalculateAlignments() {
Line line;
int line_no;
@@ -3813,7 +3892,75 @@ namespace System.Windows.Forms {
#endregion // Constructors
#region Internal Methods
- /// <summary>Applies 'font' to characters starting at 'start' for 'length' chars;
+ ///<summary>Break a tag into two with identical attributes; pos is 1-based; returns tag starting at &gt;pos&lt; or null if end-of-line</summary>
+ internal LineTag Break(int pos) {
+ LineTag new_tag;
+
+ // Sanity
+ if (pos == this.start) {
+ return this;
+ } else if (pos >= (start + length)) {
+ return null;
+ }
+
+ new_tag = new LineTag(line, pos, start + length - pos);
+ new_tag.color = color;
+ new_tag.font = font;
+ this.length -= new_tag.length;
+ new_tag.next = this.next;
+ this.next = new_tag;
+ new_tag.previous = this;
+ if (new_tag.next != null) {
+ new_tag.next.previous = new_tag;
+ }
+
+ return new_tag;
+ }
+
+ ///<summary>Create new font and brush from existing font and given new attributes. Returns true if fontheight changes</summary>
+ internal static bool GenerateTextFormat(Font font_from, Brush color_from, FontDefinition attributes, out Font new_font, out Brush new_color) {
+ float size;
+ string face;
+ FontStyle style;
+ GraphicsUnit unit;
+
+ if (attributes.font_obj == null) {
+ size = font_from.SizeInPoints;
+ unit = font_from.Unit;
+ face = font_from.Name;
+ style = font_from.Style;
+
+ if (attributes.face != null) {
+ face = attributes.face;
+ }
+
+ if (attributes.size != 0) {
+ size = attributes.size;
+ }
+
+ style |= attributes.add_style;
+ style &= ~attributes.remove_style;
+
+ // Create new font
+ new_font = new Font(face, size, style, unit);
+ } else {
+ new_font = attributes.font_obj;
+ }
+
+ // Create 'new' color brush
+ if (attributes.color != Color.Empty) {
+ new_color = new SolidBrush(attributes.color);
+ } else {
+ new_color = color_from;
+ }
+
+ if (new_font.Height == font_from.Height) {
+ return false;
+ }
+ return true;
+ }
+
+ /// <summary>Applies 'font' and 'brush' to characters starting at 'start' for 'length' chars;
/// Removes any previous tags overlapping the same area;
/// returns true if lineheight has changed</summary>
/// <param name="start">1-based character position on line</param>
@@ -3845,8 +3992,11 @@ namespace System.Windows.Forms {
return retval;
}
-//Console.WriteLine("Finding tag for {0} {1}", line, start);
+ //Console.WriteLine("Finding tag for {0} {1}", line, start);
start_tag = FindTag(line, start);
+ if (start_tag == null) { // FIXME - is there a better way to handle this, or do we even need it?
+ throw new Exception(String.Format("Could not find start_tag in document at line {0} position {1}", line.line_no, start));
+ }
tag = new LineTag(line, start, length);
tag.font = font;
@@ -3855,7 +4005,7 @@ namespace System.Windows.Forms {
if (start == 1) {
line.tags = tag;
}
-//Console.WriteLine("Start tag: '{0}'", start_tag!=null ? start_tag.ToString() : "NULL");
+ //Console.WriteLine("Start tag: '{0}'", start_tag!=null ? start_tag.ToString() : "NULL");
if (start_tag.start == start) {
tag.next = start_tag;
tag.previous = start_tag.previous;
@@ -3912,6 +4062,67 @@ namespace System.Windows.Forms {
return retval;
}
+ /// <summary>Applies font attributes specified to characters starting at 'start' for 'length' chars;
+ /// Breaks tags at start and end point, keeping middle tags with altered attributes.
+ /// Returns true if lineheight has changed</summary>
+ /// <param name="start">1-based character position on line</param>
+ internal static bool FormatText(Line line, int start, int length, FontDefinition attributes) {
+ LineTag tag;
+ LineTag start_tag;
+ LineTag end_tag;
+ bool retval = false; // Assume line-height doesn't change
+
+ line.recalc = true; // This forces recalculation of the line in RecalculateDocument
+
+ // A little sanity, not sure if it's needed, might be able to remove for speed
+ if (length > line.text.Length) {
+ length = line.text.Length;
+ }
+
+ tag = line.tags;
+
+ // Common special case
+ if ((start == 1) && (length == tag.length)) {
+ tag.ascent = 0;
+ GenerateTextFormat(tag.font, tag.color, attributes, out tag.font, out tag.color);
+ return retval;
+ }
+
+ start_tag = FindTag(line, start);
+
+ if (start_tag == null) {
+ if (length == 0) {
+ // We are 'starting' after all valid tags; create a new tag with the right attributes
+ start_tag = FindTag(line, line.text.Length - 1);
+ start_tag.next = new LineTag(line, line.text.Length + 1, 0);
+ start_tag.next.font = start_tag.font;
+ start_tag.next.color = start_tag.color;
+ start_tag.next.previous = start_tag;
+ start_tag = start_tag.next;
+ } else {
+ throw new Exception(String.Format("Could not find start_tag in document at line {0} position {1}", line.line_no, start));
+ }
+ } else {
+ start_tag = start_tag.Break(start);
+ }
+
+ end_tag = FindTag(line, start + length);
+ if (end_tag != null) {
+ end_tag = end_tag.Break(start + length);
+ }
+
+ // start_tag or end_tag might be null; we're cool with that
+ // we now walk from start_tag to end_tag, applying new attributes
+ tag = start_tag;
+ while ((tag != null) && tag != end_tag) {
+ if (LineTag.GenerateTextFormat(tag.font, tag.color, attributes, out tag.font, out tag.color)) {
+ retval = true;
+ }
+ tag = tag.next;
+ }
+ return retval;
+ }
+
/// <summary>Finds the tag that describes the character at position 'pos' on 'line'</summary>
internal static LineTag FindTag(Line line, int pos) {