/// <summary> /// AddLineAnnot adds a line annotation to the annotation manager. /// </summary> /// <param name="srcXPixels">The X coordinate of the source (pixels).</param> /// <param name="srcYPixels">The Y coordinate of the source (pixels).</param> /// <param name="dstXPixels">The X coordinate of the target (pixels).</param> /// <param name="dstYPixels">The Y coordinate of the target (pixels).</param> /// <param name="colorComponents">The components for the color of the line.</param> /// <param name="borderWidthPixels">The width of the border (pixels).</param> public void AddLineAnnot(int srcXPixels, int srcYPixels, int dstXPixels, int dstYPixels, byte[] colorComponents, int borderWidthPixels) { if (_textWriter != null) { _textWriter.WriteLine("AddLineAnnot"); _textWriter.WriteLine("srcYPixels: " + srcXPixels + "srcYPixels: " + srcYPixels + " dstXPixels: " + dstXPixels + " dstYPixels: " + dstYPixels); _textWriter.WriteLine("colorComponents: " + colorComponents[0] + " " + colorComponents[1] + " " + colorComponents[2]); _textWriter.WriteLine("borderWidthPixels: " + borderWidthPixels); } AnnotationLine annotation = _annotationManager.AddLineAnnot(GdPictureColor(colorComponents), ToInchesHorizontal(srcXPixels), ToInchesVertical(srcYPixels), ToInchesHorizontal(dstXPixels), ToInchesVertical(dstYPixels)); GdPictureStatus status = _annotationManager.GetStat(); if (status != GdPictureStatus.OK) { LastError = status; } annotation.BorderWidth = ToInchesHorizontal(borderWidthPixels); }
private void RenderAnnotationLines(AnnotationLine annotationLine, string prefix) { var sourceFile = annotationLine.Annotations.First().Span.Source; Debug.Assert(sourceFile != null); var line = sourceFile.Line(annotationLine.AnnotatedLine).TrimEnd(); // Order annotations by starting position var annotationsOrdered = annotationLine.Annotations.OrderBy(si => si.Span.Start).ToList(); // Now we draw the arrows to their correct places under the annotated line // Also collect physical column positions to extend the arrows var arrowHeadColumns = new List <(int Column, SpannedDiagnosticInfo Info)>(); buffer.Write(prefix); var lineCur = new LineCursor { TabSize = TabSize }; var charIdx = 0; foreach (var annot in annotationsOrdered) { // From the last character index until the start of this annotation we need to fill with spaces for (; charIdx < annot.Span.Start.Column; ++charIdx) { if (charIdx < line.Length) { // Still in range of the line lineCur.Append(line[charIdx], out var advance); buffer.CursorX += advance; } else { // After the line buffer.CursorX += 1; } } // Now we are inside the span var arrowHead = annot.Severity != null ? '^' : '-'; var startColumn = buffer.CursorX; arrowHeadColumns.Add((startColumn, annot)); if (annot.Severity != null) { buffer.ForegroundColor = annot.Severity.Color; } for (; charIdx < annot.Span.End.Column; ++charIdx) { if (charIdx < line.Length) { // Still in range of the line lineCur.Append(line[charIdx], out var advance); for (int i = 0; i < advance; ++i) { buffer.Write(arrowHead); } } else { // After the line buffer.Write(arrowHead); } } var endColumn = buffer.CursorX; if (annot.Severity != null) { // Recolor the source line too buffer.Recolor(startColumn, buffer.CursorY - 1, endColumn - startColumn, 1); buffer.ResetColor(); } } // Now we are done with arrows in the line, it's time to do the arrow bodies downwards // The first one will have N, the last 0 length bodies, decreasing by one // The last one just has the message inline { var lastAnnot = annotationsOrdered.Last(); if (lastAnnot.Message != null) { buffer.Write($" {lastAnnot.Message}"); } buffer.WriteLine(); } // From now on all previous ones will be one longer than the ones later int arrowBaseLine = buffer.CursorY; int arrowBodyLength = 0; // We only consider annotations with messages foreach (var(col, annot) in arrowHeadColumns.SkipLast(1).Reverse().Where(a => a.Info.Message != null)) { if (annot.Severity != null) { buffer.ForegroundColor = annot.Severity.Color; } // Draw the arrow buffer.Fill(col, arrowBaseLine, 1, arrowBodyLength, '│'); buffer.Plot(col, arrowBaseLine + arrowBodyLength, '└'); arrowBodyLength += 1; // Append the message buffer.Write($" {annot.Message}"); if (annot.Severity != null) { buffer.ResetColor(); } } // Fill the in between lines with the prefix for (int i = 0; i < arrowBodyLength; ++i) { buffer.WriteAt(0, arrowBaseLine + i, prefix); } // Reset cursor position buffer.CursorX = 0; buffer.CursorY = arrowBaseLine + arrowBodyLength; }