void DrawLinePart (Cairo.Context cr, DocumentLine line, int lineNumber, int logicalRulerColumn, int offset, int length, ref double position, ref bool isSelectionDrawn, double y, double maxX, double _lineHeight)
{
ISyntaxMode mode = Document.SyntaxMode != null && textEditor.Options.EnableSyntaxHighlighting ? Document.SyntaxMode : new SyntaxMode (Document);
int selectionStartOffset;
int selectionEndOffset;
if (this.HideSelection) {
selectionStartOffset = selectionEndOffset = -1;
} else {
GetSelectionOffsets (line, out selectionStartOffset, out selectionEndOffset);
}
// ---- new renderer
LayoutWrapper layout = CreateLinePartLayout (mode, line, logicalRulerColumn, offset, length, selectionStartOffset, selectionEndOffset);
int lineOffset = line.Offset;
double width = layout.Width;
double xPos = position;
// The caret line marker must be drawn below the text markers otherwise the're invisible
if ((HighlightCaretLine || textEditor.GetTextEditorData ().HighlightCaretLine) && Caret.Line == lineNumber)
DrawCaretLineMarker (cr, xPos, y, layout.Width, _lineHeight);
// if (!(HighlightCaretLine || textEditor.Options.HighlightCaretLine) || Document.GetLine(Caret.Line) != line) {
if (BackgroundRenderer == null) {
foreach (var bg in layout.BackgroundColors) {
int x1, x2;
x1 = layout.Layout.IndexToPos (bg.FromIdx).X;
x2 = layout.Layout.IndexToPos (bg.ToIdx).X;
DrawRectangleWithRuler (
cr, xPos + textEditor.HAdjustment.Value - TextStartPosition,
new Cairo.Rectangle (x1 / Pango.Scale.PangoScale + position, y, (x2 - x1) / Pango.Scale.PangoScale + 1, _lineHeight),
bg.Color, true);
}
}
var metrics = new LineMetrics {
LineSegment = line,
Layout = layout,
SelectionStart = selectionStartOffset,
SelectionEnd = selectionEndOffset,
TextStartOffset = offset,
TextEndOffset = offset + length,
TextRenderStartPosition = xPos,
TextRenderEndPosition = xPos + width,
LineHeight = _lineHeight,
WholeLineWidth = textEditor.Allocation.Width - xPos,
LineYRenderStartPosition = y
};
foreach (TextLineMarker marker in line.Markers) {
if (!marker.IsVisible)
continue;
if (marker.DrawBackground (textEditor, cr, metrics)) {
isSelectionDrawn |= (marker.Flags & TextLineMarkerFlags.DrawsSelection) == TextLineMarkerFlags.DrawsSelection;
}
}
var textSegmentMarkers = TextDocument.OrderTextSegmentMarkersByInsertion (Document.GetTextSegmentMarkersAt (line).Where (m => m.IsVisible)).ToArray ();
foreach (var marker in textSegmentMarkers) {
if (layout.Layout != null)
marker.DrawBackground (textEditor, cr, metrics, offset, offset + length);
}
if (DecorateLineBg != null)
DecorateLineBg (cr, layout, offset, length, xPos, y, selectionStartOffset, selectionEndOffset);
if (!isSelectionDrawn && (layout.StartSet || selectionStartOffset == offset + length) && BackgroundRenderer == null) {
double startX;
int startY;
double endX;
int endY;
if (selectionStartOffset != offset + length) {
var start = layout.Layout.IndexToPos (layout.SelectionStartIndex);
startX = System.Math.Floor (start.X / Pango.Scale.PangoScale);
startY = (int)(y + System.Math.Floor (start.Y / Pango.Scale.PangoScale));
var end = layout.Layout.IndexToPos (layout.SelectionEndIndex);
endX = System.Math.Ceiling (end.X / Pango.Scale.PangoScale);
endY = (int)(y + System.Math.Ceiling (end.Y / Pango.Scale.PangoScale));
} else {
startY = endY = (int)y;
startX = width;
endX = startX;
}
if (textEditor.MainSelection.SelectionMode == SelectionMode.Block && startX == endX) {
endX = startX + 2;
}
if (startY == endY) {
DrawRectangleWithRuler (
cr,
xPos + textEditor.HAdjustment.Value - TextStartPosition,
new Cairo.Rectangle (xPos + startX, startY, endX - startX, LineHeight),
this.SelectionColor.Background,
true
);
} else {
DrawRectangleWithRuler (
cr,
xPos + textEditor.HAdjustment.Value - TextStartPosition,
new Cairo.Rectangle (xPos + startX, startY, textEditor.Allocation.Width - xPos - startX, LineHeight),
this.SelectionColor.Background,
true
);
if (endY - startY > LineHeight) {
DrawRectangleWithRuler (
cr,
xPos,
new Cairo.Rectangle (xPos, startY + LineHeight, textEditor.Allocation.Width - xPos, endY - startY - LineHeight),
this.SelectionColor.Background,
true
);
}
DrawRectangleWithRuler (
cr,
xPos,
new Cairo.Rectangle (xPos, endY, endX, LineHeight),
this.SelectionColor.Background,
true
);
}
}
// highlight search results
TextSegment firstSearch;
int o = offset;
uint curIndex = 0, byteIndex = 0;
if (textEditor.HighlightSearchPattern) {
while (!(firstSearch = GetFirstSearchResult (o, offset + length)).IsInvalid) {
double x = position;
HandleSelection (lineOffset, logicalRulerColumn, selectionStartOffset, selectionEndOffset, System.Math.Max (lineOffset, firstSearch.Offset), System.Math.Min (lineOffset + line.Length, firstSearch.EndOffset), delegate(int start, int end) {
uint startIndex = (uint)(start - offset);
uint endIndex = (uint)(end - offset);
if (startIndex < endIndex && endIndex <= layout.LineChars.Length) {
uint startTranslated = TranslateToUTF8Index (layout.LineChars, startIndex, ref curIndex, ref byteIndex);
uint endTranslated = TranslateToUTF8Index (layout.LineChars, endIndex, ref curIndex, ref byteIndex);
int l, x1, x2;
layout.Layout.IndexToLineX ((int)startTranslated, false, out l, out x1);
layout.Layout.IndexToLineX ((int)endTranslated, false, out l, out x2);
int w = (int) System.Math.Ceiling ((x2 - x1) / Pango.Scale.PangoScale);
int s = (int) System.Math.Floor (x1 / Pango.Scale.PangoScale + x);
double corner = System.Math.Min (4, width) * textEditor.Options.Zoom;
cr.SetSourceColor (MainSearchResult.IsInvalid || MainSearchResult.Offset != firstSearch.Offset ? ColorStyle.SearchResult.Color : ColorStyle.SearchResultMain.Color);
FoldingScreenbackgroundRenderer.DrawRoundRectangle (cr, true, true, s, y, corner, w + 1, LineHeight);
cr.Fill ();
}
}, null);
o = System.Math.Max (firstSearch.EndOffset, o + 1);
}
}
cr.Save ();
cr.Translate (xPos, y);
cr.ShowLayout (layout.Layout);
cr.Restore ();
if (offset == line.Offset) {
DrawIndent (cr, layout, line, xPos, y);
}
if (textEditor.Options.ShowWhitespaces != ShowWhitespaces.Never && !(BackgroundRenderer != null && textEditor.Options.ShowWhitespaces == ShowWhitespaces.Selection))
DecorateTabsAndSpaces (cr, layout, offset, xPos, y, selectionStartOffset, selectionEndOffset);
if (textEditor.IsSomethingSelected && !isSelectionDrawn && BackgroundRenderer == null) {
if (lineNumber == textEditor.MainSelection.End.Line && textEditor.MainSelection.End.Column > line.Length + 1) {
using (var wrapper = GetVirtualSpaceLayout (line, textEditor.MainSelection.End)) {
double startX;
double endX;
startX = xPos;
endX = position + wrapper.Width + layout.Width;
DrawRectangleWithRuler (cr, xPos + textEditor.HAdjustment.Value - TextStartPosition, new Cairo.Rectangle (startX, y, endX - startX, _lineHeight), this.SelectionColor.Background, true);
if (lineNumber == Caret.Line &&
textEditor.Options.ShowWhitespaces == ShowWhitespaces.Selection &&
textEditor.IsSomethingSelected &&
(selectionStartOffset < offset || selectionStartOffset == selectionEndOffset) &&
BackgroundRenderer == null) {
DecorateTabsAndSpaces (cr, wrapper, offset, xPos, y, selectionStartOffset, selectionEndOffset + wrapper.LineChars.Length);
}
}
}
}
if (lineNumber == Caret.Line) {
int caretOffset = Caret.Offset;
if (offset <= caretOffset && caretOffset <= offset + length) {
int index = caretOffset - offset;
//This if means we have temporary indent
if (Caret.Column > line.Length + 1) {
using (var wrapper = GetVirtualSpaceLayout (line, Caret.Location)) {
var x = (position + wrapper.Width) + layout.Width;
SetVisibleCaretPosition (x, y, x, y);
xPos = position + layout.Width;
// When drawing virtual space before the selection start paint it as unselected.
var virtualSpaceMod = selectionStartOffset < caretOffset ? 0 : wrapper.LineChars.Length;
if ((!textEditor.IsSomethingSelected || (selectionStartOffset >= offset && selectionStartOffset != selectionEndOffset)) && (HighlightCaretLine || textEditor.Options.HighlightCaretLine) && Caret.Line == lineNumber)
DrawCaretLineMarker (cr, position, y, wrapper.Width, _lineHeight);
if (DecorateLineBg != null)
DecorateLineBg (cr, wrapper, offset, length, xPos, y, selectionStartOffset + virtualSpaceMod, selectionEndOffset + wrapper.LineChars.Length);
if (textEditor.Options.ShowWhitespaces == ShowWhitespaces.Always) {
DecorateTabsAndSpaces (cr, wrapper, offset, xPos, y, selectionStartOffset, selectionEndOffset + wrapper.LineChars.Length);
}
}
} else if (index == length && string.IsNullOrEmpty (textEditor.preeditString)) {
var x = position + layout.Width;
SetVisibleCaretPosition (x, y, x, y);
} else if (index >= 0 && index <= length) {
Pango.Rectangle strong_pos, weak_pos;
curIndex = byteIndex = 0;
int utf8ByteIndex = (int)TranslateToUTF8Index (layout.LineChars, (uint)index, ref curIndex, ref byteIndex);
layout.Layout.GetCursorPos (utf8ByteIndex, out strong_pos, out weak_pos);
var cx = xPos + (strong_pos.X / Pango.Scale.PangoScale);
var cy = y + (strong_pos.Y / Pango.Scale.PangoScale);
if (textEditor.preeditCursorCharIndex == 0) {
SetVisibleCaretPosition (cx, cy, cx, cy);
} else {
var preeditIndex = (uint)(index + textEditor.preeditCursorCharIndex);
utf8ByteIndex = (int)TranslateToUTF8Index (layout.LineChars, preeditIndex, ref curIndex, ref byteIndex);
layout.Layout.GetCursorPos (utf8ByteIndex, out strong_pos, out weak_pos);
var pcx = xPos + (strong_pos.X / Pango.Scale.PangoScale);
var pcy = y + (strong_pos.Y / Pango.Scale.PangoScale);
SetVisibleCaretPosition (pcx, pcy, cx, cy);
}
}
}
}
foreach (TextLineMarker marker in line.Markers.Where (m => m.IsVisible)) {
if (layout.Layout != null)
marker.Draw (textEditor, cr, metrics);
}
foreach (var marker in textSegmentMarkers) {
if (layout.Layout != null)
marker.Draw (textEditor, cr, metrics, offset, offset + length);
}
position += System.Math.Floor (layout.LastLineWidth);
if (layout.IsUncached)
layout.Dispose ();
}