LineTransform ILineTransformSource.GetLineTransform(ITextViewLine line, double yPosition, ViewRelativePosition placement) { #pragma warning disable 219 bool imageOnLine = false; // useful for tracing #pragma warning restore 219 int lineNumber = line.Snapshot.GetLineFromPosition(line.Start.Position).LineNumber; LineTransform lineTransform; // Look up Image for current line and increase line height as necessary if (_manager.Images.ContainsKey(lineNumber) && ImageAdornmentManager.Enabled) { double defaultHeight = line.DefaultLineTransform.BottomSpace; CommentImage image = _manager.Images[lineNumber]; lineTransform = new LineTransform(0, image.Height + defaultHeight, 1.0); imageOnLine = true; } else { lineTransform = new LineTransform(0, 0, 1.0); } return(lineTransform); }
/// <summary> /// Scans text line for matching image comment signature, then adds new or updates existing image adornment /// </summary> private void CreateVisuals(ITextViewLine line, int lineNumber, string absFilename) { ThreadHelper.ThrowIfNotOnUIThread(); var directory = absFilename != null?System.IO.Path.GetDirectoryName(absFilename) : null; var lineText = line.Extent.GetText().Split(new[] { "\r\n", "\r" }, StringSplitOptions.None)[0]; var matchIndex = ImageCommentParser.Match(_contentTypeName, lineText, out var matchedText); if (matchIndex >= 0) { //lineText = line.Extent.GetText().Split(new string[] { "\r\n", "\r" }, StringSplitOptions.None)[0]; // Get coordinates of text var start = line.Extent.Start.Position + matchIndex; var end = line.Start + (line.Extent.Length - 1); var span = new SnapshotSpan(_view.TextSnapshot, Span.FromBounds(start, end)); ImageCommentParser.TryParse(matchedText, out var parsedImgData, out var parsingError); if (parsingError != null) { if (Images.ContainsKey(lineNumber)) { _layer.RemoveAdornment(Images[lineNumber]); Images.Remove(lineNumber); } _errorTags.Add(new TagSpan <ErrorTag>(span, new ErrorTag("XML parse error", $"Problem with comment format: {parsingError}"))); return; } string loadingMessage = null; // Check for and update existing image CommentImage image = Images.ContainsKey(lineNumber) ? Images[lineNumber] : null; if (image != null) { if (!image.Attributes.IsEqual(parsedImgData)) { image.TrySet(directory, parsedImgData, out loadingMessage, () => CreateVisuals(line, lineNumber, absFilename)); } } else // No existing image, so create new one { image = new CommentImage(_variableExpander); image.TrySet(directory, parsedImgData, out loadingMessage, () => CreateVisuals(line, lineNumber, absFilename)); Images.Add(lineNumber, image); } // Position image and add as adornment if (loadingMessage == null && image.Source != null) { var geometry = _view.TextViewLines.GetMarkerGeometry(span); if (geometry == null) // Exceptional case when image dimensions are massive (e.g. specifying very large scale factor) { throw new InvalidOperationException("Couldn't get source code line geometry. Is the loaded image massive?"); } var textLeft = geometry.Bounds.Left; var textBottom = line.TextBottom; Canvas.SetLeft(image, textLeft); Canvas.SetTop(image, textBottom); // Add image to editor view try { _layer.RemoveAdornment(image); _layer.AddAdornment(AdornmentPositioningBehavior.TextRelative, line.Extent, null, image, null); } catch (Exception ex) { // No expected exceptions, so tell user something is wrong. ExceptionHandler.Notify(ex, true); } } else { if (Images.ContainsKey(lineNumber)) { Images.Remove(lineNumber); } _errorTags.Add(new TagSpan <ErrorTag>(span, loadingMessage == null ? new ErrorTag("No image set", "No image set") : new ErrorTag("Trouble loading image", loadingMessage))); } } else { if (Images.ContainsKey(lineNumber)) { Images.Remove(lineNumber); } } }