bool IsSelected(AdornmentTagInfo adornmentInfo, HexViewLine line)
 {
     if (line == null)
     {
         return(false);
     }
     if (wpfHexView.Selection.IsEmpty)
     {
         return(false);
     }
     if (adornmentInfo.HexTagSpan != null)
     {
         foreach (var span in wpfHexView.Selection.SelectedSpans)
         {
             if (span.Contains(adornmentInfo.BufferSpan))
             {
                 return(true);
             }
         }
     }
     else
     {
         foreach (var span in wpfHexView.Selection.GetSelectionOnHexViewLine(line))
         {
             if (span.Contains(adornmentInfo.HexTextTagSpan.Span))
             {
                 return(true);
             }
         }
     }
     return(false);
 }
        public IEnumerable <ITagSpan <SpaceNegotiatingAdornmentTag> > GetTags(NormalizedSnapshotSpanCollection spans)
        {
            if (wpfTextView.IsClosed)
            {
                yield break;
            }

            foreach (var span in spans)
            {
                foreach (var tagSpan in tagAggregator.GetTags(span))
                {
                    var spanColl = tagSpan.Span.GetSpans(wpfTextView.TextSnapshot);
                    Debug.Assert(spanColl.Count != 0);
                    if (spanColl.Count == 0)
                    {
                        continue;
                    }
                    var    fullSpan      = new SnapshotSpan(spanColl[0].Snapshot, Span.FromBounds(spanColl[0].Span.Start, spanColl[spanColl.Count - 1].Span.End));
                    var    uiElem        = tagSpan.Tag.Adornment;
                    double topSpace      = tagSpan.Tag.TopSpace ?? 0;
                    double bottomSpace   = tagSpan.Tag.BottomSpace ?? 0;
                    double textHeight    = tagSpan.Tag.TextHeight ?? (Filter(uiElem.DesiredSize.Height) - (topSpace + bottomSpace));
                    var    adornmentInfo = new AdornmentTagInfo(fullSpan, uiElem, tagSpan);
                    var    tag           = new SpaceNegotiatingAdornmentTag(Filter(uiElem.DesiredSize.Width), topSpace,
                                                                            tagSpan.Tag.Baseline ?? textHeight * 0.75, textHeight, bottomSpace,
                                                                            tagSpan.Tag.Affinity ?? PositionAffinity.Predecessor, adornmentInfo, providerTag);
                    adornmentInfo.Tag = tag;
                    yield return(new TagSpan <SpaceNegotiatingAdornmentTag>(fullSpan, tag));
                }
            }
        }
        void UpdateAdornmentUIState(HexViewLine line, AdornmentTagInfo adornmentInfo, VSTF.TextBounds bounds)
        {
            double verticalScale = line.LineTransform.VerticalScale;

            adornmentInfo.TopUIElement.SetScale(verticalScale);
            Canvas.SetTop(adornmentInfo.TopUIElement, bounds.TextTop + line.Baseline - verticalScale * adornmentInfo.Tag.Baseline);
            Canvas.SetLeft(adornmentInfo.TopUIElement, bounds.Left);
        }
        void UpdateIsSelected(AdornmentTagInfo adornmentInfo, HexViewLine line)
        {
            if (line == null)
            {
                line = wpfHexView.HexViewLines.GetHexViewLineContainingBufferPosition(adornmentInfo.BufferSpan.Start);
            }
            bool selected = IsSelected(adornmentInfo, line);

            VSTE.IntraTextAdornment.SetIsSelected(adornmentInfo.UserUIElement, selected);
        }
        void UpdateIsSelected(AdornmentTagInfo adornmentInfo, ITextViewLine line)
        {
            if (line == null)
            {
                line = wpfTextView.TextViewLines.GetTextViewLineContainingBufferPosition(adornmentInfo.Span.Start);
            }
            var  selSpan  = line == null ? null : wpfTextView.Selection.GetSelectionOnTextViewLine(line);
            bool selected = selSpan != null && selSpan.Value.Contains(new VirtualSnapshotSpan(adornmentInfo.Span));

            IntraTextAdornment.SetIsSelected(adornmentInfo.UserUIElement, selected);
        }
        bool AddAdornment(AdornmentTagInfo adornmentInfo, HexViewLine line)
        {
            SizeChangedEventHandler sizeChanged = (a, e) => {
                var bounds = line.GetAdornmentBounds(adornmentInfo);
                if (bounds == null)
                {
                    return;
                }
                // Sometimes the size just gets changed very little, eg. from 400 to 399.95.....
                const double d = 0.5;
                if (e.NewSize.Height <= bounds.Value.Height + d && e.NewSize.Width <= bounds.Value.Width + d)
                {
                    return;
                }
                tagger?.RefreshSpans(new HexBufferSpanEventArgs(adornmentInfo.BufferSpan));
            };

            adornmentInfo.TopUIElement.SizeChanged += sizeChanged;

            VSTE.AdornmentRemovedCallback removedCallback = (a, b) => {
                adornmentTagInfos.Remove(adornmentInfo);
                adornmentInfo.TopUIElement.SizeChanged -= sizeChanged;
                adornmentInfo.TopUIElement.OnRemoved();
                if (adornmentInfo.HexTagSpan != null)
                {
                    adornmentInfo.HexTagSpan.Tag.RemovalCallback?.Invoke(adornmentInfo.HexTagSpan, b);
                }
                else
                {
                    adornmentInfo.HexTextTagSpan.Tag.RemovalCallback?.Invoke(adornmentInfo.HexTextTagSpan, b);
                }
            };

            Debug.Assert(!adornmentTagInfos.Contains(adornmentInfo));
            adornmentTagInfos.Add(adornmentInfo);
            // Use OwnerControlled because there are corner cases that the adornment layer can't handle,
            // eg. an adornment with buffer span length == 0 that is shown on its own line (word wrap).
            bool added = layer.AddAdornment(VSTE.AdornmentPositioningBehavior.OwnerControlled, (HexBufferSpan?)null, adornmentInfo, adornmentInfo.TopUIElement, removedCallback);

            if (!added)
            {
                removedCallback(null, adornmentInfo.TopUIElement);
            }
            return(added);
        }
        bool AddAdornment(AdornmentTagInfo adornmentInfo)
        {
            var oldSize = adornmentInfo.TopUIElement.DesiredSize;
            SizeChangedEventHandler sizeChanged = (a, e) => {
                if (e.NewSize == oldSize)
                {
                    return;
                }
                // Sometimes the size just gets changed very little, eg. from 400 to 399.95.....
                const double d = 0.5;
                if (Math.Abs(e.NewSize.Height - oldSize.Height) < d && Math.Abs(e.NewSize.Width - oldSize.Width) < d)
                {
                    return;
                }
                oldSize = e.NewSize;
                tagger?.RefreshSpans(new SnapshotSpanEventArgs(adornmentInfo.Span));
            };

            adornmentInfo.TopUIElement.SizeChanged += sizeChanged;

            AdornmentRemovedCallback removedCallback = (a, b) => {
                adornmentTagInfos.Remove(adornmentInfo);
                adornmentInfo.TopUIElement.SizeChanged -= sizeChanged;
                adornmentInfo.TopUIElement.OnRemoved();
                adornmentInfo.TagSpan.Tag.RemovalCallback?.Invoke(adornmentInfo.TagSpan, b);
            };

            Debug.Assert(!adornmentTagInfos.Contains(adornmentInfo));
            adornmentTagInfos.Add(adornmentInfo);
            // Use OwnerControlled because there are corner cases that the adornment layer can't handle,
            // eg. an adornment with buffer span length == 0 that is shown on its own line (word wrap).
            bool added = layer.AddAdornment(AdornmentPositioningBehavior.OwnerControlled, null, adornmentInfo, adornmentInfo.TopUIElement, removedCallback);

            if (!added)
            {
                removedCallback(null, adornmentInfo.TopUIElement);
            }
            return(added);
        }
        public override IEnumerable <IHexTextTagSpan <HexSpaceNegotiatingAdornmentTag> > GetLineTags(HexTaggerContext context)
        {
            if (wpfHexView.IsClosed)
            {
                yield break;
            }

            var taggerContext = new HexTaggerContext(context.Line, context.LineSpan);

            foreach (var tagSpan in tagAggregator.GetLineTags(taggerContext))
            {
                var    uiElem        = tagSpan.Tag.Adornment;
                double topSpace      = tagSpan.Tag.TopSpace ?? 0;
                double bottomSpace   = tagSpan.Tag.BottomSpace ?? 0;
                double textHeight    = tagSpan.Tag.TextHeight ?? (Filter(uiElem.DesiredSize.Height) - (topSpace + bottomSpace));
                var    adornmentInfo = new AdornmentTagInfo(context.Line.BufferSpan, uiElem, tagSpan);
                var    tag           = new HexSpaceNegotiatingAdornmentTag(Filter(uiElem.DesiredSize.Width), topSpace,
                                                                           tagSpan.Tag.Baseline ?? textHeight * 0.75, textHeight, bottomSpace,
                                                                           tagSpan.Tag.Affinity ?? VST.PositionAffinity.Predecessor, adornmentInfo, providerTag);
                adornmentInfo.Tag = tag;
                yield return(new HexTextTagSpan <HexSpaceNegotiatingAdornmentTag>(tagSpan.Span, tag));
            }
        }