/// <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) { #pragma warning disable 219 bool imageDetected = false; // useful for tracing #pragma warning restore 219 string lineText = line.Extent.GetText(); string matchedText; int matchIndex = ImageCommentParser.Match(_contentTypeName, lineText, out matchedText); if (matchIndex >= 0) { // Get coordinates of text int start = line.Extent.Start.Position + matchIndex; int end = line.Start + (line.Extent.Length - 1); var span = new SnapshotSpan(_view.TextSnapshot, Span.FromBounds(start, end)); Exception xmlParseException; string imageUrl; double scale; Color bgColor = new Color(); ImageCommentParser.TryParse(matchedText, out imageUrl, out scale, ref bgColor, out xmlParseException); if (xmlParseException != null) { if (Images.ContainsKey(lineNumber)) { _layer.RemoveAdornment(Images[lineNumber]); Images.Remove(lineNumber); } _errorTags.Add(new TagSpan <ErrorTag>(span, new ErrorTag("XML parse error", GetErrorMessage(xmlParseException)))); return; } MyImage image; Exception imageLoadingException = null; // Check for and update existing image MyImage existingImage = Images.ContainsKey(lineNumber) ? Images[lineNumber] : null; if (existingImage != null) { image = existingImage; if (existingImage.Url != imageUrl || existingImage.BgColor != bgColor) // URL different, so set new source { existingImage.TrySet(imageUrl, scale, bgColor, out imageLoadingException, () => CreateVisuals(line, lineNumber)); } else if (existingImage.Url == imageUrl && Math.Abs(existingImage.Scale - scale) > 0.0001) // URL same but scale changed { existingImage.Scale = scale; } } else // No existing image, so create new one { image = new MyImage(_variableExpander); image.TrySet(imageUrl, scale, bgColor, out imageLoadingException, () => CreateVisuals(line, lineNumber)); Images.Add(lineNumber, image); } // Position image and add as adornment if (imageLoadingException == null) { Geometry g = _view.TextViewLines.GetMarkerGeometry(span); if (g == 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?"); } double textLeft = g.Bounds.Left; double 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, new ErrorTag("Trouble loading image", GetErrorMessage(imageLoadingException)))); } imageDetected = true; } else { if (Images.ContainsKey(lineNumber)) { Images.Remove(lineNumber); } } }
/// <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) { #pragma warning disable 219 bool imageDetected = false; // useful for tracing #pragma warning restore 219 string lineText = line.Extent.GetText(); string matchedText; int matchIndex = ImageCommentParser.Match(_contentTypeName, lineText, out matchedText); if (matchIndex >= 0) { // Get coordinates of text int start = line.Extent.Start.Position + matchIndex; int end = line.Start + (line.Extent.Length - 1); var span = new SnapshotSpan(_view.TextSnapshot, Span.FromBounds(start, end)); Exception xmlParseException; string imageUrl; double scale; Color bgColor = new Color(); ImageCommentParser.TryParse(matchedText, out imageUrl, out scale, ref bgColor, out xmlParseException); if (xmlParseException != null) { if (Images.ContainsKey(lineNumber)) { _layer.RemoveAdornment(Images[lineNumber]); Images.Remove(lineNumber); } _errorTags.Add(new TagSpan <ErrorTag>(span, new ErrorTag("XML parse error", GetErrorMessage(xmlParseException)))); return; } MyImage image; Exception imageLoadingException = null; // Check for and update existing image MyImage existingImage = Images.ContainsKey(lineNumber) ? Images[lineNumber] : null; if (existingImage != null) { image = existingImage; if (existingImage.Url != imageUrl) // URL different, so set new source { existingImage.TrySet(imageUrl, scale, bgColor, out imageLoadingException, () => CreateVisuals(line, lineNumber)); if (image.BgColor != null) { image.BgColor.R = 254; } } } else // No existing image, so create new one { image = new MyImage(_variableExpander); image.TrySet(imageUrl, scale, bgColor, out imageLoadingException, () => CreateVisuals(line, lineNumber)); if (image.BgColor != null) { image.BgColor.R = 254; } Images.Add(lineNumber, image); } // Position image and add as adornment if (imageLoadingException == null) { try { _layer.RemoveAdornment(image); } catch (Exception ex) { // No expected exceptions, so tell user something is wrong. ExceptionHandler.Notify(ex, true); } if ((image.Source as BitmapFrame)?.IsDownloading ?? false) { (image.Source as BitmapFrame).DownloadCompleted += (x, y) => { if (x == image.Source) { ShowDownloadedImage(line, span, bgColor, image); } }; } else { ShowDownloadedImage(line, span, bgColor, image); } } else { if (Images.ContainsKey(lineNumber)) { Images.Remove(lineNumber); } _errorTags.Add(new TagSpan <ErrorTag>(span, new ErrorTag("Trouble loading image", GetErrorMessage(imageLoadingException)))); } imageDetected = true; } else { if (Images.ContainsKey(lineNumber)) { Images.Remove(lineNumber); } } }