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; MyImage 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) { #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); } } }
private void ShowDownloadedImage(ITextViewLine line, SnapshotSpan span, Color bgColor, MyImage image) { if (bgColor.A != 0 && image.BgColor != bgColor) { image.Scale = 1; image.Source = image.ReplaceTransparency(image.Source, bgColor); image.BgColor = bgColor; } 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); } }
/// <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); } } }