|
|
|
|
@ -5,10 +5,12 @@ using System;
@@ -5,10 +5,12 @@ using System;
|
|
|
|
|
using System.Collections.Generic; |
|
|
|
|
using System.Linq; |
|
|
|
|
using System.Windows; |
|
|
|
|
using System.Windows.Controls.Primitives; |
|
|
|
|
using System.Windows.Media; |
|
|
|
|
using System.Windows.Media.TextFormatting; |
|
|
|
|
|
|
|
|
|
using ICSharpCode.AvalonEdit.Document; |
|
|
|
|
using ICSharpCode.AvalonEdit.Editing; |
|
|
|
|
using ICSharpCode.AvalonEdit.Utils; |
|
|
|
|
|
|
|
|
|
namespace ICSharpCode.AvalonEdit.Rendering |
|
|
|
|
@ -38,6 +40,11 @@ namespace ICSharpCode.AvalonEdit.Rendering
@@ -38,6 +40,11 @@ namespace ICSharpCode.AvalonEdit.Rendering
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool AlignToMiddleOfPixels { get; set; } |
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets/Sets whether to extend the rectangles to full width at line end.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool ExtendToFullWidthAtLineEnd { get; set; } |
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Creates a new BackgroundGeometryBuilder instance.
|
|
|
|
|
/// </summary>
|
|
|
|
|
@ -53,7 +60,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
@@ -53,7 +60,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
|
|
|
|
|
if (textView == null) |
|
|
|
|
throw new ArgumentNullException("textView"); |
|
|
|
|
Size pixelSize = PixelSnapHelpers.GetPixelSize(textView); |
|
|
|
|
foreach (Rect r in GetRectsForSegment(textView, segment)) { |
|
|
|
|
foreach (Rect r in GetRectsForSegment(textView, segment, ExtendToFullWidthAtLineEnd)) { |
|
|
|
|
if (AlignToWholePixels) { |
|
|
|
|
AddRectangle(PixelSnapHelpers.Round(r.Left, pixelSize.Width), |
|
|
|
|
PixelSnapHelpers.Round(r.Top + 1, pixelSize.Height), |
|
|
|
|
@ -74,21 +81,33 @@ namespace ICSharpCode.AvalonEdit.Rendering
@@ -74,21 +81,33 @@ namespace ICSharpCode.AvalonEdit.Rendering
|
|
|
|
|
/// Calculates the list of rectangle where the segment in shown.
|
|
|
|
|
/// This returns one rectangle for each line inside the segment.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static IEnumerable<Rect> GetRectsForSegment(TextView textView, ISegment segment) |
|
|
|
|
public static IEnumerable<Rect> GetRectsForSegment(TextView textView, ISegment segment, bool extendToFullWidthAtLineEnd = false) |
|
|
|
|
{ |
|
|
|
|
if (textView == null) |
|
|
|
|
throw new ArgumentNullException("textView"); |
|
|
|
|
if (segment == null) |
|
|
|
|
throw new ArgumentNullException("segment"); |
|
|
|
|
return GetRectsForSegmentImpl(textView, segment); |
|
|
|
|
return GetRectsForSegmentImpl(textView, segment, extendToFullWidthAtLineEnd); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static IEnumerable<Rect> GetRectsForSegmentImpl(TextView textView, ISegment segment) |
|
|
|
|
static IEnumerable<Rect> GetRectsForSegmentImpl(TextView textView, ISegment segment, bool extendToFullWidthAtLineEnd) |
|
|
|
|
{ |
|
|
|
|
Vector scrollOffset = textView.ScrollOffset; |
|
|
|
|
int segmentStart = segment.Offset; |
|
|
|
|
int segmentEnd = segment.Offset + segment.Length; |
|
|
|
|
|
|
|
|
|
TextViewPosition start; |
|
|
|
|
TextViewPosition end; |
|
|
|
|
|
|
|
|
|
if (segment is SelectionSegment) { |
|
|
|
|
SelectionSegment sel = (SelectionSegment)segment; |
|
|
|
|
start = new TextViewPosition(textView.Document.GetLocation(sel.StartOffset), sel.StartVisualColumn); |
|
|
|
|
end = new TextViewPosition(textView.Document.GetLocation(sel.EndOffset), sel.EndVisualColumn); |
|
|
|
|
} else { |
|
|
|
|
start = new TextViewPosition(textView.Document.GetLocation(segmentStart), -1); |
|
|
|
|
end = new TextViewPosition(textView.Document.GetLocation(segmentEnd), -1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
foreach (VisualLine vl in textView.VisualLines) { |
|
|
|
|
int vlStartOffset = vl.FirstDocumentLine.Offset; |
|
|
|
|
if (vlStartOffset > segmentEnd) |
|
|
|
|
@ -101,13 +120,13 @@ namespace ICSharpCode.AvalonEdit.Rendering
@@ -101,13 +120,13 @@ namespace ICSharpCode.AvalonEdit.Rendering
|
|
|
|
|
if (segmentStart < vlStartOffset) |
|
|
|
|
segmentStartVC = 0; |
|
|
|
|
else |
|
|
|
|
segmentStartVC = vl.GetVisualColumn(segmentStart - vlStartOffset); |
|
|
|
|
segmentStartVC = vl.ValidateVisualColumn(start, extendToFullWidthAtLineEnd); |
|
|
|
|
|
|
|
|
|
int segmentEndVC; |
|
|
|
|
if (segmentEnd > vlEndOffset) |
|
|
|
|
segmentEndVC = vl.VisualLength; |
|
|
|
|
segmentEndVC = extendToFullWidthAtLineEnd ? int.MaxValue : vl.VisualLength; |
|
|
|
|
else |
|
|
|
|
segmentEndVC = vl.GetVisualColumn(segmentEnd - vlStartOffset); |
|
|
|
|
segmentEndVC = vl.ValidateVisualColumn(end, extendToFullWidthAtLineEnd); |
|
|
|
|
|
|
|
|
|
TextLine lastTextLine = vl.TextLines.Last(); |
|
|
|
|
|
|
|
|
|
@ -121,7 +140,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
@@ -121,7 +140,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
|
|
|
|
|
|
|
|
|
|
if (segmentEndVC < visualStartCol) |
|
|
|
|
break; |
|
|
|
|
if (segmentStartVC > visualEndCol) |
|
|
|
|
if (lastTextLine != line && segmentStartVC > visualEndCol) |
|
|
|
|
continue; |
|
|
|
|
int segmentStartVCInLine = Math.Max(segmentStartVC, visualStartCol); |
|
|
|
|
int segmentEndVCInLine = Math.Min(segmentEndVC, visualEndCol); |
|
|
|
|
@ -140,14 +159,33 @@ namespace ICSharpCode.AvalonEdit.Rendering
@@ -140,14 +159,33 @@ namespace ICSharpCode.AvalonEdit.Rendering
|
|
|
|
|
continue; |
|
|
|
|
yield return new Rect(pos, y, 1, line.Height); |
|
|
|
|
} else { |
|
|
|
|
foreach (TextBounds b in line.GetTextBounds(segmentStartVCInLine, segmentEndVCInLine - segmentStartVCInLine)) { |
|
|
|
|
double left = b.Rectangle.Left; |
|
|
|
|
double right = b.Rectangle.Right; |
|
|
|
|
left -= scrollOffset.X; |
|
|
|
|
right -= scrollOffset.X; |
|
|
|
|
// left>right is possible in RTL languages
|
|
|
|
|
yield return new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height); |
|
|
|
|
Rect lastRect = Rect.Empty; |
|
|
|
|
if (segmentStartVCInLine <= visualEndCol) { |
|
|
|
|
foreach (TextBounds b in line.GetTextBounds(segmentStartVCInLine, segmentEndVCInLine - segmentStartVCInLine)) { |
|
|
|
|
double left = b.Rectangle.Left - scrollOffset.X; |
|
|
|
|
double right = b.Rectangle.Right - scrollOffset.X; |
|
|
|
|
if (!lastRect.IsEmpty) |
|
|
|
|
yield return lastRect; |
|
|
|
|
// left>right is possible in RTL languages
|
|
|
|
|
lastRect = new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (segmentEndVC >= vl.VisualLength) { |
|
|
|
|
double left = (segmentStartVC > vl.VisualLength ? vl.GetTextLineVisualXPosition(line, segmentStartVC) : line.Width) - scrollOffset.X; |
|
|
|
|
double right = (segmentEndVC == int.MaxValue ? Math.Max(((IScrollInfo)textView).ExtentWidth, ((IScrollInfo)textView).ViewportWidth) : vl.GetTextLineVisualXPosition(line, segmentEndVC)) - scrollOffset.X; |
|
|
|
|
Rect extendSelection = new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height); |
|
|
|
|
if (!lastRect.IsEmpty) { |
|
|
|
|
if (extendSelection.IntersectsWith(lastRect)) { |
|
|
|
|
lastRect.Union(extendSelection); |
|
|
|
|
yield return lastRect; |
|
|
|
|
} else { |
|
|
|
|
yield return lastRect; |
|
|
|
|
yield return extendSelection; |
|
|
|
|
} |
|
|
|
|
} else |
|
|
|
|
yield return extendSelection; |
|
|
|
|
} else |
|
|
|
|
yield return lastRect; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|