internal void Redraw(FoldingSection fs) { foreach (TextView textView in textViews) { textView.Redraw(fs); } }
/// <inheritdoc/> public override VisualLineElement ConstructElement(int offset) { if (foldingManager == null) { return(null); } int foldedUntil = -1; FoldingSection foldingSection = null; foreach (FoldingSection fs in foldingManager.GetFoldingsContaining(offset)) { if (fs.IsFolded) { if (fs.EndOffset > foldedUntil) { foldedUntil = fs.EndOffset; foldingSection = fs; } } } if (foldedUntil > offset && foldingSection != null) { // Handle overlapping foldings: if there's another folded folding // (starting within the foldingSection) that continues after the end of the folded section, // then we'll extend our fold element to cover that overlapping folding. bool foundOverlappingFolding; do { foundOverlappingFolding = false; foreach (FoldingSection fs in FoldingManager.GetFoldingsContaining(foldedUntil)) { if (fs.IsFolded && fs.EndOffset > foldedUntil) { foldedUntil = fs.EndOffset; foundOverlappingFolding = true; } } } while (foundOverlappingFolding); string title = foldingSection.Title; if (string.IsNullOrEmpty(title)) { title = "..."; } var p = new VisualLineElementTextRunProperties(CurrentContext.GlobalTextRunProperties); p.SetForegroundBrush(textBrush); var textFormatter = TextFormatterFactory.Create(CurrentContext.TextView); var text = FormattedTextElement.PrepareText(textFormatter, title, p); return(new FoldingLineElement(foldingSection, text, foldedUntil - offset) { textBrush = textBrush }); } else { return(null); } }
/// <summary> /// Gets the first offset greater or equal to <paramref name="startOffset"/> where a folded folding starts. /// Returns -1 if there are no foldings after <paramref name="startOffset"/>. /// </summary> public int GetNextFoldedFoldingStart(int startOffset) { FoldingSection fs = foldings.FindFirstSegmentWithStartAfter(startOffset); while (fs != null && !fs.IsFolded) { fs = foldings.GetNextSegment(fs); } return(fs != null ? fs.StartOffset : -1); }
/// <summary> /// Removes a folding section from this manager. /// </summary> public void RemoveFolding(FoldingSection fs) { if (fs == null) { throw new ArgumentNullException("fs"); } fs.IsFolded = false; foldings.Remove(fs); Redraw(fs); }
/// <summary> /// Gets all foldings that start exactly at <paramref name="startOffset"/>. /// </summary> public ReadOnlyCollection <FoldingSection> GetFoldingsAt(int startOffset) { List <FoldingSection> result = new List <FoldingSection>(); FoldingSection fs = foldings.FindFirstSegmentWithStartAfter(startOffset); while (fs != null && fs.StartOffset == startOffset) { result.Add(fs); fs = foldings.GetNextSegment(fs); } return(result.AsReadOnly()); }
/// <summary> /// Creates a folding for the specified text section. /// </summary> public FoldingSection CreateFolding(int startOffset, int endOffset) { if (startOffset >= endOffset) { throw new ArgumentException("startOffset must be less than endOffset"); } if (startOffset < 0 || endOffset > document.TextLength) { throw new ArgumentException("Folding must be within document boundary"); } FoldingSection fs = new FoldingSection(this, startOffset, endOffset); foldings.Add(fs); Redraw(fs); return(fs); }
void TextViewVisualLinesChanged(object sender, EventArgs e) { foreach (FoldingMarginMarker m in markers) { RemoveVisualChild(m); } markers.Clear(); InvalidateVisual(); if (TextView != null && FoldingManager != null && TextView.VisualLinesValid) { foreach (VisualLine line in TextView.VisualLines) { FoldingSection fs = FoldingManager.GetNextFolding(line.FirstDocumentLine.Offset); if (fs == null) { continue; } if (fs.StartOffset <= line.LastDocumentLine.Offset + line.LastDocumentLine.Length) { FoldingMarginMarker m = new FoldingMarginMarker { IsExpanded = !fs.IsFolded, VisualLine = line, FoldingSection = fs }; markers.Add(m); AddVisualChild(m); m.IsMouseDirectlyOverChanged += delegate { InvalidateVisual(); }; InvalidateMeasure(); continue; } } } }
/// <summary> /// Updates the foldings in this <see cref="FoldingManager"/> using the given new foldings. /// This method will try to detect which new foldings correspond to which existing foldings; and will keep the state /// (<see cref="FoldingSection.IsFolded"/>) for existing foldings. /// </summary> /// <param name="newFoldings">The new set of foldings. These must be sorted by starting offset.</param> /// <param name="firstErrorOffset">The first position of a parse error. Existing foldings starting after /// this offset will be kept even if they don't appear in <paramref name="newFoldings"/>. /// Use -1 for this parameter if there were no parse errors.</param> public void UpdateFoldings(IEnumerable <NewFolding> newFoldings, int firstErrorOffset) { if (newFoldings == null) { throw new ArgumentNullException("newFoldings"); } if (firstErrorOffset < 0) { firstErrorOffset = int.MaxValue; } var oldFoldings = this.AllFoldings.ToArray(); int oldFoldingIndex = 0; int previousStartOffset = 0; // merge new foldings into old foldings so that sections keep being collapsed // both oldFoldings and newFoldings are sorted by start offset foreach (NewFolding newFolding in newFoldings) { // ensure newFoldings are sorted correctly if (newFolding.StartOffset < previousStartOffset) { throw new ArgumentException("newFoldings must be sorted by start offset"); } previousStartOffset = newFolding.StartOffset; int startOffset = newFolding.StartOffset.CoerceValue(0, document.TextLength); int endOffset = newFolding.EndOffset.CoerceValue(0, document.TextLength); if (newFolding.StartOffset == newFolding.EndOffset) { continue; // ignore zero-length foldings } // remove old foldings that were skipped while (oldFoldingIndex < oldFoldings.Length && newFolding.StartOffset > oldFoldings[oldFoldingIndex].StartOffset) { this.RemoveFolding(oldFoldings[oldFoldingIndex++]); } FoldingSection section; // reuse current folding if its matching: if (oldFoldingIndex < oldFoldings.Length && newFolding.StartOffset == oldFoldings[oldFoldingIndex].StartOffset) { section = oldFoldings[oldFoldingIndex++]; section.Length = newFolding.EndOffset - newFolding.StartOffset; } else { // no matching current folding; create a new one: section = this.CreateFolding(newFolding.StartOffset, newFolding.EndOffset); // auto-close #regions only when opening the document if (isFirstUpdate) { section.IsFolded = newFolding.DefaultClosed; } section.Tag = newFolding; } section.Title = newFolding.Name; } isFirstUpdate = false; // remove all outstanding old foldings: while (oldFoldingIndex < oldFoldings.Length) { FoldingSection oldSection = oldFoldings[oldFoldingIndex++]; if (oldSection.StartOffset >= firstErrorOffset) { break; } this.RemoveFolding(oldSection); } }
public FoldingLineElement(FoldingSection fs, TextLine text, int documentLength) : base(text, documentLength) { this.fs = fs; }