public override void DrawAfterEol (TextEditor textEditor, Cairo.Context g, double y, EndOfLineMetrics metrics)
		{
			if (!IsVisible)
				return;
			EnsureLayoutCreated (editor);
			int errorCounterWidth = 0, eh = 0;
			if (errorCountLayout != null) {
				errorCountLayout.GetPixelSize (out errorCounterWidth, out eh);
				errorCounterWidth = Math.Max (15, Math.Max (errorCounterWidth + 3, (int)(editor.LineHeight * 3 / 4)));
			}

			var sx = metrics.TextRenderEndPosition;
			var width = LayoutWidth + errorCounterWidth + editor.LineHeight;
			var drawLayout = layouts[0].Layout;
			int ex = 0 , ey = 0;
			bool customLayout = true; //sx + width > editor.Allocation.Width;
			bool hideText = false;
			bubbleIsReduced = customLayout;
			var showErrorCount = errorCounterWidth > 0 && errorCountLayout != null;
			if (customLayout) {
				width = editor.Allocation.Width - sx;
				string text = layouts[0].Layout.Text;
				drawLayout = new Pango.Layout (editor.PangoContext);
				drawLayout.FontDescription = cache.fontDescription;
				var paintWidth = (width - errorCounterWidth - editor.LineHeight + 4);
				var minWidth = Math.Max (17, errorCounterWidth) + editor.LineHeight;
				if (paintWidth < minWidth) {
					hideText = true;
					drawLayout.SetMarkup ("<span weight='heavy'>···</span>");
					width = minWidth;
					showErrorCount = false;
					sx = Math.Min (sx, editor.Allocation.Width - width);
				} else {
					drawLayout.Ellipsize = Pango.EllipsizeMode.End;
					drawLayout.Width = (int)(paintWidth * Pango.Scale.PangoScale);
					drawLayout.SetText (text);
					int w2, h2;
					drawLayout.GetPixelSize (out w2, out h2);
					width = w2 + errorCounterWidth + editor.LineHeight;
				}
			}
			bubbleDrawX = sx - editor.TextViewMargin.XOffset;
			bubbleDrawY = y;
			bubbleWidth = width;

			var bubbleHeight = editor.LineHeight - 1;
			g.RoundedRectangle (sx, y + 1, width, bubbleHeight, editor.LineHeight / 2 - 1);
			g.SetSourceColor (TagColor.Color);
			g.Fill ();

			// Draw error count icon
			if (showErrorCount) {
				var errorCounterHeight = bubbleHeight - 2;
				var errorCounterX = sx + width - errorCounterWidth - 3;
				var errorCounterY = y + 1 + (bubbleHeight - errorCounterHeight) / 2;

				g.RoundedRectangle (
					errorCounterX - 1, 
					errorCounterY - 1, 
					errorCounterWidth + 2, 
					errorCounterHeight + 2, 
					editor.LineHeight / 2 - 3
				);

				g.SetSourceColor (new Cairo.Color (0, 0, 0, 0.081));
				g.Fill ();

				g.RoundedRectangle (
					errorCounterX, 
					errorCounterY, 
					errorCounterWidth, 
					errorCounterHeight, 
					editor.LineHeight / 2 - 3
				);
				using (var lg = new Cairo.LinearGradient (errorCounterX, errorCounterY, errorCounterX, errorCounterY + errorCounterHeight)) {
					lg.AddColorStop (0, CounterColor.Color);
					lg.AddColorStop (1, CounterColor.Color.AddLight (-0.1));
					g.Pattern = lg;
					g.Fill ();
				}

				g.Save ();

				int ew;
				errorCountLayout.GetPixelSize (out ew, out eh);

				g.Translate (
					errorCounterX + (errorCounterWidth - ew) / 2,
					errorCounterY + (errorCounterHeight - eh) / 2
				);
				g.SetSourceColor (CounterColor.SecondColor);
				g.ShowLayout (errorCountLayout);
				g.Restore ();
			}

			// Draw label text
			if (!showErrorCount || !hideText) {
				g.Save ();
				g.Translate (sx + editor.LineHeight / 2, y + (editor.LineHeight - layouts [0].Height) / 2 + 1);

				// draw shadow
				g.SetSourceColor (MessageBubbleCache.ShadowColor);
				g.ShowLayout (drawLayout);
				g.Translate (0, -1);

				g.SetSourceColor (TagColor.SecondColor);
				g.ShowLayout (drawLayout);
				g.Restore ();
			}

			if (customLayout)
				drawLayout.Dispose ();

		}
		public override void DrawAfterEol (TextEditor textEditor, Cairo.Context g, double y, EndOfLineMetrics metrics)
		{
			EnsureLayoutCreated (editor);
			int errorCounterWidth = 0, eh = 0;
			if (errorCountLayout != null) 
				errorCountLayout.GetPixelSize (out errorCounterWidth, out eh);

			var sx = metrics.TextRenderEndPosition;
			var width = LayoutWidth + errorCounterWidth + editor.LineHeight;
			var drawLayout = layouts[0].Layout;
			int ex = 0 , ey = 0;
			bool customLayout = sx + width > editor.Allocation.Width;
			bool hideText = false;
			bubbleIsReduced = customLayout;
			if (customLayout) {
				width = editor.Allocation.Width - sx;
				string text = layouts[0].Layout.Text;
				drawLayout = new Pango.Layout (editor.PangoContext);
				drawLayout.FontDescription = cache.fontDescription;
				for (int j = text.Length - 4; j > 0; j--) {
					drawLayout.SetText (text.Substring (0, j) + "...");
					drawLayout.GetPixelSize (out ex, out ey);
					if (ex + (errorCountLayout != null ? errorCounterWidth : 0) + editor.LineHeight < width)
						break;
				}
				if (ex + (errorCountLayout != null ? errorCounterWidth : 0) + editor.LineHeight > width) {
					hideText = true;
					drawLayout.SetMarkup ("<span weight='heavy'>···</span>");
					width = Math.Max (17, errorCounterWidth) + editor.LineHeight;
					sx = Math.Min (sx, editor.Allocation.Width - width);
				}
			}
			bubbleDrawX = sx - editor.TextViewMargin.XOffset;
			bubbleDrawY = y;
			bubbleWidth = width;
			g.RoundedRectangle (sx, y + 1, width, editor.LineHeight - 2, editor.LineHeight / 2 - 1);
			g.Color = TagColor.Color;
			g.Fill ();

			if (errorCounterWidth > 0 && errorCountLayout != null) {
				g.RoundedRectangle (sx + width - errorCounterWidth - editor.LineHeight / 2, y + 2, errorCounterWidth, editor.LineHeight - 4, editor.LineHeight / 2 - 3);
				g.Color = CounterColor.Color;
				g.Fill ();

				g.Save ();
				g.Translate (sx + width - errorCounterWidth - editor.LineHeight / 2 + (errorCounterWidth - errorCounterWidth) / 2, y + 1);
				g.Color = CounterColor.SecondColor;
				g.ShowLayout (errorCountLayout);
				g.Restore ();
			}

			if (errorCounterWidth <= 0 || errorCountLayout == null || !hideText) {
				g.Save ();
				g.Translate (sx + editor.LineHeight / 2, y + (editor.LineHeight - layouts [0].Height) / 2 + layouts [0].Height % 2);
				g.Color = TagColor.SecondColor;
				g.ShowLayout (drawLayout);
				g.Restore ();
			}

			if (customLayout)
				drawLayout.Dispose ();

		}
		protected internal override void Draw (Cairo.Context cr, Cairo.Rectangle area, DocumentLine line, int lineNr, double x, double y, double _lineHeight)
		{
//			double xStart = System.Math.Max (area.X, XOffset);
//			xStart = System.Math.Max (0, xStart);
			var correctedXOffset = System.Math.Floor (XOffset) - 1;
			var lineArea = new Cairo.Rectangle (correctedXOffset, y, textEditor.Allocation.Width - correctedXOffset, _lineHeight);
			int width, height;
			double pangoPosition = (x - textEditor.HAdjustment.Value + TextStartPosition) * Pango.Scale.PangoScale;

			defaultBgColor = Document.ReadOnly ? ColorStyle.BackgroundReadOnly.Color : ColorStyle.PlainText.Background;

			// Draw the default back color for the whole line. Colors other than the default
			// background will be drawn when rendering the text chunks.
			if (BackgroundRenderer == null)
				DrawRectangleWithRuler (cr, x, lineArea, defaultBgColor, true);
			bool isSelectionDrawn = false;

			// Check if line is beyond the document length
			if (line == null) {
				var marker = Document.GetExtendingTextMarker (lineNr);
				if (marker != null)
					marker.Draw (textEditor, cr, lineNr, lineArea);
				return;
			}
			
			IEnumerable<FoldSegment> foldings = Document.GetStartFoldings (line);
			int offset = line.Offset;
			int caretOffset = Caret.Offset;
			bool isEolFolded = false;
			restart:
			int logicalRulerColumn = line.GetLogicalColumn (textEditor.GetTextEditorData (), textEditor.Options.RulerColumn);

			if ((HighlightCaretLine || textEditor.Options.HighlightCaretLine) && Caret.Line == lineNr)
				DrawCaretLineMarker (cr, x, y, TextStartPosition, _lineHeight);

			foreach (FoldSegment folding in foldings) {
				int foldOffset = folding.StartLine.Offset + folding.Column - 1;
				if (foldOffset < offset)
					continue;

				if (folding.IsFolded) {
					
					DrawLinePart (cr, line, lineNr, logicalRulerColumn, offset, foldOffset - offset, ref pangoPosition, ref isSelectionDrawn, y, area.X + area.Width, _lineHeight);
					
					offset = folding.EndLine.Offset + folding.EndColumn - 1;
					markerLayout.SetText (folding.Description);
					markerLayout.GetSize (out width, out height);
					
					bool isFoldingSelected = !this.HideSelection && textEditor.IsSomethingSelected && textEditor.SelectionRange.Contains (folding.Segment);
					double pixelX = 0.5 + System.Math.Floor (pangoPosition / Pango.Scale.PangoScale);
					double foldXMargin = foldMarkerXMargin * textEditor.Options.Zoom;
					double pixelWidth = System.Math.Floor ((pangoPosition + width) / Pango.Scale.PangoScale - pixelX + foldXMargin * 2);
					var foldingRectangle = new Cairo.Rectangle (
						pixelX, 
						y, 
						pixelWidth, 
						this.LineHeight);

					if (BackgroundRenderer == null && isFoldingSelected) {
						cr.Color = SelectionColor.Background;
						cr.Rectangle (foldingRectangle);
						cr.Fill ();
					}

					if (isFoldingSelected && SelectionColor.TransparentForeground) {
						cr.Color = ColorStyle.CollapsedText.Foreground;
					} else {
						cr.Color = isFoldingSelected ? SelectionColor.Foreground : ColorStyle.CollapsedText.Foreground;
					}
					var boundingRectangleHeight = foldingRectangle.Height - 1;
					var boundingRectangleY = System.Math.Floor (foldingRectangle.Y + (foldingRectangle.Height - boundingRectangleHeight) / 2);
					RoundedRectangle (cr,
					                 System.Math.Floor (foldingRectangle.X) + 0.5,
					                 boundingRectangleY + 0.5,
					                 System.Math.Floor (foldingRectangle.Width - cr.LineWidth),
					                 System.Math.Floor (boundingRectangleHeight - cr.LineWidth),
					                 LineHeight / 8, CairoCorners.All, false);
					cr.Stroke ();
					
					cr.Save ();
					cr.Translate (
						pangoPosition / Pango.Scale.PangoScale + foldXMargin,
						System.Math.Floor (boundingRectangleY + (boundingRectangleHeight - System.Math.Floor (height / Pango.Scale.PangoScale)) / 2));
					cr.ShowLayout (markerLayout);
					cr.Restore ();

					if (caretOffset == foldOffset && !string.IsNullOrEmpty (folding.Description)) {
						var cx = (int)(pangoPosition / Pango.Scale.PangoScale);
						SetVisibleCaretPosition (cx, y, cx, y);
					}
					pangoPosition += foldingRectangle.Width * Pango.Scale.PangoScale;
					if (caretOffset == foldOffset + folding.Length && !string.IsNullOrEmpty (folding.Description)) {
						var cx = (int)(pangoPosition / Pango.Scale.PangoScale);
						SetVisibleCaretPosition (cx, y, cx, y);
					}

					if (folding.EndLine != line) {
						line = folding.EndLine;
						lineNr = line.LineNumber;
						foldings = Document.GetStartFoldings (line);
						isEolFolded = line.Length <= folding.EndColumn;
						goto restart;
					}
					isEolFolded = line.Length <= folding.EndColumn;
				}
			}
			
			// Draw remaining line - must be called for empty line parts as well because the caret may be at this positon
			// and the caret position is calculated in DrawLinePart.
			if (line.EndOffsetIncludingDelimiter - offset >= 0) {
				DrawLinePart (cr, line, lineNr, logicalRulerColumn, offset, line.Offset + line.Length - offset, ref pangoPosition, ref isSelectionDrawn, y, area.X + area.Width, _lineHeight);
			}

			bool isEolSelected = !this.HideSelection && textEditor.IsSomethingSelected && textEditor.SelectionMode == SelectionMode.Normal && textEditor.SelectionRange.Contains (line.Offset + line.Length);
			var lx = (int)(pangoPosition / Pango.Scale.PangoScale);
			lineArea = new Cairo.Rectangle (lx,
				lineArea.Y,
				textEditor.Allocation.Width - lx,
				lineArea.Height);

			if (textEditor.SelectionMode == SelectionMode.Block && textEditor.IsSomethingSelected && textEditor.SelectionRange.Contains (line.Offset + line.Length)) {
				DocumentLocation start = textEditor.MainSelection.Anchor;
				DocumentLocation end = textEditor.MainSelection.Lead;
				DocumentLocation visStart = textEditor.LogicalToVisualLocation (start);
				DocumentLocation visEnd = textEditor.LogicalToVisualLocation (end);
				
				double x1 = this.ColumnToX (line, visStart.Column);
				double x2 = this.ColumnToX (line, visEnd.Column);
				if (x1 > x2) {
					var tmp = x1;
					x1 = x2;
					x2 = tmp;
				}
				x1 += correctedXOffset - textEditor.HAdjustment.Value;
				x2 += correctedXOffset - textEditor.HAdjustment.Value;

				if (x2 > lineArea.X && BackgroundRenderer == null)  {
					if (x1 - lineArea.X > 0) {
						DrawRectangleWithRuler (cr, x, new Cairo.Rectangle (lineArea.X, lineArea.Y, x1 - lineArea.X, lineArea.Height), defaultBgColor, false);
						lineArea = new Cairo.Rectangle (x1, lineArea.Y, lineArea.Width, lineArea.Height);
					}
					DrawRectangleWithRuler (cr, x, new Cairo.Rectangle (lineArea.X, lineArea.Y, x2 - lineArea.X, lineArea.Height), this.SelectionColor.Background, false);
					lineArea = new Cairo.Rectangle (x2, lineArea.Y, textEditor.Allocation.Width - lineArea.X, lineArea.Height);
				}
			}

			if (!isSelectionDrawn && BackgroundRenderer == null) {
				if (isEolSelected) {
					// prevent "gaps" in the selection drawing ('fuzzy' lines problem)
					var eolStartX = System.Math.Floor (pangoPosition / Pango.Scale.PangoScale);
					lineArea = new Cairo.Rectangle (
						eolStartX,
						lineArea.Y,
						textEditor.Allocation.Width - eolStartX,
						lineArea.Height);
					DrawRectangleWithRuler (cr, x, lineArea, this.SelectionColor.Background, false);
					if (line.Length == 0)
						DrawIndent (cr, GetLayout (line), line, lx, y);
				} else if (!(HighlightCaretLine || textEditor.Options.HighlightCaretLine) || Caret.Line != lineNr) {
					LayoutWrapper wrapper = GetLayout (line);
					if (wrapper.EolSpanStack != null) {
						foreach (var span in wrapper.EolSpanStack) {
							var spanStyle = textEditor.ColorStyle.GetChunkStyle (span.Color);
							if (spanStyle == null)
								continue;
							if (!spanStyle.TransparentBackground && GetPixel (ColorStyle.PlainText.Background) != GetPixel (spanStyle.Background)) {
								DrawRectangleWithRuler (cr, x, lineArea, spanStyle.Background, false);
								break;
							}
						}
					}
				} else {
					double xPos = pangoPosition / Pango.Scale.PangoScale;
					DrawCaretLineMarker (cr, xPos, y, lineArea.X + lineArea.Width - xPos, _lineHeight);
				}
			}
			
			if (textEditor.Options.ShowWhitespaces != ShowWhitespaces.Never) {
				if (!isEolFolded && isEolSelected || textEditor.Options.ShowWhitespaces == ShowWhitespaces.Always)
					if (!(BackgroundRenderer != null && textEditor.Options.ShowWhitespaces == ShowWhitespaces.Selection))
						DrawEolMarker (cr, line, isEolSelected, pangoPosition / Pango.Scale.PangoScale, y);
			}

			var extendingMarker = Document.GetExtendingTextMarker (lineNr);
			if (extendingMarker != null)
				extendingMarker.Draw (textEditor, cr, lineNr, lineArea);

			if (BackgroundRenderer == null) {
				var metrics = new EndOfLineMetrics {
					LineSegment = line,
					TextRenderEndPosition = TextStartPosition + pangoPosition / Pango.Scale.PangoScale,
					LineHeight = _lineHeight
				};
				foreach (var marker in line.Markers) {
					marker.DrawAfterEol (textEditor, cr, y, metrics);
				}
			}

			lastLineRenderWidth = pangoPosition / Pango.Scale.PangoScale;
			if (textEditor.HAdjustment.Value > 0) {
				cr.LineWidth = textEditor.Options.Zoom;
				for (int i = 0; i < verticalShadowAlphaTable.Length; i++) {
					cr.Color = new Cairo.Color (0, 0, 0, 1 - verticalShadowAlphaTable[i]);
					cr.MoveTo (x + i * cr.LineWidth + 0.5, y);
					cr.LineTo (x + i * cr.LineWidth + 0.5, y + 1 + _lineHeight);
					cr.Stroke ();
				}
			}
		}
		public override void DrawAfterEol (MonoTextEditor textEditor, Cairo.Context g, EndOfLineMetrics metrics)
		{
			if (!IsVisible)
				return;
			EnsureLayoutCreated (editor);
			int errorCounterWidth = 0, eh = 0;
			if (errorCountLayout != null) {
				errorCountLayout.GetPixelSize (out errorCounterWidth, out eh);
				errorCounterWidth = Math.Max (15, Math.Max (errorCounterWidth + 3, (int)(editor.LineHeight * 3 / 4)));
			}

			var sx = metrics.TextRenderEndPosition;
			var width = LayoutWidth + errorCounterWidth + editor.LineHeight;
			var drawLayout = layouts[0].Layout;
			var y = metrics.LineYRenderStartPosition;
			bool customLayout = true; //sx + width > editor.Allocation.Width;
			bool hideText = false;
			bubbleIsReduced = customLayout;
			var showErrorCount = errorCounterWidth > 0 && errorCountLayout != null;
			double roundingRadius = editor.LineHeight / 2 - 1;

			if (customLayout) {
				width = editor.Allocation.Width - sx;
				string text = layouts[0].Layout.Text;
				drawLayout = new Pango.Layout (editor.PangoContext);
				drawLayout.FontDescription = cache.fontDescription;
				var paintWidth = (width - errorCounterWidth - editor.LineHeight + 4);
				var minWidth = Math.Max (25, errorCounterWidth) * editor.Options.Zoom;
				if (paintWidth < minWidth) {
					hideText = true;
					showErrorCount = false;
//					drawLayout.SetMarkup ("<span weight='heavy'>···</span>");
					width = minWidth;
					//roundingRadius = 10 * editor.Options.Zoom;
					sx = Math.Min (sx, editor.Allocation.Width - width);
				} else {
					drawLayout.Ellipsize = Pango.EllipsizeMode.End;
					drawLayout.Width = (int)(paintWidth * Pango.Scale.PangoScale);
					drawLayout.SetText (text);
					int w2, h2;
					drawLayout.GetPixelSize (out w2, out h2);
					width = w2 + errorCounterWidth + editor.LineHeight - 2;
				}
			}

			bubbleDrawX = sx - editor.TextViewMargin.XOffset;
			bubbleDrawY = y + 2;
			bubbleWidth = width;
			var bubbleHeight = editor.LineHeight;

			g.RoundedRectangle (sx, y, width, bubbleHeight, roundingRadius);
			g.SetSourceColor (TagColor.Color);
			g.Fill ();

			// Draw error count icon
			if (showErrorCount) {
				var errorCounterHeight = bubbleHeight - 2;
				var errorCounterX = sx + width - errorCounterWidth - 1;
				var errorCounterY = Math.Round (y + (bubbleHeight - errorCounterHeight) / 2);

				g.RoundedRectangle (
					errorCounterX, 
					errorCounterY, 
					errorCounterWidth, 
					errorCounterHeight, 
					editor.LineHeight / 2 - 2
				);

				using (var lg = new Cairo.LinearGradient (errorCounterX, errorCounterY, errorCounterX, errorCounterY + errorCounterHeight)) {
					lg.AddColorStop (0, CounterColor.Color);
					lg.AddColorStop (1, CounterColor.Color.AddLight (-0.1));
					g.SetSource (lg);
					g.Fill ();
				}

				g.Save ();

				int ew;
				errorCountLayout.GetPixelSize (out ew, out eh);

				var tx = Math.Round (errorCounterX + (2 + errorCounterWidth - ew) / 2);
				var ty = Math.Round (errorCounterY + (-1 + errorCounterHeight - eh) / 2);

				g.Translate (tx, ty);
				g.SetSourceColor (CounterColor.SecondColor);
				g.ShowLayout (errorCountLayout);
				g.Restore ();
			}

			if (hideText) {
				// Draw dots
				double radius = 2 * editor.Options.Zoom;
				double spacing = 1 * editor.Options.Zoom;

				sx += 1 * editor.Options.Zoom + Math.Ceiling((bubbleWidth - 3 * (radius * 2) - 2 * spacing) / 2);

				for (int i = 0; i < 3; i++) {
					g.Arc (sx, y + bubbleHeight / 2, radius, 0, Math.PI * 2);
					g.SetSourceColor (TagColor.SecondColor);
					g.Fill ();
					sx += radius * 2 + spacing;
				}
			} else {
				// Draw label text
				var tx = Math.Round (sx + editor.LineHeight / 2);
				var ty = Math.Round (y + (editor.LineHeight - layouts [0].Height) / 2) - 1;

				g.Save ();
				g.Translate (tx, ty);

				g.SetSourceColor (TagColor.SecondColor);
				g.ShowLayout (drawLayout);
				g.Restore ();
			}

			if (customLayout)
				drawLayout.Dispose ();
		}
Example #5
0
		/// <summary>
		/// Is used to draw in the area after the visible text.
		/// </summary>
		public virtual void DrawAfterEol (TextEditor textEditor, Cairo.Context cr, double y, EndOfLineMetrics lineHeight)
		{
		}
Example #6
0
 /// <summary>
 /// Is used to draw in the area after the visible text.
 /// </summary>
 public virtual void DrawAfterEol(MonoTextEditor textEditor, Cairo.Context cr, EndOfLineMetrics metrics)
 {
 }
Example #7
0
 /// <summary>
 /// Is used to draw in the area after the visible text.
 /// </summary>
 public virtual void DrawAfterEol(TextEditor textEditor, Cairo.Context cr, double y, EndOfLineMetrics lineHeight)
 {
 }
		/// <summary>
		/// Is used to draw in the area after the visible text.
		/// </summary>
		public virtual void DrawAfterEol (MonoTextEditor textEditor, Cairo.Context cr, EndOfLineMetrics metrics)
		{
		}