public override void DrawAfterEol (TextEditor textEditor, Cairo.Context g, double y, EndOfLineMetrics metrics) { if (!IsVisible) return; EnsureLayoutCreated (editor); int errorCounterWidth = 0, eh = 0; if (errorCountLayout != null) { errorCountLayout.GetPixelSize (out errorCounterWidth, out eh); errorCounterWidth = Math.Max (15, Math.Max (errorCounterWidth + 3, (int)(editor.LineHeight * 3 / 4))); } var sx = metrics.TextRenderEndPosition; var width = LayoutWidth + errorCounterWidth + editor.LineHeight; var drawLayout = layouts[0].Layout; int ex = 0 , ey = 0; bool customLayout = true; //sx + width > editor.Allocation.Width; bool hideText = false; bubbleIsReduced = customLayout; var showErrorCount = errorCounterWidth > 0 && errorCountLayout != null; if (customLayout) { width = editor.Allocation.Width - sx; string text = layouts[0].Layout.Text; drawLayout = new Pango.Layout (editor.PangoContext); drawLayout.FontDescription = cache.fontDescription; var paintWidth = (width - errorCounterWidth - editor.LineHeight + 4); var minWidth = Math.Max (17, errorCounterWidth) + editor.LineHeight; if (paintWidth < minWidth) { hideText = true; drawLayout.SetMarkup ("<span weight='heavy'>···</span>"); width = minWidth; showErrorCount = false; sx = Math.Min (sx, editor.Allocation.Width - width); } else { drawLayout.Ellipsize = Pango.EllipsizeMode.End; drawLayout.Width = (int)(paintWidth * Pango.Scale.PangoScale); drawLayout.SetText (text); int w2, h2; drawLayout.GetPixelSize (out w2, out h2); width = w2 + errorCounterWidth + editor.LineHeight; } } bubbleDrawX = sx - editor.TextViewMargin.XOffset; bubbleDrawY = y; bubbleWidth = width; var bubbleHeight = editor.LineHeight - 1; g.RoundedRectangle (sx, y + 1, width, bubbleHeight, editor.LineHeight / 2 - 1); g.SetSourceColor (TagColor.Color); g.Fill (); // Draw error count icon if (showErrorCount) { var errorCounterHeight = bubbleHeight - 2; var errorCounterX = sx + width - errorCounterWidth - 3; var errorCounterY = y + 1 + (bubbleHeight - errorCounterHeight) / 2; g.RoundedRectangle ( errorCounterX - 1, errorCounterY - 1, errorCounterWidth + 2, errorCounterHeight + 2, editor.LineHeight / 2 - 3 ); g.SetSourceColor (new Cairo.Color (0, 0, 0, 0.081)); g.Fill (); g.RoundedRectangle ( errorCounterX, errorCounterY, errorCounterWidth, errorCounterHeight, editor.LineHeight / 2 - 3 ); using (var lg = new Cairo.LinearGradient (errorCounterX, errorCounterY, errorCounterX, errorCounterY + errorCounterHeight)) { lg.AddColorStop (0, CounterColor.Color); lg.AddColorStop (1, CounterColor.Color.AddLight (-0.1)); g.Pattern = lg; g.Fill (); } g.Save (); int ew; errorCountLayout.GetPixelSize (out ew, out eh); g.Translate ( errorCounterX + (errorCounterWidth - ew) / 2, errorCounterY + (errorCounterHeight - eh) / 2 ); g.SetSourceColor (CounterColor.SecondColor); g.ShowLayout (errorCountLayout); g.Restore (); } // Draw label text if (!showErrorCount || !hideText) { g.Save (); g.Translate (sx + editor.LineHeight / 2, y + (editor.LineHeight - layouts [0].Height) / 2 + 1); // draw shadow g.SetSourceColor (MessageBubbleCache.ShadowColor); g.ShowLayout (drawLayout); g.Translate (0, -1); g.SetSourceColor (TagColor.SecondColor); g.ShowLayout (drawLayout); g.Restore (); } if (customLayout) drawLayout.Dispose (); }
public override void DrawAfterEol (TextEditor textEditor, Cairo.Context g, double y, EndOfLineMetrics metrics) { EnsureLayoutCreated (editor); int errorCounterWidth = 0, eh = 0; if (errorCountLayout != null) errorCountLayout.GetPixelSize (out errorCounterWidth, out eh); var sx = metrics.TextRenderEndPosition; var width = LayoutWidth + errorCounterWidth + editor.LineHeight; var drawLayout = layouts[0].Layout; int ex = 0 , ey = 0; bool customLayout = sx + width > editor.Allocation.Width; bool hideText = false; bubbleIsReduced = customLayout; if (customLayout) { width = editor.Allocation.Width - sx; string text = layouts[0].Layout.Text; drawLayout = new Pango.Layout (editor.PangoContext); drawLayout.FontDescription = cache.fontDescription; for (int j = text.Length - 4; j > 0; j--) { drawLayout.SetText (text.Substring (0, j) + "..."); drawLayout.GetPixelSize (out ex, out ey); if (ex + (errorCountLayout != null ? errorCounterWidth : 0) + editor.LineHeight < width) break; } if (ex + (errorCountLayout != null ? errorCounterWidth : 0) + editor.LineHeight > width) { hideText = true; drawLayout.SetMarkup ("<span weight='heavy'>···</span>"); width = Math.Max (17, errorCounterWidth) + editor.LineHeight; sx = Math.Min (sx, editor.Allocation.Width - width); } } bubbleDrawX = sx - editor.TextViewMargin.XOffset; bubbleDrawY = y; bubbleWidth = width; g.RoundedRectangle (sx, y + 1, width, editor.LineHeight - 2, editor.LineHeight / 2 - 1); g.Color = TagColor.Color; g.Fill (); if (errorCounterWidth > 0 && errorCountLayout != null) { g.RoundedRectangle (sx + width - errorCounterWidth - editor.LineHeight / 2, y + 2, errorCounterWidth, editor.LineHeight - 4, editor.LineHeight / 2 - 3); g.Color = CounterColor.Color; g.Fill (); g.Save (); g.Translate (sx + width - errorCounterWidth - editor.LineHeight / 2 + (errorCounterWidth - errorCounterWidth) / 2, y + 1); g.Color = CounterColor.SecondColor; g.ShowLayout (errorCountLayout); g.Restore (); } if (errorCounterWidth <= 0 || errorCountLayout == null || !hideText) { g.Save (); g.Translate (sx + editor.LineHeight / 2, y + (editor.LineHeight - layouts [0].Height) / 2 + layouts [0].Height % 2); g.Color = TagColor.SecondColor; g.ShowLayout (drawLayout); g.Restore (); } if (customLayout) drawLayout.Dispose (); }
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); int width, height; double pangoPosition = (x - textEditor.HAdjustment.Value + TextStartPosition) * Pango.Scale.PangoScale; defaultBgColor = Document.ReadOnly ? ColorStyle.BackgroundReadOnly.Color : ColorStyle.PlainText.Background; // 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) { 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.Options.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 pangoPosition, ref isSelectionDrawn, y, area.X + area.Width, _lineHeight); offset = folding.EndLine.Offset + folding.EndColumn - 1; markerLayout.SetText (folding.Description); markerLayout.GetSize (out width, out height); bool isFoldingSelected = !this.HideSelection && textEditor.IsSomethingSelected && textEditor.SelectionRange.Contains (folding.Segment); double pixelX = 0.5 + System.Math.Floor (pangoPosition / Pango.Scale.PangoScale); double foldXMargin = foldMarkerXMargin * textEditor.Options.Zoom; double pixelWidth = System.Math.Floor ((pangoPosition + width) / Pango.Scale.PangoScale - pixelX + foldXMargin * 2); var foldingRectangle = new Cairo.Rectangle ( pixelX, y, pixelWidth, this.LineHeight); if (BackgroundRenderer == null && isFoldingSelected) { cr.Color = SelectionColor.Background; cr.Rectangle (foldingRectangle); cr.Fill (); } if (isFoldingSelected && SelectionColor.TransparentForeground) { cr.Color = ColorStyle.CollapsedText.Foreground; } else { cr.Color = 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 ( pangoPosition / Pango.Scale.PangoScale + foldXMargin, System.Math.Floor (boundingRectangleY + (boundingRectangleHeight - System.Math.Floor (height / Pango.Scale.PangoScale)) / 2)); cr.ShowLayout (markerLayout); cr.Restore (); if (caretOffset == foldOffset && !string.IsNullOrEmpty (folding.Description)) { var cx = (int)(pangoPosition / Pango.Scale.PangoScale); SetVisibleCaretPosition (cx, y, cx, y); } pangoPosition += foldingRectangle.Width * Pango.Scale.PangoScale; if (caretOffset == foldOffset + folding.Length && !string.IsNullOrEmpty (folding.Description)) { var cx = (int)(pangoPosition / Pango.Scale.PangoScale); 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 pangoPosition, ref isSelectionDrawn, y, area.X + area.Width, _lineHeight); } bool isEolSelected = !this.HideSelection && textEditor.IsSomethingSelected && textEditor.SelectionMode == SelectionMode.Normal && textEditor.SelectionRange.Contains (line.Offset + line.Length); var lx = (int)(pangoPosition / Pango.Scale.PangoScale); 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); } } if (!isSelectionDrawn && BackgroundRenderer == null) { if (isEolSelected) { // prevent "gaps" in the selection drawing ('fuzzy' lines problem) var eolStartX = System.Math.Floor (pangoPosition / Pango.Scale.PangoScale); lineArea = new Cairo.Rectangle ( eolStartX, lineArea.Y, textEditor.Allocation.Width - eolStartX, lineArea.Height); DrawRectangleWithRuler (cr, x, lineArea, this.SelectionColor.Background, false); if (line.Length == 0) DrawIndent (cr, GetLayout (line), line, lx, y); } else if (!(HighlightCaretLine || textEditor.Options.HighlightCaretLine) || Caret.Line != lineNr) { LayoutWrapper 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 = pangoPosition / Pango.Scale.PangoScale; DrawCaretLineMarker (cr, xPos, y, lineArea.X + lineArea.Width - xPos, _lineHeight); } } if (textEditor.Options.ShowWhitespaces != ShowWhitespaces.Never) { if (!isEolFolded && isEolSelected || textEditor.Options.ShowWhitespaces == ShowWhitespaces.Always) if (!(BackgroundRenderer != null && textEditor.Options.ShowWhitespaces == ShowWhitespaces.Selection)) DrawEolMarker (cr, line, isEolSelected, pangoPosition / Pango.Scale.PangoScale, y); } 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 + pangoPosition / Pango.Scale.PangoScale, LineHeight = _lineHeight }; foreach (var marker in line.Markers) { marker.DrawAfterEol (textEditor, cr, y, metrics); } } lastLineRenderWidth = pangoPosition / Pango.Scale.PangoScale; if (textEditor.HAdjustment.Value > 0) { cr.LineWidth = textEditor.Options.Zoom; for (int i = 0; i < verticalShadowAlphaTable.Length; i++) { cr.Color = new Cairo.Color (0, 0, 0, 1 - verticalShadowAlphaTable[i]); cr.MoveTo (x + i * cr.LineWidth + 0.5, y); cr.LineTo (x + i * cr.LineWidth + 0.5, y + 1 + _lineHeight); cr.Stroke (); } } }
public override void DrawAfterEol (MonoTextEditor textEditor, Cairo.Context g, EndOfLineMetrics metrics) { if (!IsVisible) return; EnsureLayoutCreated (editor); int errorCounterWidth = 0, eh = 0; if (errorCountLayout != null) { errorCountLayout.GetPixelSize (out errorCounterWidth, out eh); errorCounterWidth = Math.Max (15, Math.Max (errorCounterWidth + 3, (int)(editor.LineHeight * 3 / 4))); } var sx = metrics.TextRenderEndPosition; var width = LayoutWidth + errorCounterWidth + editor.LineHeight; var drawLayout = layouts[0].Layout; var y = metrics.LineYRenderStartPosition; bool customLayout = true; //sx + width > editor.Allocation.Width; bool hideText = false; bubbleIsReduced = customLayout; var showErrorCount = errorCounterWidth > 0 && errorCountLayout != null; double roundingRadius = editor.LineHeight / 2 - 1; if (customLayout) { width = editor.Allocation.Width - sx; string text = layouts[0].Layout.Text; drawLayout = new Pango.Layout (editor.PangoContext); drawLayout.FontDescription = cache.fontDescription; var paintWidth = (width - errorCounterWidth - editor.LineHeight + 4); var minWidth = Math.Max (25, errorCounterWidth) * editor.Options.Zoom; if (paintWidth < minWidth) { hideText = true; showErrorCount = false; // drawLayout.SetMarkup ("<span weight='heavy'>···</span>"); width = minWidth; //roundingRadius = 10 * editor.Options.Zoom; sx = Math.Min (sx, editor.Allocation.Width - width); } else { drawLayout.Ellipsize = Pango.EllipsizeMode.End; drawLayout.Width = (int)(paintWidth * Pango.Scale.PangoScale); drawLayout.SetText (text); int w2, h2; drawLayout.GetPixelSize (out w2, out h2); width = w2 + errorCounterWidth + editor.LineHeight - 2; } } bubbleDrawX = sx - editor.TextViewMargin.XOffset; bubbleDrawY = y + 2; bubbleWidth = width; var bubbleHeight = editor.LineHeight; g.RoundedRectangle (sx, y, width, bubbleHeight, roundingRadius); g.SetSourceColor (TagColor.Color); g.Fill (); // Draw error count icon if (showErrorCount) { var errorCounterHeight = bubbleHeight - 2; var errorCounterX = sx + width - errorCounterWidth - 1; var errorCounterY = Math.Round (y + (bubbleHeight - errorCounterHeight) / 2); g.RoundedRectangle ( errorCounterX, errorCounterY, errorCounterWidth, errorCounterHeight, editor.LineHeight / 2 - 2 ); using (var lg = new Cairo.LinearGradient (errorCounterX, errorCounterY, errorCounterX, errorCounterY + errorCounterHeight)) { lg.AddColorStop (0, CounterColor.Color); lg.AddColorStop (1, CounterColor.Color.AddLight (-0.1)); g.SetSource (lg); g.Fill (); } g.Save (); int ew; errorCountLayout.GetPixelSize (out ew, out eh); var tx = Math.Round (errorCounterX + (2 + errorCounterWidth - ew) / 2); var ty = Math.Round (errorCounterY + (-1 + errorCounterHeight - eh) / 2); g.Translate (tx, ty); g.SetSourceColor (CounterColor.SecondColor); g.ShowLayout (errorCountLayout); g.Restore (); } if (hideText) { // Draw dots double radius = 2 * editor.Options.Zoom; double spacing = 1 * editor.Options.Zoom; sx += 1 * editor.Options.Zoom + Math.Ceiling((bubbleWidth - 3 * (radius * 2) - 2 * spacing) / 2); for (int i = 0; i < 3; i++) { g.Arc (sx, y + bubbleHeight / 2, radius, 0, Math.PI * 2); g.SetSourceColor (TagColor.SecondColor); g.Fill (); sx += radius * 2 + spacing; } } else { // Draw label text var tx = Math.Round (sx + editor.LineHeight / 2); var ty = Math.Round (y + (editor.LineHeight - layouts [0].Height) / 2) - 1; g.Save (); g.Translate (tx, ty); g.SetSourceColor (TagColor.SecondColor); g.ShowLayout (drawLayout); g.Restore (); } if (customLayout) drawLayout.Dispose (); }
/// <summary> /// Is used to draw in the area after the visible text. /// </summary> public virtual void DrawAfterEol (TextEditor textEditor, Cairo.Context cr, double y, EndOfLineMetrics lineHeight) { }
/// <summary> /// Is used to draw in the area after the visible text. /// </summary> public virtual void DrawAfterEol(MonoTextEditor textEditor, Cairo.Context cr, EndOfLineMetrics metrics) { }
/// <summary> /// Is used to draw in the area after the visible text. /// </summary> public virtual void DrawAfterEol(TextEditor textEditor, Cairo.Context cr, double y, EndOfLineMetrics lineHeight) { }
/// <summary> /// Is used to draw in the area after the visible text. /// </summary> public virtual void DrawAfterEol (MonoTextEditor textEditor, Cairo.Context cr, EndOfLineMetrics metrics) { }