Free cookie consent management tool by TermsFeed Policy Generator

source: branches/RemoveBackwardsCompatibility/HeuristicLab.ExtLibs/HeuristicLab.AvalonEdit/5.0.1/AvalonEdit-5.0.1/Folding/FoldingElementGenerator.cs @ 18242

Last change on this file since 18242 was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

File size: 7.0 KB
Line 
1// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4// software and associated documentation files (the "Software"), to deal in the Software
5// without restriction, including without limitation the rights to use, copy, modify, merge,
6// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7// to whom the Software is furnished to do so, subject to the following conditions:
8//
9// The above copyright notice and this permission notice shall be included in all copies or
10// substantial portions of the Software.
11//
12// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17// DEALINGS IN THE SOFTWARE.
18
19using System;
20using System.Collections.Generic;
21using System.Windows;
22using System.Windows.Input;
23using System.Windows.Media;
24using System.Windows.Media.TextFormatting;
25
26using ICSharpCode.AvalonEdit.Rendering;
27using ICSharpCode.AvalonEdit.Utils;
28
29namespace ICSharpCode.AvalonEdit.Folding
30{
31  /// <summary>
32  /// A <see cref="VisualLineElementGenerator"/> that produces line elements for folded <see cref="FoldingSection"/>s.
33  /// </summary>
34  public sealed class FoldingElementGenerator : VisualLineElementGenerator, ITextViewConnect
35  {
36    readonly List<TextView> textViews = new List<TextView>();
37    FoldingManager foldingManager;
38   
39    #region FoldingManager property / connecting with TextView
40    /// <summary>
41    /// Gets/Sets the folding manager from which the foldings should be shown.
42    /// </summary>
43    public FoldingManager FoldingManager {
44      get {
45        return foldingManager;
46      }
47      set {
48        if (foldingManager != value) {
49          if (foldingManager != null) {
50            foreach (TextView v in textViews)
51              foldingManager.RemoveFromTextView(v);
52          }
53          foldingManager = value;
54          if (foldingManager != null) {
55            foreach (TextView v in textViews)
56              foldingManager.AddToTextView(v);
57          }
58        }
59      }
60    }
61   
62    void ITextViewConnect.AddToTextView(TextView textView)
63    {
64      textViews.Add(textView);
65      if (foldingManager != null)
66        foldingManager.AddToTextView(textView);
67    }
68   
69    void ITextViewConnect.RemoveFromTextView(TextView textView)
70    {
71      textViews.Remove(textView);
72      if (foldingManager != null)
73        foldingManager.RemoveFromTextView(textView);
74    }
75    #endregion
76   
77    /// <inheritdoc/>
78    public override void StartGeneration(ITextRunConstructionContext context)
79    {
80      base.StartGeneration(context);
81      if (foldingManager != null) {
82        if (!foldingManager.textViews.Contains(context.TextView))
83          throw new ArgumentException("Invalid TextView");
84        if (context.Document != foldingManager.document)
85          throw new ArgumentException("Invalid document");
86      }
87    }
88   
89    /// <inheritdoc/>
90    public override int GetFirstInterestedOffset(int startOffset)
91    {
92      if (foldingManager != null) {
93        foreach (FoldingSection fs in foldingManager.GetFoldingsContaining(startOffset)) {
94          // Test whether we're currently within a folded folding (that didn't just end).
95          // If so, create the fold marker immediately.
96          // This is necessary if the actual beginning of the fold marker got skipped due to another VisualElementGenerator.
97          if (fs.IsFolded && fs.EndOffset > startOffset) {
98            //return startOffset;
99          }
100        }
101        return foldingManager.GetNextFoldedFoldingStart(startOffset);
102      } else {
103        return -1;
104      }
105    }
106   
107    /// <inheritdoc/>
108    public override VisualLineElement ConstructElement(int offset)
109    {
110      if (foldingManager == null)
111        return null;
112      int foldedUntil = -1;
113      FoldingSection foldingSection = null;
114      foreach (FoldingSection fs in foldingManager.GetFoldingsContaining(offset)) {
115        if (fs.IsFolded) {
116          if (fs.EndOffset > foldedUntil) {
117            foldedUntil = fs.EndOffset;
118            foldingSection = fs;
119          }
120        }
121      }
122      if (foldedUntil > offset && foldingSection != null) {
123        // Handle overlapping foldings: if there's another folded folding
124        // (starting within the foldingSection) that continues after the end of the folded section,
125        // then we'll extend our fold element to cover that overlapping folding.
126        bool foundOverlappingFolding;
127        do {
128          foundOverlappingFolding = false;
129          foreach (FoldingSection fs in FoldingManager.GetFoldingsContaining(foldedUntil)) {
130            if (fs.IsFolded && fs.EndOffset > foldedUntil) {
131              foldedUntil = fs.EndOffset;
132              foundOverlappingFolding = true;
133            }
134          }
135        } while (foundOverlappingFolding);
136       
137        string title = foldingSection.Title;
138        if (string.IsNullOrEmpty(title))
139          title = "...";
140        var p = new VisualLineElementTextRunProperties(CurrentContext.GlobalTextRunProperties);
141        p.SetForegroundBrush(textBrush);
142        var textFormatter = TextFormatterFactory.Create(CurrentContext.TextView);
143        var text = FormattedTextElement.PrepareText(textFormatter, title, p);
144        return new FoldingLineElement(foldingSection, text, foldedUntil - offset) { textBrush = textBrush };
145      } else {
146        return null;
147      }
148    }
149   
150    sealed class FoldingLineElement : FormattedTextElement
151    {
152      readonly FoldingSection fs;
153     
154      internal Brush textBrush;
155     
156      public FoldingLineElement(FoldingSection fs, TextLine text, int documentLength) : base(text, documentLength)
157      {
158        this.fs = fs;
159      }
160     
161      public override TextRun CreateTextRun(int startVisualColumn, ITextRunConstructionContext context)
162      {
163        return new FoldingLineTextRun(this, this.TextRunProperties) { textBrush = textBrush };
164      }
165     
166      protected internal override void OnMouseDown(MouseButtonEventArgs e)
167      {
168        if (e.ClickCount == 2 && e.ChangedButton == MouseButton.Left) {
169          fs.IsFolded = false;
170          e.Handled = true;
171        } else {
172          base.OnMouseDown(e);
173        }
174      }
175    }
176   
177    sealed class FoldingLineTextRun : FormattedTextRun
178    {
179      internal Brush textBrush;
180     
181      public FoldingLineTextRun(FormattedTextElement element, TextRunProperties properties)
182        : base(element, properties)
183      {
184      }
185     
186      public override void Draw(DrawingContext drawingContext, Point origin, bool rightToLeft, bool sideways)
187      {
188        var metrics = Format(double.PositiveInfinity);
189        Rect r = new Rect(origin.X, origin.Y - metrics.Baseline, metrics.Width, metrics.Height);
190        drawingContext.DrawRectangle(null, new Pen(textBrush, 1), r);
191        base.Draw(drawingContext, origin, rightToLeft, sideways);
192      }
193    }
194   
195    /// <summary>
196    /// Default brush for folding element text. Value: Brushes.Gray
197    /// </summary>
198    public static readonly Brush DefaultTextBrush = Brushes.Gray;
199   
200    static Brush textBrush = DefaultTextBrush;
201   
202    /// <summary>
203    /// Gets/sets the brush used for folding element text.
204    /// </summary>
205    public static Brush TextBrush {
206      get { return textBrush; }
207      set { textBrush = value; }
208    }
209  }
210}
Note: See TracBrowser for help on using the repository browser.