void DrawTextLine (Cairo.Context g, IReadonlyTextDocument document, int lineNumber, ref int y) { using (var drawingLayout = new Pango.Layout (this.PangoContext)) { drawingLayout.FontDescription = fontDescription; var line = document.GetLine (lineNumber); var correctedIndentLength = CorrectIndent (document, line, indentLength); drawingLayout.SetText (document.GetTextAt (line.Offset + Math.Min (correctedIndentLength, line.Length), Math.Max (0, line.Length - correctedIndentLength))); g.Save (); g.Translate (textBorder, y); g.ShowLayout (drawingLayout); g.Restore (); y += lineHeight; } }
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 (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 (); }
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 (); }
void DrawLinePart (Cairo.Context cr, DocumentLine line, int lineNumber, int logicalRulerColumn, int offset, int length, ref double pangoPosition, ref bool isSelectionDrawn, double y, double maxX, double _lineHeight) { ISyntaxMode mode = Document.SyntaxMode != null && textEditor.Options.EnableSyntaxHighlighting ? Document.SyntaxMode : new SyntaxMode (Document); int selectionStart; int selectionEnd; if (this.HideSelection) { selectionStart = selectionEnd = -1; } else { GetSelectionOffsets (line, out selectionStart, out selectionEnd); } // ---- new renderer LayoutWrapper layout = CreateLinePartLayout (mode, line, logicalRulerColumn, offset, length, selectionStart, selectionEnd); int lineOffset = line.Offset; double width = layout.PangoWidth / Pango.Scale.PangoScale; double xPos = pangoPosition / Pango.Scale.PangoScale; // The caret line marker must be drawn below the text markers otherwise the're invisible if ((HighlightCaretLine || textEditor.Options.HighlightCaretLine) && Caret.Line == lineNumber) DrawCaretLineMarker (cr, xPos, y, layout.PangoWidth / Pango.Scale.PangoScale, _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 + pangoPosition) / Pango.Scale.PangoScale, y, (x2 - x1) / Pango.Scale.PangoScale + 1, _lineHeight), bg.Color, true); } } bool drawBg = true; bool drawText = true; LineMetrics metrics = new LineMetrics { LineSegment = line, Layout = layout, SelectionStart = selectionStart, SelectionEnd = selectionEnd, TextStartOffset = offset, TextEndOffset = offset + length, TextRenderStartPosition = xPos, TextRenderEndPosition = xPos + width, LineHeight = _lineHeight, WholeLineWidth = textEditor.Allocation.Width - xPos }; foreach (TextLineMarker marker in line.Markers) { if (!marker.IsVisible) continue; if (marker.DrawBackground (textEditor, cr, y, metrics)) { isSelectionDrawn |= (marker.Flags & TextLineMarkerFlags.DrawsSelection) == TextLineMarkerFlags.DrawsSelection; } var bgMarker = marker as IBackgroundMarker; if (bgMarker != null) { isSelectionDrawn |= (marker.Flags & TextLineMarkerFlags.DrawsSelection) == TextLineMarkerFlags.DrawsSelection; drawText &= bgMarker.DrawBackground (textEditor, cr, metrics.Layout, metrics.SelectionStart, metrics.SelectionEnd, metrics.TextStartOffset, metrics.TextEndOffset, y, metrics.TextRenderStartPosition, metrics.TextRenderEndPosition, ref drawBg); continue; } } if (DecorateLineBg != null) DecorateLineBg (cr, layout, offset, length, xPos, y, selectionStart, selectionEnd); if (!isSelectionDrawn && (layout.StartSet || selectionStart == offset + length) && BackgroundRenderer == null) { double startX; double endX; if (selectionStart != offset + length) { var start = layout.Layout.IndexToPos ((int)layout.SelectionStartIndex); startX = System.Math.Floor (start.X / Pango.Scale.PangoScale); var end = layout.Layout.IndexToPos ((int)layout.SelectionEndIndex); endX = System.Math.Ceiling (end.X / Pango.Scale.PangoScale); } else { startX = width; endX = startX; } if (textEditor.MainSelection.SelectionMode == SelectionMode.Block && startX == endX) { endX = startX + 2; } DrawRectangleWithRuler (cr, xPos + textEditor.HAdjustment.Value - TextStartPosition, new Cairo.Rectangle (xPos + startX, y, endX - startX, _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 = pangoPosition; HandleSelection (lineOffset, logicalRulerColumn, selectionStart, selectionEnd, 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 + x) / Pango.Scale.PangoScale); double corner = System.Math.Min (4, width) * textEditor.Options.Zoom; cr.Color = 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, length, xPos, y, selectionStart, selectionEnd); if (lineNumber == Caret.Line) { int caretOffset = Caret.Offset; if (offset <= caretOffset && caretOffset <= offset + length) { int index = caretOffset - offset; if (Caret.Column > line.Length + 1) { string virtualSpace = ""; var data = textEditor.GetTextEditorData (); if (data.HasIndentationTracker && line.Length == 0) { virtualSpace = this.textEditor.GetTextEditorData ().GetIndentationString (Caret.Location); } if (Caret.Column > line.Length + 1 + virtualSpace.Length) virtualSpace += new string (' ', Caret.Column - line.Length - 1 - virtualSpace.Length); // predit layout already contains virtual space. if (!string.IsNullOrEmpty (textEditor.preeditString)) virtualSpace = ""; LayoutWrapper wrapper = new LayoutWrapper (PangoUtil.CreateLayout (textEditor)); wrapper.LineChars = virtualSpace.ToCharArray (); wrapper.Layout.SetText (virtualSpace); wrapper.Layout.Tabs = tabArray; wrapper.Layout.FontDescription = textEditor.Options.Font; int vy, vx; wrapper.Layout.GetSize (out vx, out vy); var x = ((pangoPosition + vx + layout.PangoWidth) / Pango.Scale.PangoScale); SetVisibleCaretPosition (x, y, x, y); xPos = (pangoPosition + layout.PangoWidth) / Pango.Scale.PangoScale; if (!isSelectionDrawn && (selectionEnd == lineOffset + line.Length) && BackgroundRenderer == null) { double startX; double endX; startX = xPos; endX = (pangoPosition + vx + layout.PangoWidth) / Pango.Scale.PangoScale; DrawRectangleWithRuler (cr, xPos + textEditor.HAdjustment.Value - TextStartPosition, new Cairo.Rectangle (startX, y, endX - startX, _lineHeight), this.SelectionColor.Background, true); } // When drawing virtual space before the selection start paint it as unselected. var virtualSpaceMod = selectionStart < caretOffset ? 0 : virtualSpace.Length; if ((!textEditor.IsSomethingSelected || (selectionStart >= offset && selectionStart != selectionEnd)) && (HighlightCaretLine || textEditor.Options.HighlightCaretLine) && Caret.Line == lineNumber) DrawCaretLineMarker (cr, pangoPosition / Pango.Scale.PangoScale, y, vx / Pango.Scale.PangoScale, _lineHeight); if (DecorateLineBg != null) DecorateLineBg (cr, wrapper, offset, length, xPos, y, selectionStart + virtualSpaceMod, selectionEnd + virtualSpace.Length); switch (textEditor.Options.ShowWhitespaces) { case ShowWhitespaces.Selection: if (textEditor.IsSomethingSelected && (selectionStart < offset || selectionStart == selectionEnd) && BackgroundRenderer == null) DecorateTabsAndSpaces (cr, wrapper, offset, length, xPos, y, selectionStart, selectionEnd + virtualSpace.Length); break; case ShowWhitespaces.Always: DecorateTabsAndSpaces (cr, wrapper, offset, length, xPos, y, selectionStart, selectionEnd + virtualSpace.Length); break; } wrapper.Dispose (); pangoPosition += vx; } else if (index == length && string.IsNullOrEmpty (textEditor.preeditString)) { var x = (pangoPosition + layout.PangoWidth) / Pango.Scale.PangoScale; 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, y, metrics); } foreach (var marker in Document.GetTextSegmentMarkersAt (line).Where (m => m.IsVisible)) { if (layout.Layout != null) marker.Draw (textEditor, cr, layout.Layout, false, /*selected*/offset, offset + length, y, xPos, xPos + width); } pangoPosition += layout.PangoWidth; int scaledDown = (int)(pangoPosition / Pango.Scale.PangoScale); pangoPosition = scaledDown * Pango.Scale.PangoScale; if (layout.IsUncached) layout.Dispose (); }
protected internal override void Draw (Cairo.Context cr, Cairo.Rectangle area, LineSegment line, int lineNr, double x, double y, double _lineHeight) { // double xStart = System.Math.Max (area.X, XOffset); // xStart = System.Math.Max (0, xStart); var lineArea = new Cairo.Rectangle (XOffset - 1, y, textEditor.Allocation.Width - XOffset + 1, _lineHeight); int width, height; double pangoPosition = (x - textEditor.HAdjustment.Value + TextStartPosition) * Pango.Scale.PangoScale; defaultBgColor = Document.ReadOnly ? ColorStyle.ReadOnlyTextBg : ColorStyle.Default.CairoBackgroundColor; // Draw the default back color for the whole line. Colors other than the default // background will be drawn when rendering the text chunks. DrawRectangleWithRuler (cr, x, lineArea, defaultBgColor, true); bool isSelectionDrawn = false; if (BackgroundRenderer != null) BackgroundRenderer.Draw (cr, area, line, x, y, _lineHeight); // Check if line is beyond the document length if (line == null) { if (textEditor.Options.ShowInvalidLines) DrawInvalidLineMarker (cr, pangoPosition / Pango.Scale.PangoScale, y); 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); 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); offset = folding.EndLine.Offset + folding.EndColumn; markerLayout.SetText (folding.Description); markerLayout.GetSize (out width, out height); bool isFoldingSelected = !this.HideSelection && textEditor.IsSomethingSelected && textEditor.SelectionRange.Contains (folding.Segment); double pixelX = pangoPosition / Pango.Scale.PangoScale; double pixelWidth = (pangoPosition + width) / Pango.Scale.PangoScale - pixelX; var foldingRectangle = new Cairo.Rectangle (pixelX + 0.5, y + 0.5, pixelWidth - cr.LineWidth, this.LineHeight - cr.LineWidth); if (BackgroundRenderer == null) { cr.Color = isFoldingSelected ? SelectionColor.CairoBackgroundColor : defaultBgColor; cr.Rectangle (foldingRectangle); cr.Fill (); } cr.Color = isFoldingSelected ? SelectionColor.CairoColor : ColorStyle.FoldLine.CairoColor; cr.Rectangle (foldingRectangle); cr.Stroke (); cr.Save (); cr.Translate (pangoPosition / Pango.Scale.PangoScale, y); cr.Color = isFoldingSelected ? SelectionColor.CairoColor : ColorStyle.FoldLine.CairoColor; cr.ShowLayout (markerLayout); cr.Restore (); if (caretOffset == foldOffset && !string.IsNullOrEmpty (folding.Description)) SetVisibleCaretPosition ((int)(pangoPosition / Pango.Scale.PangoScale), y); pangoPosition += width; if (caretOffset == foldOffset + folding.Length && !string.IsNullOrEmpty (folding.Description)) SetVisibleCaretPosition ((int)(pangoPosition / Pango.Scale.PangoScale), y); if (folding.EndLine != line) { line = folding.EndLine; lineNr = Document.OffsetToLineNumber (line.Offset); 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); bool isEolSelected = !this.HideSelection && textEditor.IsSomethingSelected && textEditor.SelectionMode == SelectionMode.Normal && textEditor.SelectionRange.Contains (line.Offset + line.Length); lineArea = new Cairo.Rectangle (pangoPosition / Pango.Scale.PangoScale, lineArea.Y, textEditor.Allocation.Width - pangoPosition / Pango.Scale.PangoScale, 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 += XOffset - textEditor.HAdjustment.Value; x2 += XOffset - textEditor.HAdjustment.Value; if (x2 > lineArea.X) { 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.CairoBackgroundColor, false); lineArea = new Cairo.Rectangle (x2, lineArea.Y, textEditor.Allocation.Width - lineArea.X, lineArea.Height); } } if (!isSelectionDrawn) { if (isEolSelected) { if (!Platform.IsMac) { // prevent "gaps" in the selection drawing ('fuzzy' lines problem) lineArea = new Cairo.Rectangle (pangoPosition / Pango.Scale.PangoScale, lineArea.Y, textEditor.Allocation.Width - pangoPosition / Pango.Scale.PangoScale + 1, lineArea.Height); } else { // prevent "gaps" in the selection drawing ('fuzzy' lines problem) lineArea = new Cairo.Rectangle (pangoPosition / Pango.Scale.PangoScale - 1, lineArea.Y, textEditor.Allocation.Width - pangoPosition / Pango.Scale.PangoScale + 1, lineArea.Height); } DrawRectangleWithRuler (cr, x, lineArea, this.SelectionColor.CairoBackgroundColor, false); } 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.TransparentBackround && GetPixel (ColorStyle.Default.BackgroundColor) != GetPixel (spanStyle.BackgroundColor)) { DrawRectangleWithRuler (cr, x, lineArea, spanStyle.CairoBackgroundColor, false); break; } } } } else { double xPos = pangoPosition / Pango.Scale.PangoScale; DrawCaretLineMarker (cr, xPos, y, lineArea.X + lineArea.Width - xPos); } } if (!isEolFolded && textEditor.Options.ShowEolMarkers) DrawEolMarker (cr, line, isEolSelected, pangoPosition / Pango.Scale.PangoScale, y); var extendingMarker = Document.GetExtendingTextMarker (lineNr); if (extendingMarker != null) extendingMarker.Draw (textEditor, cr, lineNr, lineArea); lastLineRenderWidth = pangoPosition / Pango.Scale.PangoScale; }
public bool DrawBackground (TextEditor editor, Cairo.Context g, TextViewMargin.LayoutWrapper layout2, int selectionStart, int selectionEnd, int startOffset, int endOffset, double y, double startXPos, double endXPos, ref bool drawBg) { if (!IsVisible || DebuggingService.IsDebugging) return true; EnsureLayoutCreated (editor); double x = editor.TextViewMargin.XOffset; int right = editor.Allocation.Width; int errorCounterWidth = 0; bool isCaretInLine = startOffset <= editor.Caret.Offset && editor.Caret.Offset <= endOffset; int ew = 0, eh = 0; if (errors.Count > 1 && errorCountLayout != null) { errorCountLayout.GetPixelSize (out ew, out eh); errorCounterWidth = ew + 10; } double x2 = System.Math.Max (right - LayoutWidth - border - (ShowIconsInBubble ? errorPixbuf.Width : 0) - errorCounterWidth, fitsInSameLine ? editor.TextViewMargin.XOffset + editor.LineHeight / 2 : editor.TextViewMargin.XOffset); bool isEolSelected = editor.IsSomethingSelected && editor.SelectionMode != SelectionMode.Block ? editor.SelectionRange.Contains (lineSegment.Offset + lineSegment.EditableLength) : false; int active = editor.Document.GetTextAt (lineSegment) == initialText ? 0 : 1; int highlighted = active == 0 && isCaretInLine ? 1 : 0; int selected = 0; double topSize = editor.LineHeight / 2; double bottomSize = editor.LineHeight / 2 + editor.LineHeight % 2; if (!fitsInSameLine) { if (isEolSelected) { x -= (int)editor.HAdjustment.Value; editor.TextViewMargin.DrawRectangleWithRuler (g, x, new Cairo.Rectangle (x, y + editor.LineHeight, editor.TextViewMargin.TextStartPosition, editor.LineHeight), editor.ColorStyle.Default.CairoBackgroundColor, true); editor.TextViewMargin.DrawRectangleWithRuler (g, x + editor.TextViewMargin.TextStartPosition, new Cairo.Rectangle (x + editor.TextViewMargin.TextStartPosition, y + editor.LineHeight, editor.Allocation.Width + (int)editor.HAdjustment.Value, editor.LineHeight), editor.ColorStyle.Selection.CairoBackgroundColor, true); x += (int)editor.HAdjustment.Value; } else { editor.TextViewMargin.DrawRectangleWithRuler (g, x, new Cairo.Rectangle (x, y + editor.LineHeight, x2, editor.LineHeight), editor.ColorStyle.Default.CairoBackgroundColor, true); } } DrawRectangle (g, x, y, right, topSize); g.Color = colorMatrix[active, TOP, LIGHT, highlighted, selected]; g.Fill (); DrawRectangle (g, x, y + topSize, right, bottomSize); g.Color = colorMatrix[active, BOTTOM, LIGHT, highlighted, selected]; g.Fill (); g.MoveTo (new Cairo.PointD (x, y + 0.5)); g.LineTo (new Cairo.PointD (x + right, y + 0.5)); g.Color = colorMatrix[active, TOP, LINE, highlighted, selected]; g.Stroke (); g.MoveTo (new Cairo.PointD (x, y + editor.LineHeight - 0.5)); g.LineTo (new Cairo.PointD ((fitsInSameLine ? x + right : x2 + 1), y + editor.LineHeight - 0.5)); g.Color = colorMatrix[active, BOTTOM, LINE, highlighted, selected]; g.Stroke (); if (editor.Options.ShowRuler) { double divider = Math.Max (editor.TextViewMargin.XOffset, x + editor.TextViewMargin.RulerX); g.MoveTo (new Cairo.PointD (divider + 0.5, y)); g.LineTo (new Cairo.PointD (divider + 0.5, y + editor.LineHeight)); g.Color = colorMatrix[active, BOTTOM, LINE, highlighted, selected]; g.Stroke (); } // draw background if (layout2.StartSet || selectionStart == endOffset) { double startX; double endX; if (selectionStart != endOffset) { var start = layout2.Layout.IndexToPos ((int)layout2.SelectionStartIndex); startX = (int)(start.X / Pango.Scale.PangoScale); var end = layout2.Layout.IndexToPos ((int)layout2.SelectionEndIndex); endX = (int)(end.X / Pango.Scale.PangoScale); } else { startX = x2; endX = startX; } if (editor.MainSelection.SelectionMode == SelectionMode.Block && startX == endX) endX = startX + 2; startX += startXPos; endX += startXPos; startX = Math.Max (editor.TextViewMargin.XOffset, startX); // clip region to textviewmargin start if (isEolSelected) endX = editor.Allocation.Width + (int)editor.HAdjustment.Value; if (startX < endX) { DrawRectangle (g, startX, y, endX - startX, topSize); g.Color = colorMatrix[active, TOP, LIGHT, highlighted, 1]; g.Fill (); DrawRectangle (g, startX, y + topSize, endX - startX, bottomSize); g.Color = colorMatrix[active, BOTTOM, LIGHT, highlighted, 1]; g.Fill (); g.MoveTo (new Cairo.PointD (startX, y + 0.5)); g.LineTo (new Cairo.PointD (endX, y + 0.5)); g.Color = colorMatrix[active, TOP, LINE, highlighted, 1]; g.Stroke (); if (startX < x2) { g.MoveTo (new Cairo.PointD (startX, y + editor.LineHeight - 0.5)); g.LineTo (new Cairo.PointD (System.Math.Min (endX, x2 + 1), y + editor.LineHeight - 0.5)); g.Color = colorMatrix[active, BOTTOM, LINE, highlighted, 1]; g.Stroke (); if (x2 + 1 < endX) { g.MoveTo (new Cairo.PointD (x2 + 1, y + editor.LineHeight - 0.5)); g.LineTo (new Cairo.PointD (endX, y + editor.LineHeight - 0.5)); g.Color = colorMatrix[active, BOTTOM, LIGHT, highlighted, 1]; g.Stroke (); } } if (editor.Options.ShowRuler) { double divider = Math.Max (editor.TextViewMargin.XOffset, x + editor.TextViewMargin.RulerX); g.MoveTo (new Cairo.PointD (divider + 0.5, y)); g.LineTo (new Cairo.PointD (divider + 0.5, y + editor.LineHeight)); g.Color = colorMatrix[active, BOTTOM, LINE, highlighted, 1]; g.Stroke (); } } } if (!fitsInSameLine) y += editor.LineHeight; double y2 = y + 0.5; double y2Bottom = y2 + editor.LineHeight - 1; selected = isEolSelected && (CollapseExtendedErrors || errors.Count == 1) ? 1 : 0; // draw message text background if (CollapseExtendedErrors || errors.Count == 1) { if (!fitsInSameLine) { // draw box below line g.MoveTo (new Cairo.PointD (x2 + 0.5, y2 - 1)); g.LineTo (new Cairo.PointD (x2 + 0.5, y2Bottom)); g.LineTo (new Cairo.PointD (right, y2Bottom)); g.LineTo (new Cairo.PointD (right, y2 - 1)); g.ClosePath (); g.Color = colorMatrix[active, BOTTOM, LIGHT, highlighted, selected]; g.Fill (); g.MoveTo (new Cairo.PointD (x2 + 0.5, y2 - 1)); g.LineTo (new Cairo.PointD (x2 + 0.5, y2Bottom)); g.LineTo (new Cairo.PointD (right, y2Bottom)); g.Color = colorMatrix[active, BOTTOM, LINE, highlighted, selected]; g.Stroke (); } else { // draw 'arrow marker' in the same line g.MoveTo (new Cairo.PointD (x2 + 0.5, y2)); double mid = y2 + topSize; g.LineTo (new Cairo.PointD (x2 - editor.LineHeight / 2 + 0.5, mid)); g.LineTo (new Cairo.PointD (right, mid)); g.LineTo (new Cairo.PointD (right, y2)); g.ClosePath (); g.Color = colorMatrix[active, TOP, DARK, highlighted, selected]; g.Fill (); g.MoveTo (new Cairo.PointD (x2 + 0.5, y2Bottom)); g.LineTo (new Cairo.PointD (x2 - editor.LineHeight / 2 + 0.5, mid)); g.LineTo (new Cairo.PointD (right, mid)); g.LineTo (new Cairo.PointD (right, y2Bottom)); g.ClosePath (); g.Color = colorMatrix[active, BOTTOM, DARK, highlighted, selected]; g.Fill (); // draw border g.MoveTo (new Cairo.PointD (x2 + 0.5, y2)); g.LineTo (new Cairo.PointD (x2 - editor.LineHeight / 2 + 0.5, y2 + editor.LineHeight / 2)); g.LineTo (new Cairo.PointD (x2 + 0.5, y2Bottom)); g.LineTo (new Cairo.PointD (right, y2Bottom)); g.LineTo (new Cairo.PointD (right, y2)); g.ClosePath (); g.Color = colorMatrix[active, BOTTOM, LINE, highlighted, selected]; g.Stroke (); } } else { if (!fitsInSameLine) { // draw box below line g.MoveTo (new Cairo.PointD (x2 + 0.5, y2 - 1)); g.LineTo (new Cairo.PointD (x2 + 0.5, y2Bottom)); g.LineTo (new Cairo.PointD (right, y2Bottom)); g.LineTo (new Cairo.PointD (right, y2 - 1)); g.ClosePath (); } else { // draw filled arrow box g.MoveTo (new Cairo.PointD (x2 + 0.5, y2)); g.LineTo (new Cairo.PointD (x2 - editor.LineHeight / 2 + 0.5, y2 + editor.LineHeight / 2)); g.LineTo (new Cairo.PointD (x2 + 0.5, y2Bottom)); g.LineTo (new Cairo.PointD (right, y2Bottom)); g.LineTo (new Cairo.PointD (right, y2)); g.ClosePath (); } g.Color = colorMatrix[active, BOTTOM, LIGHT, highlighted, selected]; g.Fill (); // draw light bottom line g.MoveTo (new Cairo.PointD (right, y2Bottom)); g.LineTo (new Cairo.PointD (x2 + 0.5, y2Bottom)); g.Stroke (); // stroke left line if (fitsInSameLine) { g.MoveTo (new Cairo.PointD (x2 + 0.5, y2)); g.LineTo (new Cairo.PointD (x2 - editor.LineHeight / 2 + 0.5, y2 + editor.LineHeight / 2)); g.LineTo (new Cairo.PointD (x2 + 0.5, y2Bottom)); } else { g.MoveTo (new Cairo.PointD (x2 + 0.5, y2 - 1)); g.LineTo (new Cairo.PointD (x2 + 0.5, y2Bottom + 1)); } g.Color = colorMatrix[active, BOTTOM, LINE, highlighted, selected]; g.Stroke (); // stroke top line if (fitsInSameLine) { g.Color = colorMatrix[active, BOTTOM, LINE, highlighted, selected]; g.MoveTo (new Cairo.PointD (right, y2)); g.LineTo (new Cairo.PointD (x2 + 0.5, y2)); g.Stroke (); } } if (editor.Options.ShowRuler) { double divider = Math.Max (editor.TextViewMargin.XOffset, x + editor.TextViewMargin.RulerX); if (divider >= x2) { g.MoveTo (new Cairo.PointD (divider + 0.5, y2)); g.LineTo (new Cairo.PointD (divider + 0.5, y2Bottom)); g.Color = colorMatrix[active, BOTTOM, DARK, highlighted, selected]; g.Stroke (); } } if (errors.Count > 1 && errorCountLayout != null) { double rX = x2 + (ShowIconsInBubble ? errorPixbuf.Width : 0) + border + LayoutWidth; double rY = y + editor.LineHeight / 6; double rW = errorCounterWidth - 2; double rH = editor.LineHeight * 3 / 4; BookmarkMarker.DrawRoundRectangle (g, rX, rY, 8, rW, rH); g.Color = oldIsOver ? new Cairo.Color (0.3, 0.3, 0.3) : new Cairo.Color (0.5, 0.5, 0.5); g.Fill (); if (CollapseExtendedErrors) { g.Color = gcLight; g.Save (); g.Translate (x2 + (ShowIconsInBubble ? errorPixbuf.Width : 0) + border + LayoutWidth + 4, y + (editor.LineHeight - eh) / 2 + eh % 2); g.ShowLayout (errorCountLayout); g.Restore (); } else { g.MoveTo (rX + rW / 2 - rW / 4, rY + rH - rH / 4); g.LineTo (rX + rW / 2 + rW / 4, rY + rH - rH / 4); g.LineTo (rX + rW / 2, rY + rH / 4); g.ClosePath (); g.Color = new Cairo.Color (1, 1, 1); g.Fill (); } } for (int i = 0; i < layouts.Count; i++) { LayoutDescriptor layout = layouts[i]; x2 = right - layout.Width - border - errorPixbuf.Width; if (i == 0) x2 -= errorCounterWidth; x2 = System.Math.Max (x2, fitsInSameLine ? editor.TextViewMargin.XOffset + editor.LineHeight / 2 : editor.TextViewMargin.XOffset); if (i > 0) { editor.TextViewMargin.DrawRectangleWithRuler (g, x, new Cairo.Rectangle (x, y, right, editor.LineHeight), isEolSelected ? editor.ColorStyle.Selection.CairoBackgroundColor : editor.ColorStyle.Default.CairoBackgroundColor, true); g.MoveTo (new Cairo.PointD (x2 + 0.5, y)); g.LineTo (new Cairo.PointD (x2 + 0.5, y + editor.LineHeight)); g.LineTo (new Cairo.PointD (right, y + editor.LineHeight)); g.LineTo (new Cairo.PointD (right, y)); g.ClosePath (); if (CollapseExtendedErrors) { Cairo.Gradient pat = new Cairo.LinearGradient (x2, y, x2, y + editor.LineHeight); pat.AddColorStop (0, colorMatrix[active, TOP, LIGHT, highlighted, selected]); pat.AddColorStop (1, colorMatrix[active, BOTTOM, LIGHT, highlighted, selected]); g.Pattern = pat; } else { g.Color = colorMatrix[active, TOP, LIGHT, highlighted, selected]; } g.Fill (); if (editor.Options.ShowRuler) { double divider = Math.Max (editor.TextViewMargin.XOffset, x + editor.TextViewMargin.RulerX); if (divider >= x2) { g.MoveTo (new Cairo.PointD (divider + 0.5, y)); g.LineTo (new Cairo.PointD (divider + 0.5, y + editor.LineHeight)); g.Color = colorMatrix[active, BOTTOM, DARK, highlighted, selected]; g.Stroke (); } } } int lw, lh; layout.Layout.GetPixelSize (out lw, out lh); g.Color = (HslColor)(selected == 0 ? gc : gcSelected); g.Save (); g.Translate (x2 + errorPixbuf.Width + border, y + (editor.LineHeight - layout.Height) / 2 + layout.Height % 2); g.ShowLayout (layout.Layout); g.Restore (); y += editor.LineHeight; if (!UseVirtualLines) break; } return true; }
public void Draw (TextEditor editor, Cairo.Context g, int lineNr, Cairo.Rectangle lineArea) { EnsureLayoutCreated (editor); int lineNumber = editor.Document.OffsetToLineNumber (lineSegment.Offset); int errorNumber = lineNr - lineNumber; if (!IsCurrentErrorTextFitting ()) errorNumber--; double x = editor.TextViewMargin.XOffset; double y = lineArea.Y; double right = editor.Allocation.Width; int errorCounterWidth = GetErrorCountBounds ().Item1; // int eh = GetErrorCountBounds ().Item2; double x2 = System.Math.Max (right - LayoutWidth - border - (ShowIconsInBubble ? cache.errorPixbuf.Width : 0) - errorCounterWidth, fitsInSameLine ? editor.TextViewMargin.XOffset + editor.LineHeight / 2 : editor.TextViewMargin.XOffset); if (errors.Count == 1) x2 = editor.TextViewMargin.XOffset; // bool isEolSelected = editor.IsSomethingSelected && editor.SelectionMode != SelectionMode.Block ? editor.SelectionRange.Contains (lineSegment.Offset + lineSegment.EditableLength) : false; int active = editor.Document.GetTextAt (lineSegment) == initialText ? 0 : 1; bool isCaretInLine = lineSegment.Offset <= editor.Caret.Offset && editor.Caret.Offset <= lineSegment.EndOffsetIncludingDelimiter; bool highlighted = active == 0 && isCaretInLine; bool selected = false; var layout = layouts [errorNumber]; x2 = right - LayoutWidth - border - (ShowIconsInBubble ? cache.errorPixbuf.Width : 0); x2 -= errorCounterWidth; x2 = System.Math.Max (x2, fitsInSameLine ? editor.TextViewMargin.XOffset + editor.LineHeight / 2 : editor.TextViewMargin.XOffset); g.MoveTo (new Cairo.PointD (x2 + 0.5, y)); g.LineTo (new Cairo.PointD (x2 + 0.5, y + editor.LineHeight)); g.LineTo (new Cairo.PointD (right, y + editor.LineHeight)); g.LineTo (new Cairo.PointD (right, y)); g.ClosePath (); g.Color = TagColor.Color;// GetLineColorTop (highlighted, selected); g.Fill (); g.Color = TagColor.BorderColor; //GetLineColorBottom (highlighted, selected); g.MoveTo (new Cairo.PointD (x2 + 0.5, y)); g.LineTo (new Cairo.PointD (x2 + 0.5, y + editor.LineHeight)); if (errorNumber == errors.Count - 1) g.LineTo (new Cairo.PointD (lineArea.X + lineArea.Width, y + editor.LineHeight)); g.Stroke (); if (editor.Options.ShowRuler) { double divider = Math.Max (editor.TextViewMargin.XOffset, x + editor.TextViewMargin.RulerX); if (divider >= x2) { g.MoveTo (new Cairo.PointD (divider + 0.5, y)); g.LineTo (new Cairo.PointD (divider + 0.5, y + editor.LineHeight)); g.Color = TagColor.BorderColor; g.Stroke (); } } g.Save (); g.Translate (x2 + (ShowIconsInBubble ? cache.errorPixbuf.Width : 0) + border, y + (editor.LineHeight - layout.Height) / 2 + layout.Height % 2); g.Color = TextColor.Color; g.ShowLayout (layout.Layout); g.Restore (); if (ShowIconsInBubble) { var pixbuf = errors [errorNumber].IsError ? cache.errorPixbuf: cache.warningPixbuf; Gdk.CairoHelper.SetSourcePixbuf (g, pixbuf, x2, y + (editor.LineHeight - cache.errorPixbuf.Height) / 2); g.Paint (); } }
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 (); }
internal protected override void Draw (Cairo.Context cr, Cairo.Rectangle area, DocumentLine lineSegment, int line, double x, double y, double lineHeight) { var gutterMarker = lineSegment != null ? (MarginMarker)lineSegment.Markers.FirstOrDefault (marker => marker is MarginMarker && ((MarginMarker)marker).CanDraw (this)) : null; if (gutterMarker != null && gutterMarker.CanDrawBackground (this)) { bool hasDrawn = gutterMarker.DrawBackground (editor, cr, new MarginDrawMetrics (this, area, lineSegment, line, x, y, lineHeight)); if (!hasDrawn) DrawGutterBackground (cr, line, x, y, lineHeight); } else { DrawGutterBackground (cr, line, x, y, lineHeight); } if (gutterMarker != null && gutterMarker.CanDrawForeground (this)) { gutterMarker.DrawForeground (editor, cr, new MarginDrawMetrics (this, area, lineSegment, line, x, y, lineHeight)); return; } if (line <= editor.Document.LineCount) { // Due to a mac? gtk bug I need to re-create the layout here // otherwise I get pango exceptions. using (var layout = editor.LayoutCache.RequestLayout ()) { layout.FontDescription = gutterFont; layout.Width = (int)Width; layout.Alignment = Pango.Alignment.Right; layout.SetText (line.ToString ()); cr.Save (); cr.Translate (x + (int)Width + (editor.Options.ShowFoldMargin ? 0 : -2), y); cr.SetSourceColor (lineNumberGC); cr.ShowLayout (layout); cr.Restore (); } } }
public bool DrawBackground (TextEditor editor, Cairo.Context g, TextViewMargin.LayoutWrapper layout2, int selectionStart, int selectionEnd, int startOffset, int endOffset, double startYPos, double startXPos, double endXPos, ref bool drawBg) { if (!IsVisible) return true; EnsureLayoutCreated (editor); double x = editor.TextViewMargin.XOffset; double y = startYPos; int right = editor.Allocation.Width; bool isCaretInLine = startOffset <= editor.Caret.Offset && editor.Caret.Offset <= endOffset; var lineTextPx = editor.TextViewMargin.XOffset + editor.TextViewMargin.TextStartPosition + layout2.PangoWidth / Pango.Scale.PangoScale; int errorCounterWidth = GetErrorCountBounds (layout2).Item1; // int eh = GetErrorCountBounds ().Item2; double x2 = System.Math.Max (right - LayoutWidth - border - (ShowIconsInBubble ? cache.errorPixbuf.Width : 0) - errorCounterWidth, fitsInSameLine ? editor.TextViewMargin.XOffset + editor.LineHeight / 2 : editor.TextViewMargin.XOffset); bool isEolSelected = editor.IsSomethingSelected && editor.SelectionMode != SelectionMode.Block ? editor.SelectionRange.Contains (lineSegment.Offset + lineSegment.Length) : false; int active = editor.Document.GetTextAt (lineSegment) == initialText ? 0 : 1; bool highlighted = active == 0 && isCaretInLine; bool selected = false; double topSize = Math.Floor (editor.LineHeight / 2); double bottomSize = editor.LineHeight / 2 + editor.LineHeight % 2; if (!fitsInSameLine) { if (isEolSelected) { x -= (int)editor.HAdjustment.Value; editor.TextViewMargin.DrawRectangleWithRuler (g, x, new Cairo.Rectangle (x, y + editor.LineHeight, editor.TextViewMargin.TextStartPosition, editor.LineHeight), editor.ColorStyle.PlainText.Background, true); editor.TextViewMargin.DrawRectangleWithRuler (g, x + editor.TextViewMargin.TextStartPosition, new Cairo.Rectangle (x + editor.TextViewMargin.TextStartPosition, y + editor.LineHeight, editor.Allocation.Width + (int)editor.HAdjustment.Value, editor.LineHeight), editor.ColorStyle.SelectedText.Background, true); x += (int)editor.HAdjustment.Value; } else { editor.TextViewMargin.DrawRectangleWithRuler (g, x, new Cairo.Rectangle (x, y + editor.LineHeight, x2, editor.LineHeight), editor.ColorStyle.PlainText.Background, true); } } DrawRectangle (g, x, y, right, topSize); g.Color = GetLineColorTop (highlighted, selected); g.Fill (); DrawRectangle (g, x, y + topSize, right, bottomSize); g.Color = GetLineColorBottom (highlighted, selected); g.Fill (); g.MoveTo (new Cairo.PointD (x, y + 0.5)); g.LineTo (new Cairo.PointD (x + right, y + 0.5)); g.Color = GetLineColorBorder (highlighted, selected); g.Stroke (); g.MoveTo (new Cairo.PointD (x, y + editor.LineHeight - 0.5)); g.LineTo (new Cairo.PointD ((fitsInSameLine ? x + right : x2 + 1), y + editor.LineHeight - 0.5)); g.Color = GetLineColorBorder (highlighted, selected); g.Stroke (); /* if (editor.Options.ShowRuler) { double divider = Math.Max (editor.TextViewMargin.XOffset, x + editor.TextViewMargin.RulerX); g.MoveTo (new Cairo.PointD (divider + 0.5, y)); g.LineTo (new Cairo.PointD (divider + 0.5, y + editor.LineHeight)); g.Color = GetLineColorBorder (highlighted, selected); g.Stroke (); }*/ // draw background if (layout2.StartSet || selectionStart == endOffset) { double startX; double endX; if (selectionStart != endOffset) { var start = layout2.Layout.IndexToPos ((int)layout2.SelectionStartIndex); startX = (int)(start.X / Pango.Scale.PangoScale); var end = layout2.Layout.IndexToPos ((int)layout2.SelectionEndIndex); endX = (int)(end.X / Pango.Scale.PangoScale); } else { startX = x2; endX = startX; } if (editor.MainSelection.SelectionMode == SelectionMode.Block && startX == endX) endX = startX + 2; startX += startXPos; endX += startXPos; startX = Math.Max (editor.TextViewMargin.XOffset, startX); // clip region to textviewmargin start if (isEolSelected) endX = editor.Allocation.Width + (int)editor.HAdjustment.Value; if (startX < endX) { DrawRectangle (g, startX, y, endX - startX, topSize); g.Color = GetLineColorTop (highlighted, true); g.Fill (); DrawRectangle (g, startX, y + topSize, endX - startX, bottomSize); g.Color = GetLineColorBottom (highlighted, true); g.Fill (); g.MoveTo (new Cairo.PointD (startX, y + 0.5)); g.LineTo (new Cairo.PointD (endX, y + 0.5)); g.Color = GetLineColorBorder (highlighted, true); g.Stroke (); if (startX < x2) { g.MoveTo (new Cairo.PointD (startX, y + editor.LineHeight - 0.5)); g.LineTo (new Cairo.PointD (System.Math.Min (endX, x2 + 1), y + editor.LineHeight - 0.5)); g.Color = GetLineColorBorder (highlighted, true); g.Stroke (); if (x2 + 1 < endX) { g.MoveTo (new Cairo.PointD (x2 + 1, y + editor.LineHeight - 0.5)); g.LineTo (new Cairo.PointD (endX, y + editor.LineHeight - 0.5)); g.Color = GetLineColorBorder (highlighted, true); g.Stroke (); } } if (editor.Options.ShowRuler) { double divider = Math.Max (editor.TextViewMargin.XOffset, x + editor.TextViewMargin.RulerX); g.MoveTo (new Cairo.PointD (divider + 0.5, y)); g.LineTo (new Cairo.PointD (divider + 0.5, y + editor.LineHeight)); g.Color = GetLineColorBorder (highlighted, true); g.Stroke (); } } } if (!fitsInSameLine) y += editor.LineHeight; double y2 = y + 0.5; double y2Bottom = y2 + editor.LineHeight - 1; selected = isEolSelected && (CollapseExtendedErrors); if (x2 < lineTextPx) x2 = lineTextPx; // draw message text background if (CollapseExtendedErrors) { if (!fitsInSameLine) { // draw box below line g.MoveTo (new Cairo.PointD (x2 + 0.5, y2 - 1)); g.LineTo (new Cairo.PointD (x2 + 0.5, y2Bottom)); g.LineTo (new Cairo.PointD (right, y2Bottom)); g.LineTo (new Cairo.PointD (right, y2 - 1)); g.ClosePath (); g.Color = TagColor.Color; g.Fill (); g.MoveTo (new Cairo.PointD (x2 + 0.5, y2 - 1)); g.LineTo (new Cairo.PointD (x2 + 0.5, y2Bottom)); g.LineTo (new Cairo.PointD (right, y2Bottom)); g.Color = TagColor.BorderColor; g.Stroke (); } else { // draw 'arrow marker' in the same line // if (errors.Count > 1) { g.MoveTo (new Cairo.PointD (x2 + 0.5, y2)); double mid = y2 + topSize; g.LineTo (new Cairo.PointD (x2 - editor.LineHeight / 2 + 0.5, mid)); g.LineTo (new Cairo.PointD (right, mid)); g.LineTo (new Cairo.PointD (right, y2)); g.ClosePath (); g.Color = TagColor.Color; g.Fill (); g.MoveTo (new Cairo.PointD (x2 + 0.5, y2Bottom)); g.LineTo (new Cairo.PointD (x2 - editor.LineHeight / 2 + 0.5, mid)); g.LineTo (new Cairo.PointD (right, mid)); g.LineTo (new Cairo.PointD (right, y2Bottom)); g.ClosePath (); g.Color = TagColor.SecondColor; g.Fill (); // } // draw border g.MoveTo (new Cairo.PointD (x2 + 0.5, y2)); g.LineTo (new Cairo.PointD (x2 - editor.LineHeight / 2 + 0.5, y2 + editor.LineHeight / 2)); g.LineTo (new Cairo.PointD (x2 + 0.5, y2Bottom)); g.LineTo (new Cairo.PointD (right, y2Bottom)); g.LineTo (new Cairo.PointD (right, y2)); g.ClosePath (); g.Color = TagColor.BorderColor; g.Stroke (); } } else { if (!fitsInSameLine) { // draw box below line g.MoveTo (new Cairo.PointD (x2 + 0.5, y2 - 1)); g.LineTo (new Cairo.PointD (x2 + 0.5, y2Bottom)); g.LineTo (new Cairo.PointD (right, y2Bottom)); g.LineTo (new Cairo.PointD (right, y2 - 1)); g.ClosePath (); } else { // draw filled arrow box if (!(errors.Count == 1 && !CollapseExtendedErrors)) { g.MoveTo (new Cairo.PointD (x2 + 0.5, y2)); g.LineTo (new Cairo.PointD (x2 - editor.LineHeight / 2 + 0.5, y2 + editor.LineHeight / 2)); g.LineTo (new Cairo.PointD (x2 + 0.5, y2Bottom)); g.LineTo (new Cairo.PointD (right, y2Bottom)); g.LineTo (new Cairo.PointD (right, y2)); g.ClosePath (); } } g.Color = TagColor.Color; g.Fill (); // draw light bottom line g.MoveTo (new Cairo.PointD (right, y2Bottom)); g.LineTo (new Cairo.PointD (x2 + 0.5, y2Bottom)); g.Stroke (); // stroke left line if (fitsInSameLine) { g.MoveTo (new Cairo.PointD (x2 + 0.5, y2)); g.LineTo (new Cairo.PointD (x2 - editor.LineHeight / 2 + 0.5, y2 + editor.LineHeight / 2)); g.LineTo (new Cairo.PointD (x2 + 0.5, y2Bottom)); } else { g.MoveTo (new Cairo.PointD (x2 + 0.5, y2 - 1)); g.LineTo (new Cairo.PointD (x2 + 0.5, y2Bottom + 1)); } g.Color = TagColor.BorderColor; g.Stroke (); // stroke top line if (fitsInSameLine) { g.Color = TagColor.BorderColor; g.MoveTo (new Cairo.PointD (right, y2)); g.LineTo (new Cairo.PointD (x2 + 0.5, y2)); g.Stroke (); } } if (editor.Options.ShowRuler) { double divider = Math.Max (editor.TextViewMargin.XOffset, x + editor.TextViewMargin.RulerX); if (divider >= x2) { g.MoveTo (new Cairo.PointD (divider + 0.5, y2)); g.LineTo (new Cairo.PointD (divider + 0.5, y2Bottom)); g.Color = GetLineColorBorder (highlighted, selected); g.Stroke (); } } for (int i = 0; i < layouts.Count; i++) { if (!IsCurrentErrorTextFitting (layout2) && !CollapseExtendedErrors) break; var layout = layouts [i]; x2 = right - layout.Width - border - (ShowIconsInBubble ? cache.errorPixbuf.Width : 0); if (i == 0) { x2 -= errorCounterWidth; if (x2 < lineTextPx) { // if (CollapseExtendedErrors) { x2 = lineTextPx; // } } } // x2 = System.Math.Max (x2, fitsInSameLine ? editor.TextViewMargin.XOffset + editor.LineHeight / 2 : editor.TextViewMargin.XOffset); if (i > 0) { editor.TextViewMargin.DrawRectangleWithRuler (g, x, new Cairo.Rectangle (x, y, right, editor.LineHeight), isEolSelected ? editor.ColorStyle.SelectedText.Background : editor.ColorStyle.PlainText.Background, true); g.MoveTo (new Cairo.PointD (x2 + 0.5, y)); g.LineTo (new Cairo.PointD (x2 + 0.5, y + editor.LineHeight)); g.LineTo (new Cairo.PointD (right, y + editor.LineHeight)); g.LineTo (new Cairo.PointD (right, y)); g.ClosePath (); if (CollapseExtendedErrors) { using (var pat = new Cairo.LinearGradient (x2, y, x2, y + editor.LineHeight)) { pat.AddColorStop (0, GetLineColorTop (highlighted, selected)); pat.AddColorStop (1, GetLineColorBottom (highlighted, selected)); g.Pattern = pat; } } else { g.Color = GetLineColorTop (highlighted, selected); } g.Fill (); if (editor.Options.ShowRuler) { double divider = Math.Max (editor.TextViewMargin.XOffset, x + editor.TextViewMargin.RulerX); if (divider >= x2) { g.MoveTo (new Cairo.PointD (divider + 0.5, y)); g.LineTo (new Cairo.PointD (divider + 0.5, y + editor.LineHeight)); g.Color = TagColor.BorderColor; g.Stroke (); } } } g.Color = TextColor.Color; g.Save (); g.Translate (x2 + (ShowIconsInBubble ? cache.errorPixbuf.Width : 0) + border, y + (editor.LineHeight - layout.Height) / 2 + layout.Height % 2); g.ShowLayout (layout.Layout); g.Restore (); y += editor.LineHeight; if (!UseVirtualLines) break; } DrawErrorMarkers (editor, g, layout2, startXPos, startYPos); return true; }
void DrawButtonTabs (Cairo.Context cr, Cairo.Rectangle rectangle) { if (IsSeparator) { cr.NewPath (); double x = Math.Ceiling (rectangle.X + rectangle.Width / 2) + 0.5; cr.MoveTo (x, rectangle.Y + 0.5 + 2); cr.RelLineTo (0, rectangle.Height - 1 - 4); cr.ClosePath (); cr.Color = (HslColor)parent.Style.Dark (StateType.Normal); cr.LineWidth = 1; cr.Stroke (); return; } int topPadding = 2; if (Active || HoverPosition.X >= 0) { cr.Rectangle (rectangle.X + 1, rectangle.Y + 1 + topPadding, rectangle.Width - 1, rectangle.Height - topPadding); if (Active) { cr.Color = (HslColor)parent.Style.Background (StateType.Prelight); } else if (HoverPosition.X >= 0) { double rx = rectangle.X + HoverPosition.X; double ry = rectangle.Y + HoverPosition.Y; Cairo.RadialGradient gradient = new Cairo.RadialGradient (rx, ry, rectangle.Height * 1.5, rx, ry, 2); var color = (HslColor)parent.Style.Dark (StateType.Normal); color.L *= 1.1; gradient.AddColorStop (0, color); color.L *= 1.1; gradient.AddColorStop (1, color); cr.Pattern = gradient; } cr.Fill (); if (Active) { cr.Rectangle (rectangle.X + 0.5, rectangle.Y + 0.5 + topPadding, rectangle.Width - 1, rectangle.Height - topPadding); cr.Color = (HslColor)parent.Style.Dark (StateType.Normal); cr.LineWidth = 1; cr.Stroke (); } } cr.Save (); cr.Translate (rectangle.X + (rectangle.Width - w) / 2, (rectangle.Height - h) / 2 + topPadding); cr.Color = (HslColor)parent.Style.Text (StateType.Normal); cr.ShowLayout (layout); cr.Restore (); }
void DrawCurveTabs (Cairo.Context cr, Cairo.Rectangle rectangle) { if (IsSeparator) return; cr.MoveTo (rectangle.X, rectangle.Y); double bottom = rectangle.Y + rectangle.Height - 1; cr.CurveTo ( rectangle.X + SpacerWidth / 2, rectangle.Y, rectangle.X + SpacerWidth / 2, bottom, rectangle.X + SpacerWidth, bottom); cr.LineTo (rectangle.X + rectangle.Width - SpacerWidth, bottom); cr.CurveTo ( rectangle.X + rectangle.Width - SpacerWidth / 2, bottom, rectangle.X + rectangle.Width - SpacerWidth / 2, rectangle.Y, rectangle.X + rectangle.Width, rectangle.Y); cr.Color = (HslColor)parent.Style.Dark (StateType.Normal); cr.StrokePreserve (); cr.ClosePath (); if (Active) { cr.Color = (HslColor)parent.Style.Background (StateType.Prelight); } else if (HoverPosition.X >= 0) { double rx = rectangle.X + HoverPosition.X; double ry = rectangle.Y + HoverPosition.Y; Cairo.RadialGradient gradient = new Cairo.RadialGradient (rx, ry, rectangle.Height * 1.5, rx, ry, 2); var color = (HslColor)parent.Style.Mid (StateType.Normal); color.L *= 1.05; gradient.AddColorStop (0, color); color.L *= 1.07; gradient.AddColorStop (1, color); cr.Pattern = gradient; } else { cr.Color = (HslColor)parent.Style.Mid (StateType.Normal); } cr.Fill (); cr.Save (); cr.Translate (rectangle.X + (rectangle.Width - w) / 2, (rectangle.Height - h) / 2); cr.Color = (HslColor)parent.Style.Text (StateType.Normal); cr.ShowLayout (layout); cr.Restore (); }
internal protected override void Draw (Cairo.Context cr, Cairo.Rectangle area, LineSegment lineSegment, int line, double x, double y, double lineHeight) { cr.Rectangle (x, y, Width, lineHeight); cr.Color = lineNumberBgGC; cr.Fill (); if (line <= editor.Document.LineCount) { layout.SetText (line.ToString ()); cr.Save (); cr.Translate (x + (int)Width, y); cr.Color = editor.Caret.Line == line ? lineNumberHighlightGC : lineNumberGC; cr.ShowLayout (layout); cr.Restore (); } }
void DrawEolMarker (Cairo.Context cr, LineSegment line, bool selected, double x, double y) { Pango.Layout layout; switch (line.DelimiterLength) { case 0: // an emty line end should only happen at eof layout = eofEolLayout; break; case 1: if (Document.GetCharAt (line.Offset + line.Length) == '\n') { layout = unixEolLayout; } else { layout = macEolLayout; } break; case 2: layout = windowEolLayout; break; default: throw new InvalidOperationException (); // other line endings are not known. } cr.Save (); cr.Translate (x, y); cr.Color = selected ? SelectionColor.CairoColor : ColorStyle.EolWhitespaceMarker; cr.ShowLayout (layout); cr.Restore (); }
void RenderLineNumberIcon (Widget widget, Cairo.Context cr, Gdk.Rectangle cell_area, int markupHeight, int yOffset) { if (Frame == null) return; cr.Save (); #if CENTER_ROUNDED_RECTANGLE cr.Translate (cell_area.X + Padding, (cell_area.Y + (cell_area.Height - RoundedRectangleHeight) / 2.0)); #else cr.Translate (cell_area.X + Padding, cell_area.Y + Padding + yOffset); #endif cr.Antialias = Cairo.Antialias.Subpixel; cr.RoundedRectangle (0.0, 0.0, RoundedRectangleWidth, RoundedRectangleHeight, RoundedRectangleRadius); cr.Clip (); if (IsUserCode) cr.SetSourceRGBA (0.90, 0.60, 0.87, 1.0); // 230, 152, 223 else cr.SetSourceRGBA (0.77, 0.77, 0.77, 1.0); // 197, 197, 197 cr.RoundedRectangle (0.0, 0.0, RoundedRectangleWidth, RoundedRectangleHeight, RoundedRectangleRadius); cr.Fill (); cr.SetSourceRGBA (0.0, 0.0, 0.0, 0.11); cr.RoundedRectangle (0.0, 0.0, RoundedRectangleWidth, RoundedRectangleHeight, RoundedRectangleRadius); cr.LineWidth = 2; cr.Stroke (); var lineNumber = !string.IsNullOrEmpty (Frame.File) ? Frame.Line : -1; using (var layout = PangoUtil.CreateLayout (widget, lineNumber != -1 ? lineNumber.ToString () : "???")) { layout.Alignment = Pango.Alignment.Left; layout.FontDescription = LineNumberFont; int width, height; layout.GetPixelSize (out width, out height); double y_offset = (RoundedRectangleHeight - height) / 2.0; double x_offset = (RoundedRectangleWidth - width) / 2.0; // render the text shadow cr.Save (); cr.SetSourceRGBA (0.0, 0.0, 0.0, 0.34); cr.Translate (x_offset, y_offset + 1); cr.ShowLayout (layout); cr.Restore (); cr.SetSourceRGBA (1.0, 1.0, 1.0, 1.0); cr.Translate (x_offset, y_offset); cr.ShowLayout (layout); } cr.Restore (); }
void DrawInvalidLineMarker (Cairo.Context cr, double x, double y) { cr.Save (); cr.Translate (x, y); cr.Color = ColorStyle.InvalidLineMarker; cr.ShowLayout (invalidLineLayout); cr.Restore (); }
public void Render (Cairo.Context cr, double _x, double _y, int max_height) { double x = _x; double y = _y; int w = Width; int h = max_height; int inner_padding = 0; if (Outlined) { x -= outlinePadding; y -= outlinePadding; w += outlinePadding * 2; h += outlinePadding * 2; cr.MoveTo (x, y); cr.LineWidth = 1; cr.SetSourceColor (Styles.ModeHelpWindowTokenOutlineColor.ToCairoColor()); if (Symbol == SymbolTokenType.None) inner_padding = textInnerPadding; // -0.5f to fix the @1x stroke problem: // 1px stroke is rendered on the center of the shape edge, resulting in // two semitransparent pixels. Even worse the rounded rectangle renders // transparency artifacts on edge overlaps. See http://vncr.in/atks FoldingScreenbackgroundRenderer.DrawRoundRectangle (cr, true, true, x - inner_padding - 0.5f, y - 0.5f, 8, w + inner_padding * 2 + 1, h + 1); cr.Stroke (); if (Symbol == SymbolTokenType.Down) { RenderTriangleDown (cr, x + 4, y + 3, 8, 6); } else if (Symbol == SymbolTokenType.Up) { RenderTriangleUp (cr, x + 4, y + 3, 8, 6); } else { cr.MoveTo (x + outlinePadding, y + (max_height - Height - 0.5)); cr.ShowLayout (layout); } } else { cr.MoveTo (x, y); cr.SetSourceColor (Styles.ModeHelpWindowTokenTextColor.ToCairoColor()); cr.ShowLayout (layout); } }
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 (); }
internal protected override void Draw (Cairo.Context cr, Cairo.Rectangle area, LineSegment lineSegment, int line, double x, double y, double lineHeight) { cr.Rectangle (x, y, Width, lineHeight); cr.Color = lineNumberBgGC; cr.Fill (); if (line <= editor.Document.LineCount) { // Due to a mac? gtk bug I need to re-create the layout here // otherwise I get pango exceptions. using (var layout = PangoUtil.CreateLayout (editor)) { layout.FontDescription = editor.Options.Font; layout.Width = (int)Width; layout.Alignment = Pango.Alignment.Right; layout.SetText (line.ToString ()); cr.Save (); cr.Translate (x + (int)Width + (editor.Options.ShowFoldMargin ? 0 : -2), y); cr.Color = editor.Caret.Line == line ? lineNumberHighlightGC : lineNumberGC; cr.ShowLayout (layout); cr.Restore (); } } }
public void Draw (TextEditor editor, Cairo.Context g, int lineNr, Cairo.Rectangle lineArea) { EnsureLayoutCreated (editor); int lineNumber = editor.Document.OffsetToLineNumber (lineSegment.Offset); int errorNumber = lineNr - lineNumber; double x = editor.TextViewMargin.XOffset; double y = lineArea.Y; double right = editor.Allocation.Width; int errorCounterWidth = 0; int ew = 0, eh = 0; if (errors.Count > 1 && errorCountLayout != null) { errorCountLayout.GetPixelSize (out ew, out eh); errorCounterWidth = ew + 10; } double x2 = System.Math.Max (right - LayoutWidth - border - (ShowIconsInBubble ? errorPixbuf.Width : 0) - errorCounterWidth, fitsInSameLine ? editor.TextViewMargin.XOffset + editor.LineHeight / 2 : editor.TextViewMargin.XOffset); // bool isEolSelected = editor.IsSomethingSelected && editor.SelectionMode != SelectionMode.Block ? editor.SelectionRange.Contains (lineSegment.Offset + lineSegment.EditableLength) : false; int active = editor.Document.GetTextAt (lineSegment) == initialText ? 0 : 1; bool isCaretInLine = lineSegment.Offset <= editor.Caret.Offset && editor.Caret.Offset <= lineSegment.EndOffset; int highlighted = active == 0 && isCaretInLine ? 1 : 0; int selected = 0; LayoutDescriptor layout = layouts[errorNumber]; x2 = right - LayoutWidth - border - (ShowIconsInBubble ? errorPixbuf.Width : 0); x2 -= errorCounterWidth; x2 = System.Math.Max (x2, fitsInSameLine ? editor.TextViewMargin.XOffset + editor.LineHeight / 2 : editor.TextViewMargin.XOffset); g.MoveTo (new Cairo.PointD (x2 + 0.5, y)); g.LineTo (new Cairo.PointD (x2 + 0.5, y + editor.LineHeight)); g.LineTo (new Cairo.PointD (right, y + editor.LineHeight)); g.LineTo (new Cairo.PointD (right, y)); g.ClosePath (); g.Color = colorMatrix[active, BOTTOM, LIGHT, highlighted, selected]; g.Fill (); g.Color = colorMatrix[active, BOTTOM, LINE, highlighted, selected]; g.MoveTo (new Cairo.PointD (x2 + 0.5, y)); g.LineTo (new Cairo.PointD (x2 + 0.5, y + editor.LineHeight)); if (errorNumber == errors.Count - 1) g.LineTo (new Cairo.PointD (lineArea.X + lineArea.Width, y + editor.LineHeight)); g.Stroke (); if (editor.Options.ShowRuler) { double divider = Math.Max (editor.TextViewMargin.XOffset, x + editor.TextViewMargin.RulerX); if (divider >= x2) { g.MoveTo (new Cairo.PointD (divider + 0.5, y)); g.LineTo (new Cairo.PointD (divider + 0.5, y + editor.LineHeight)); g.Color = colorMatrix[active, BOTTOM, DARK, highlighted, selected]; g.Stroke (); } } g.Save (); g.Translate (x2 + (ShowIconsInBubble ? errorPixbuf.Width : 0) + border, y + (editor.LineHeight - layout.Height) / 2 + layout.Height % 2); g.Color = selected == 0 ? gc : gcSelected; g.ShowLayout (layout.Layout); g.Restore (); // if (ShowIconsInBubble) // win.DrawPixbuf (editor.Style.BaseGC (Gtk.StateType.Normal), errors[errorNumber].IsError ? errorPixbuf : warningPixbuf, 0, 0, x2, y + (editor.LineHeight - errorPixbuf.Height) / 2, errorPixbuf.Width, errorPixbuf.Height, Gdk.RgbDither.None, 0, 0); }
internal protected override void Draw (Cairo.Context cr, Cairo.Rectangle area, DocumentLine lineSegment, int line, double x, double y, double lineHeight) { var gutterMarker = lineSegment != null ? (IGutterMarker)lineSegment.Markers.FirstOrDefault (marker => marker is IGutterMarker) : null; if (gutterMarker != null) { gutterMarker.DrawLineNumber (editor, Width, cr, area, lineSegment, line, x, y, lineHeight); return; } if (editor.Caret.Line == line) { editor.TextViewMargin.DrawCaretLineMarker (cr, x, y, Width, lineHeight); } else { cr.Rectangle (x, y, Width, lineHeight); cr.Color = lineNumberBgGC; cr.Fill (); } if (line <= editor.Document.LineCount) { // Due to a mac? gtk bug I need to re-create the layout here // otherwise I get pango exceptions. using (var layout = PangoUtil.CreateLayout (editor)) { layout.FontDescription = gutterFont; layout.Width = (int)Width; layout.Alignment = Pango.Alignment.Right; layout.SetText (line.ToString ()); cr.Save (); cr.Translate (x + (int)Width + (editor.Options.ShowFoldMargin ? 0 : -2), y + (lineHeight - fontHeight) / 2); cr.Color = lineNumberGC; cr.ShowLayout (layout); cr.Restore (); } } }
void DrawEolMarker (Cairo.Context cr, DocumentLine line, bool selected, double x, double y) { if (!textEditor.Options.IncludeWhitespaces.HasFlag (IncludeWhitespaces.LineEndings)) return; Pango.Layout layout; Pango.Rectangle rect; var index = GetEolMarkerIndex (line.UnicodeNewline); layout = eolMarkerLayout [index]; rect = eolMarkerLayoutRect [index]; cr.Save (); cr.Translate (x, y + System.Math.Max (0, LineHeight - rect.Height - 1)); var col = ColorStyle.PlainText.Foreground; if (selected && !SelectionColor.TransparentForeground) { col = SelectionColor.Foreground; } else { if (line != null && line.NextLine != null && line.NextLine.StartSpan != null && line.NextLine.StartSpan.Count > 0) { var span = line.NextLine.StartSpan.Peek (); var chunkStyle = ColorStyle.GetChunkStyle (span.Color); if (chunkStyle != null) col = ColorStyle.GetForeground (chunkStyle); } } cr.SetSourceRGBA (col.R, col.G, col.B, whitespaceMarkerAlpha * 1.4); // needs to more opaque due to font rendering cr.ShowLayout (layout); cr.Restore (); }
void DrawMessageExtendIcon (Mono.TextEditor.TextEditor editor, Cairo.Context g, double y, int errorCounterWidth, int eh) { EnsureLayoutCreated (editor); double rW = errorCounterWidth - 2; double rH = editor.LineHeight * 3 / 4; double rX = editor.Allocation.Width - rW - 2; double rY = y + (editor.LineHeight - rH) / 2; BookmarkMarker.DrawRoundRectangle (g, rX, rY, 8, rW, rH); g.Color = oldIsOver ? new Cairo.Color (0.3, 0.3, 0.3) : new Cairo.Color (0.5, 0.5, 0.5); g.Fill (); if (CollapseExtendedErrors) { if (errorCountLayout != null) { g.Color = cache.gcLight; g.Save (); g.Translate (rX + rW / 4, rY + (rH - eh) / 2); g.ShowLayout (errorCountLayout); g.Restore (); } else { g.MoveTo (rX + rW / 2 - rW / 4, rY + rH / 4); g.LineTo (rX + rW / 2 + rW / 4, rY + rH / 4); g.LineTo (rX + rW / 2, rY + rH - rH / 4); g.ClosePath (); g.Color = new Cairo.Color (1, 1, 1); g.Fill (); } } else { g.MoveTo (rX + rW / 2 - rW / 4, rY + rH - rH / 4); g.LineTo (rX + rW / 2 + rW / 4, rY + rH - rH / 4); g.LineTo (rX + rW / 2, rY + rH / 4); g.ClosePath (); g.Color = new Cairo.Color (1, 1, 1); g.Fill (); } }
void DrawEolMarker (Cairo.Context cr, DocumentLine line, bool selected, double x, double y) { if (!textEditor.Options.IncludeWhitespaces.HasFlag (IncludeWhitespaces.LineEndings)) return; Pango.Layout layout; Pango.Rectangle rect; switch (line.DelimiterLength) { case 0: // an emty line end should only happen at eof layout = eofEolLayout; rect = eofEolLayoutRect; break; case 1: var eolIndex = GetEolMarkerIndex (Document.GetCharAt (line.Offset + line.Length)); layout = eolMarkerLayout[eolIndex]; rect = eolMarkerLayoutRect[eolIndex]; break; case 2: layout = eolMarkerLayout[2]; rect = eolMarkerLayoutRect[2]; break; default: throw new InvalidOperationException (); // other line endings are not known. } cr.Save (); cr.Translate (x, y + System.Math.Max (0, LineHeight - rect.Height - 1)); var col = ColorStyle.PlainText.Foreground; if (selected && !SelectionColor.TransparentForeground) { col = SelectionColor.Foreground; } else { if (line != null && line.NextLine != null && line.NextLine.StartSpan != null && line.NextLine.StartSpan.Count > 0) { var span = line.NextLine.StartSpan.Peek (); var chunkStyle = ColorStyle.GetChunkStyle (span.Color); if (chunkStyle != null) col = ColorStyle.GetForeground (chunkStyle); } } cr.Color = new Cairo.Color (col.R, col.G, col.B, whitespaceMarkerAlpha); cr.ShowLayout (layout); cr.Restore (); }
void DrawTabMarker (Cairo.Context cr, bool selected, double x, double y) { cr.Save (); cr.Translate (x, y); cr.ShowLayout (tabMarkerLayout); cr.Restore (); }
protected override void OnDrawContent (Gdk.EventExpose evnt, Cairo.Context g) { g.Rectangle (0, 0, Allocation.Width, Allocation.Height); g.SetSourceColor (marker.TooltipColor.Color); g.Fill (); using (var drawingLayout = new Pango.Layout (this.PangoContext)) { drawingLayout.FontDescription = cache.tooltipFontDescription; double y = verticalTextBorder; var showBulletedList = marker.Errors.Count > 1; foreach (var msg in marker.Errors) { var icon = msg.IsError ? errorPixbuf : warningPixbuf; int w, h; if (!showBulletedList) drawingLayout.Width = maxTextWidth; drawingLayout.SetText (GetFirstLine (msg)); drawingLayout.GetPixelSize (out w, out h); if (showBulletedList) { g.Save (); g.Translate (textBorder, y + verticalTextSpace / 2 + Math.Max (0, (h - icon.Height) / 2)); g.DrawImage (this, icon, 0, 0); g.Restore (); } g.Save (); g.Translate (showBulletedList ? textBorder + iconTextSpacing + icon.Width: textBorder, y + verticalTextSpace / 2); g.SetSourceColor (marker.TagColor.SecondColor); g.ShowLayout (drawingLayout); g.Restore (); y += h + verticalTextSpace; } } }
void DrawLinePart (Cairo.Context cr, LineSegment line, int lineNumber, int logicalRulerColumn, int offset, int length, ref double pangoPosition, ref bool isSelectionDrawn, double y, double maxX) { ISyntaxMode mode = Document.SyntaxMode != null && textEditor.Options.EnableSyntaxHighlighting ? Document.SyntaxMode : new SyntaxMode (Document); int selectionStart; int selectionEnd; if (this.HideSelection) { selectionStart = selectionEnd = -1; } else { GetSelectionOffsets (line, out selectionStart, out selectionEnd); } // ---- new renderer LayoutWrapper layout = CreateLinePartLayout (mode, line, logicalRulerColumn, offset, length, selectionStart, selectionEnd); int lineOffset = line.Offset; double width = layout.PangoWidth / Pango.Scale.PangoScale; double xPos = pangoPosition / Pango.Scale.PangoScale; // if (!(HighlightCaretLine || textEditor.Options.HighlightCaretLine) || Document.GetLine(Caret.Line) != line) { 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 + pangoPosition) / Pango.Scale.PangoScale, y, (x2 - x1) / Pango.Scale.PangoScale + 1, LineHeight), bg.Color, true); } // } bool drawBg = true; bool drawText = true; foreach (TextMarker marker in line.Markers) { IBackgroundMarker bgMarker = marker as IBackgroundMarker; if (bgMarker == null || !marker.IsVisible) continue; isSelectionDrawn |= (marker.Flags & TextMarkerFlags.DrawsSelection) == TextMarkerFlags.DrawsSelection; drawText &= bgMarker.DrawBackground (textEditor, cr, layout, selectionStart, selectionEnd, offset, offset + length, y, xPos, xPos + width, ref drawBg); } if (DecorateLineBg != null) DecorateLineBg (cr, layout, offset, length, xPos, y, selectionStart, selectionEnd); if ((HighlightCaretLine || textEditor.Options.HighlightCaretLine) && Caret.Line == lineNumber) DrawCaretLineMarker (cr, xPos, y, layout.PangoWidth / Pango.Scale.PangoScale); if (!isSelectionDrawn && (layout.StartSet || selectionStart == offset + length)) { double startX; double endX; if (selectionStart != offset + length) { var start = layout.Layout.IndexToPos ((int)layout.SelectionStartIndex); startX = start.X / Pango.Scale.PangoScale; var end = layout.Layout.IndexToPos ((int)layout.SelectionEndIndex); endX = end.X / Pango.Scale.PangoScale; } else { startX = width; endX = startX; } if (textEditor.MainSelection.SelectionMode == SelectionMode.Block && startX == endX) { endX = startX + 2; } DrawRectangleWithRuler (cr, xPos + textEditor.HAdjustment.Value - TextStartPosition, new Cairo.Rectangle (xPos + startX, y, endX - startX, LineHeight), this.SelectionColor.CairoBackgroundColor, 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 = pangoPosition; HandleSelection (lineOffset, logicalRulerColumn, selectionStart, selectionEnd, 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); x1 += (int)x; x2 += (int)x; x1 /= (int)Pango.Scale.PangoScale; x2 /= (int)Pango.Scale.PangoScale; cr.Color = MainSearchResult.IsInvalid || MainSearchResult.Offset != firstSearch.Offset ? ColorStyle.SearchTextBg : ColorStyle.SearchTextMainBg; FoldingScreenbackgroundRenderer.DrawRoundRectangle (cr, true, true, x1, y, System.Math.Min (10, width) * textEditor.Options.Zoom, x2 - x1, 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 (DecorateLineFg != null) DecorateLineFg (cr, layout, offset, length, xPos, y, selectionStart, selectionEnd); if (lineNumber == Caret.Line) { int caretOffset = Caret.Offset; if (offset <= caretOffset && caretOffset <= offset + length) { int index = caretOffset - offset; if (Caret.Column > line.Length + 1) { string virtualSpace = ""; var data = textEditor.GetTextEditorData (); if (data.HasIndentationTracker && line.Length == 0) { virtualSpace = this.textEditor.GetTextEditorData ().GetIndentationString (Caret.Location); } if (Caret.Column > line.Length + 1 + virtualSpace.Length) virtualSpace += new string (' ', Caret.Column - line.Length - 1 - virtualSpace.Length); LayoutWrapper wrapper = new LayoutWrapper (PangoUtil.CreateLayout (textEditor)); wrapper.LineChars = virtualSpace.ToCharArray (); wrapper.Layout.SetText (virtualSpace); wrapper.Layout.Tabs = tabArray; wrapper.Layout.FontDescription = textEditor.Options.Font; int vy, vx; wrapper.Layout.GetSize (out vx, out vy); SetVisibleCaretPosition (((pangoPosition + vx + layout.PangoWidth) / Pango.Scale.PangoScale), y); xPos = (pangoPosition + layout.PangoWidth) / Pango.Scale.PangoScale; if (!isSelectionDrawn && (selectionEnd == lineOffset + line.Length)) { double startX; double endX; startX = xPos; endX = (pangoPosition + vx + layout.PangoWidth) / Pango.Scale.PangoScale; DrawRectangleWithRuler (cr, xPos + textEditor.HAdjustment.Value - TextStartPosition, new Cairo.Rectangle (startX, y, endX - startX, LineHeight), this.SelectionColor.CairoBackgroundColor, true); } if ((HighlightCaretLine || textEditor.Options.HighlightCaretLine) && Caret.Line == lineNumber) DrawCaretLineMarker (cr, pangoPosition / Pango.Scale.PangoScale, y, vx / Pango.Scale.PangoScale); // When drawing virtual space before the selection start paint it as unselected. var virtualSpaceMod = selectionStart < caretOffset ? 0 : virtualSpace.Length; if (DecorateLineBg != null) DecorateLineBg (cr, wrapper, offset, length, xPos, y, selectionStart + virtualSpaceMod, selectionEnd + virtualSpace.Length); if (DecorateLineFg != null) DecorateLineFg (cr, wrapper, offset, length, xPos, y, selectionStart + virtualSpaceMod, selectionEnd + virtualSpace.Length); wrapper.Dispose (); pangoPosition += vx; } else if (index == length && textEditor.preeditString == null) { SetVisibleCaretPosition ((pangoPosition + layout.PangoWidth) / Pango.Scale.PangoScale, 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); if (textEditor.preeditString != null && textEditor.preeditCursorCharIndex > 0) { curIndex = byteIndex = 0; int preeditUtf8ByteIndex = (int)TranslateToUTF8Index (textEditor.preeditString.ToCharArray (), (uint)textEditor.preeditCursorCharIndex, ref curIndex, ref byteIndex); utf8ByteIndex += preeditUtf8ByteIndex; } layout.Layout.GetCursorPos (utf8ByteIndex, out strong_pos, out weak_pos); SetVisibleCaretPosition (xPos + (strong_pos.X / Pango.Scale.PangoScale), y); } } } foreach (TextMarker marker in line.Markers.Where (m => m.IsVisible)) { if (layout.Layout != null) marker.Draw (textEditor, cr, layout.Layout, false, /*selected*/offset, offset + length, y, xPos, xPos + width); } pangoPosition += layout.PangoWidth; if (layout.IsUncached) layout.Dispose (); }
protected override void OnDrawContent (Gdk.EventExpose evnt, Cairo.Context g) { g.Rectangle (0, 0, Allocation.Width, Allocation.Height); g.Color = marker.LineColor.SecondColor; g.Fill (); double y = 8; double x = 4; foreach (var layout in marker.Layouts) { g.Save (); g.Translate (x, y); g.Color = marker.TagColor.SecondColor; g.ShowLayout (layout.Layout); g.Restore (); y += layout.Height; } }
void DrawLine (Cairo.Context g, TextEditor editor, int lineNumber, ref int y) { using (var drawingLayout = new Pango.Layout (this.PangoContext)) { drawingLayout.FontDescription = fontDescription; var line = editor.GetLine (lineNumber); var correctedIndentLength = CorrectIndent (editor, line, indentLength); drawingLayout.SetMarkup (editor.GetPangoMarkup (line.Offset + Math.Min (correctedIndentLength, line.Length), Math.Max (0, line.Length - correctedIndentLength))); g.Save (); g.Translate (textBorder, y); g.ShowLayout (drawingLayout); g.Restore (); y += lineHeight; } }