void DisplayLines(HexBufferPoint bufferPosition, double verticalDistance, VSTE.ViewRelativePosition relativeTo, double viewportWidthOverride, double viewportHeightOverride, DisplayHexLineOptions options, double? newViewportTop) { if (IsClosed) throw new InvalidOperationException(); var oldBufferLines = hexBufferLineFormatter; var oldHexBufferLineFormatterOptions = hexBufferLineFormatterOptions; Debug.Assert(oldBufferLines != null); bool raiseBufferLinesChangedEvent = false; bool revalidateBufferPosition = false; canvas.Dispatcher.VerifyAccess(); if (bufferPosition.Buffer != Buffer) throw new ArgumentException(); if (relativeTo != VSTE.ViewRelativePosition.Top && relativeTo != VSTE.ViewRelativePosition.Bottom) throw new ArgumentOutOfRangeException(nameof(relativeTo)); if (viewportHeightOverride < 0 || double.IsNaN(viewportHeightOverride)) throw new ArgumentOutOfRangeException(nameof(viewportHeightOverride)); if (viewportWidthOverride < 0 || double.IsNaN(viewportWidthOverride)) throw new ArgumentOutOfRangeException(nameof(viewportWidthOverride)); bool invalidateAllLines = false; if (recreateHexBufferLineFormatter) invalidateAllLines = true; if (viewportWidthOverride != lastViewportWidth || viewportWidthOverride != lastFormattedLineSourceViewportWidth) { invalidateAllLines = true; lastViewportWidth = viewportWidthOverride; } // Make sure the scheduled method doesn't try to call this method delayLayoutLinesInProgress = false; if (invalidateAllLines) { invalidatedRegions.Clear(); invalidatedRegions.Add(new HexBufferSpan(new HexBufferPoint(Buffer, 0), new HexBufferPoint(Buffer, HexPosition.MaxEndPosition))); } var regionsToInvalidate = new NormalizedHexBufferSpanCollection(invalidatedRegions); invalidatedRegions.Clear(); if (invalidatedRegions.Capacity > 100) invalidatedRegions.TrimExcess(); if (invalidateAllLines || formattedLineSourceIsInvalidated) { CreateFormattedLineSource(viewportWidthOverride); formattedLineSourceIsInvalidated = false; recreateHexBufferLineFormatter = true; } // This one depends on FormattedLineSource and must be created afterwards if (recreateHexBufferLineFormatter) { recreateHexBufferLineFormatter = false; raiseBufferLinesChangedEvent = true; if ((options & DisplayHexLineOptions.CanRecreateBufferLines) != 0) { // It's safe to invalidate it here since we were called by the dispatcher and // not by user code. hexBufferLineFormatter = null; // Once the new instance gets created, the input bufferPosition could be invalid // because start and/or end got updated. Re-validate it before creating new lines. revalidateBufferPosition = true; } else { // Don't re-create it here. That can lead to exceptions if Start/End positions get // updated and bufferPosition becomes invalid. New BufferLines' IsValidPosition() throws. // It's recreated with a short delay after raising LayoutChanged. } } var lineTransformProvider = LineTransformProvider; if (InLayout) throw new InvalidOperationException(); inLayout = true; var oldVisibleLines = new HashSet<HexViewLine>(wpfHexViewLineCollection == null ? (IEnumerable<HexViewLine>)Array.Empty<HexViewLine>() : wpfHexViewLineCollection); wpfHexViewLineCollection?.Invalidate(); var layoutHelper = new LayoutHelper(BufferLines, lineTransformProvider, newViewportTop ?? 0, oldVisibleLines, GetValidCachedLines(regionsToInvalidate), FormattedLineSource); if (revalidateBufferPosition) { if (bufferPosition < BufferLines.BufferStart) { bufferPosition = BufferLines.BufferStart; relativeTo = VSTE.ViewRelativePosition.Top; verticalDistance = 0; } else if (bufferPosition > BufferLines.BufferEnd) { bufferPosition = BufferLines.BufferEnd; relativeTo = VSTE.ViewRelativePosition.Bottom; verticalDistance = 0; } } layoutHelper.LayoutLines(bufferPosition, relativeTo, verticalDistance, ViewportLeft, viewportWidthOverride, viewportHeightOverride); visiblePhysicalLines.AddRange(layoutHelper.AllVisiblePhysicalLines); wpfHexViewLineCollection = new WpfHexViewLineCollectionImpl(this, layoutHelper.AllVisibleLines); if (!InLayout) throw new InvalidOperationException(); inLayout = false; textLayer.AddVisibleLines(layoutHelper.AllVisibleLines); var newOrReformattedLines = layoutHelper.NewOrReformattedLines.ToArray(); var translatedLines = layoutHelper.TranslatedLines.ToArray(); if (layoutHelper.NewViewportTop != viewportTop) { viewportTop = layoutHelper.NewViewportTop; Canvas.SetTop(normalAdornmentLayerCollection, -viewportTop); } if ((options & DisplayHexLineOptions.CanRecreateBufferLines) != 0) { if (raiseBufferLinesChangedEvent) RaiseBufferLinesChanged(oldBufferLines); } else if (raiseBufferLinesChangedEvent && oldBufferLines == hexBufferLineFormatter) { var newOptions = GetHexBufferLineFormatterOptions(); if (!newOptions.Equals(oldHexBufferLineFormatterOptions)) { canvas.Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() => { if (oldBufferLines == hexBufferLineFormatter) { hexBufferLineFormatter = null; var newBufferLines = BufferLines; RaiseBufferLinesChanged(oldBufferLines); var line = wpfHexViewLineCollection.FirstVisibleLine; verticalDistance = line.Top - ViewportTop; bufferPosition = line.BufferStart; if (bufferPosition < BufferLines.BufferStart) bufferPosition = BufferLines.BufferStart; else if (bufferPosition > BufferLines.BufferEnd) bufferPosition = BufferLines.BufferEnd; DisplayLines(bufferPosition, verticalDistance, VSTE.ViewRelativePosition.Top, ViewportWidth, ViewportHeight, DisplayHexLineOptions.CanRecreateBufferLines, ViewportTop); } })); } } // Raise this event after BufferLinesChanged event. BufferLinesChanged is more low level and // various code could use cached positions in LayoutChanged handlers (eg. the caret will use // its cached position). If this event is raised afterwards, they have a chance to re-validate // their cached values. RaiseLayoutChanged(viewportWidthOverride, viewportHeightOverride, newOrReformattedLines, translatedLines); }
/// <summary> /// Displays a line in the view /// </summary> /// <param name="bufferPosition">Position</param> /// <param name="verticalDistance">Distance relative to the top or bottom of the view</param> /// <param name="relativeTo">The <see cref="VSTE.ViewRelativePosition"/></param> /// <param name="viewportWidthOverride">Overrides viewport width</param> /// <param name="viewportHeightOverride">Overrides viewport height</param> /// <param name="options">Options</param> public abstract void DisplayHexLineContainingBufferPosition(HexBufferPoint bufferPosition, double verticalDistance, VSTE.ViewRelativePosition relativeTo, double?viewportWidthOverride, double?viewportHeightOverride, DisplayHexLineOptions options);
public override void DisplayHexLineContainingBufferPosition(HexBufferPoint bufferPosition, double verticalDistance, VSTE.ViewRelativePosition relativeTo, double? viewportWidthOverride, double? viewportHeightOverride, DisplayHexLineOptions options) => DisplayLines(bufferPosition, verticalDistance, relativeTo, viewportWidthOverride ?? ViewportWidth, viewportHeightOverride ?? ViewportHeight, options, null);
/// <summary> /// Displays a line in the view /// </summary> /// <param name="bufferPosition">Position</param> /// <param name="verticalDistance">Distance relative to the top or bottom of the view</param> /// <param name="relativeTo">The <see cref="VSTE.ViewRelativePosition"/></param> /// <param name="viewportWidthOverride">Overrides viewport width</param> /// <param name="viewportHeightOverride">Overrides viewport height</param> /// <param name="options">Options</param> public abstract void DisplayHexLineContainingBufferPosition(HexBufferPoint bufferPosition, double verticalDistance, VSTE.ViewRelativePosition relativeTo, double? viewportWidthOverride, double? viewportHeightOverride, DisplayHexLineOptions options);