protected internal override void Draw (Cairo.Context cr, Cairo.Rectangle area, DocumentLine line, int lineNr, double x, double y, double _lineHeight)
{
// double xStart = System.Math.Max (area.X, XOffset);
// xStart = System.Math.Max (0, xStart);
var correctedXOffset = System.Math.Floor (XOffset) - 1;
var lineArea = new Cairo.Rectangle (correctedXOffset, y, textEditor.Allocation.Width - correctedXOffset, _lineHeight);
double position = x - textEditor.HAdjustment.Value + TextStartPosition;
defaultBgColor = Document.ReadOnly ? ColorStyle.BackgroundReadOnly.Color : ColorStyle.PlainText.Background;
var startLineNr = lineNr;
// Draw the default back color for the whole line. Colors other than the default
// background will be drawn when rendering the text chunks.
if (BackgroundRenderer == null)
DrawRectangleWithRuler (cr, x, lineArea, defaultBgColor, true);
bool isSelectionDrawn = false;
// Check if line is beyond the document length
if (line == null) {
DrawScrollShadow (cr, x, y, _lineHeight);
var marker = Document.GetExtendingTextMarker (lineNr);
if (marker != null)
marker.Draw (textEditor, cr, lineNr, lineArea);
return;
}
IEnumerable<FoldSegment> foldings = Document.GetStartFoldings (line);
int offset = line.Offset;
int caretOffset = Caret.Offset;
bool isEolFolded = false;
restart:
int logicalRulerColumn = line.GetLogicalColumn (textEditor.GetTextEditorData (), textEditor.Options.RulerColumn);
if ((HighlightCaretLine || textEditor.GetTextEditorData ().HighlightCaretLine) && Caret.Line == lineNr)
DrawCaretLineMarker (cr, x, y, TextStartPosition, _lineHeight);
foreach (FoldSegment folding in foldings) {
int foldOffset = folding.StartLine.Offset + folding.Column - 1;
if (foldOffset < offset)
continue;
if (folding.IsFolded) {
DrawLinePart (cr, line, lineNr, logicalRulerColumn, offset, foldOffset - offset, ref position, ref isSelectionDrawn, y, area.X + area.Width, _lineHeight);
offset = folding.EndLine.Offset + folding.EndColumn - 1;
markerLayout.SetText (folding.Description);
int width, height;
markerLayout.GetPixelSize (out width, out height);
bool isFoldingSelected = !this.HideSelection && textEditor.IsSomethingSelected && textEditor.SelectionRange.Contains (folding.Segment);
double pixelX = 0.5 + System.Math.Floor (position);
double foldXMargin = foldMarkerXMargin * textEditor.Options.Zoom;
double pixelWidth = System.Math.Floor (position + width - pixelX + foldXMargin * 2);
var foldingRectangle = new Cairo.Rectangle (
pixelX,
y,
pixelWidth,
this.LineHeight);
if (BackgroundRenderer == null && isFoldingSelected) {
cr.SetSourceColor (SelectionColor.Background);
cr.Rectangle (foldingRectangle);
cr.Fill ();
}
if (isFoldingSelected && SelectionColor.TransparentForeground) {
cr.SetSourceColor (ColorStyle.CollapsedText.Foreground);
} else {
cr.SetSourceColor (isFoldingSelected ? SelectionColor.Foreground : ColorStyle.CollapsedText.Foreground);
}
var boundingRectangleHeight = foldingRectangle.Height - 1;
var boundingRectangleY = System.Math.Floor (foldingRectangle.Y + (foldingRectangle.Height - boundingRectangleHeight) / 2);
RoundedRectangle (cr,
System.Math.Floor (foldingRectangle.X) + 0.5,
boundingRectangleY + 0.5,
System.Math.Floor (foldingRectangle.Width - cr.LineWidth),
System.Math.Floor (boundingRectangleHeight - cr.LineWidth),
LineHeight / 8, CairoCorners.All, false);
cr.Stroke ();
cr.Save ();
cr.Translate (
position + foldXMargin,
System.Math.Floor (boundingRectangleY + System.Math.Max (0, boundingRectangleHeight - height) / 2));
cr.ShowLayout (markerLayout);
cr.Restore ();
if (caretOffset == foldOffset && !string.IsNullOrEmpty (folding.Description)) {
var cx = (int)position;
SetVisibleCaretPosition (cx, y, cx, y);
}
position += foldingRectangle.Width;
if (caretOffset == foldOffset + folding.Length && !string.IsNullOrEmpty (folding.Description)) {
var cx = (int)position;
SetVisibleCaretPosition (cx, y, cx, y);
}
if (folding.EndLine != line) {
line = folding.EndLine;
lineNr = line.LineNumber;
foldings = Document.GetStartFoldings (line);
isEolFolded = line.Length <= folding.EndColumn;
goto restart;
}
isEolFolded = line.Length <= folding.EndColumn;
}
}
// Draw remaining line - must be called for empty line parts as well because the caret may be at this positon
// and the caret position is calculated in DrawLinePart.
if (line.EndOffsetIncludingDelimiter - offset >= 0) {
DrawLinePart (cr, line, lineNr, logicalRulerColumn, offset, line.Offset + line.Length - offset, ref position, ref isSelectionDrawn, y, area.X + area.Width, _lineHeight);
}
bool isEolSelected =
!this.HideSelection &&
textEditor.IsSomethingSelected &&
textEditor.SelectionMode == SelectionMode.Normal &&
textEditor.MainSelection.ContainsLine (lineNr) &&
textEditor.MainSelection.Contains (lineNr + 1, 1);
var lx = (int)position;
lineArea = new Cairo.Rectangle (lx,
lineArea.Y,
textEditor.Allocation.Width - lx,
lineArea.Height);
if (textEditor.SelectionMode == SelectionMode.Block && textEditor.IsSomethingSelected && textEditor.SelectionRange.Contains (line.Offset + line.Length)) {
DocumentLocation start = textEditor.MainSelection.Anchor;
DocumentLocation end = textEditor.MainSelection.Lead;
DocumentLocation visStart = textEditor.LogicalToVisualLocation (start);
DocumentLocation visEnd = textEditor.LogicalToVisualLocation (end);
double x1 = this.ColumnToX (line, visStart.Column);
double x2 = this.ColumnToX (line, visEnd.Column);
if (x1 > x2) {
var tmp = x1;
x1 = x2;
x2 = tmp;
}
x1 += correctedXOffset - textEditor.HAdjustment.Value;
x2 += correctedXOffset - textEditor.HAdjustment.Value;
if (x2 > lineArea.X && BackgroundRenderer == null) {
if (x1 - lineArea.X > 0) {
DrawRectangleWithRuler (cr, x, new Cairo.Rectangle (lineArea.X, lineArea.Y, x1 - lineArea.X, lineArea.Height), defaultBgColor, false);
lineArea = new Cairo.Rectangle (x1, lineArea.Y, lineArea.Width, lineArea.Height);
}
DrawRectangleWithRuler (cr, x, new Cairo.Rectangle (lineArea.X, lineArea.Y, x2 - lineArea.X, lineArea.Height), this.SelectionColor.Background, false);
lineArea = new Cairo.Rectangle (x2, lineArea.Y, textEditor.Allocation.Width - lineArea.X, lineArea.Height);
}
}
LayoutWrapper wrapper = null;
if (!isSelectionDrawn && BackgroundRenderer == null) {
if (isEolSelected) {
// prevent "gaps" in the selection drawing ('fuzzy' lines problem)
wrapper = GetLayout (line);
if (lineNr == textEditor.MainSelection.Start.Line && line.Length == 0 && textEditor.MainSelection.Start.Column > 1) {
using (var vwrapper = GetVirtualSpaceLayout (line, textEditor.MainSelection.Start)) {
lineArea = new Cairo.Rectangle (
lineArea.X + vwrapper.Width,
lineArea.Y + System.Math.Max (0, wrapper.Height - LineHeight),
textEditor.Allocation.Width - (lineArea.X + vwrapper.Width),
LineHeight
);
}
} else {
var eolStartX = System.Math.Floor (position);
lineArea = new Cairo.Rectangle (
eolStartX,
lineArea.Y + System.Math.Max (0, wrapper.Height - LineHeight),
textEditor.Allocation.Width - eolStartX,
LineHeight);
}
if (lineNr != textEditor.MainSelection.End.Line)
DrawRectangleWithRuler (cr, x, lineArea, this.SelectionColor.Background, false);
if (line.Length == 0)
DrawIndent (cr, wrapper, line, lx, y);
} else if (!(HighlightCaretLine || textEditor.GetTextEditorData ().HighlightCaretLine) || Caret.Line != lineNr && Caret.Line != startLineNr) {
wrapper = GetLayout (line);
if (wrapper.EolSpanStack != null) {
foreach (var span in wrapper.EolSpanStack) {
var spanStyle = textEditor.ColorStyle.GetChunkStyle (span.Color);
if (spanStyle == null)
continue;
if (!spanStyle.TransparentBackground && GetPixel (ColorStyle.PlainText.Background) != GetPixel (spanStyle.Background)) {
DrawRectangleWithRuler (cr, x, lineArea, spanStyle.Background, false);
break;
}
}
}
} else {
double xPos = position;
DrawCaretLineMarker (cr, xPos, y, lineArea.X + lineArea.Width - xPos, _lineHeight);
}
}
if (textEditor.Options.ShowWhitespaces != ShowWhitespaces.Never) {
switch (textEditor.Options.ShowWhitespaces) {
case ShowWhitespaces.Selection:
if (!isEolFolded && isEolSelected)
if (!(BackgroundRenderer != null && textEditor.Options.ShowWhitespaces == ShowWhitespaces.Selection))
if (textEditor.MainSelection.Contains (lineNr, 2 + line.Length) &&
!(lineNr == Caret.Line && Caret.Column > 1 && textEditor.MainSelection.Anchor.Line < textEditor.MainSelection.Lead.Line) &&
textEditor.MainSelection.Anchor.Line != textEditor.MainSelection.Lead.Line)
goto case ShowWhitespaces.Always;
break;
case ShowWhitespaces.Always:
if (wrapper == null)
wrapper = GetLayout (line);
DrawEolMarker (cr, line, isEolSelected, position, y + System.Math.Max (0, wrapper.Height - LineHeight));
break;
}
}
var extendingMarker = Document.GetExtendingTextMarker (lineNr);
if (extendingMarker != null)
extendingMarker.Draw (textEditor, cr, lineNr, lineArea);
if (BackgroundRenderer == null) {
var metrics = new EndOfLineMetrics {
LineSegment = line,
TextRenderEndPosition = TextStartPosition + position,
LineHeight = _lineHeight,
LineYRenderStartPosition = y
};
foreach (var marker in line.Markers) {
marker.DrawAfterEol (textEditor, cr, metrics);
}
}
lastLineRenderWidth = position;
DrawScrollShadow (cr, x, y, _lineHeight);
if (wrapper != null && wrapper.IsUncached)
wrapper.Dispose ();
}