PageRenderTime 44ms CodeModel.GetById 10ms app.highlight 23ms RepoModel.GetById 2ms app.codeStats 0ms

/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLineElement.cs

http://github.com/icsharpcode/ILSpy
C# | 264 lines | 122 code | 24 blank | 118 comment | 33 complexity | 213e195624b46029de4edc4401e1c48b MD5 | raw file
  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.Documents;
 22using System.Windows.Input;
 23using System.Windows.Media;
 24using System.Windows.Media.TextFormatting;
 25
 26using ICSharpCode.AvalonEdit.Document;
 27
 28namespace ICSharpCode.AvalonEdit.Rendering
 29{
 30	/// <summary>
 31	/// Represents a visual element in the document.
 32	/// </summary>
 33	public abstract class VisualLineElement
 34	{
 35		/// <summary>
 36		/// Creates a new VisualLineElement.
 37		/// </summary>
 38		/// <param name="visualLength">The length of the element in VisualLine coordinates. Must be positive.</param>
 39		/// <param name="documentLength">The length of the element in the document. Must be non-negative.</param>
 40		protected VisualLineElement(int visualLength, int documentLength)
 41		{
 42			if (visualLength < 1)
 43				throw new ArgumentOutOfRangeException("visualLength", visualLength, "Value must be at least 1");
 44			if (documentLength < 0)
 45				throw new ArgumentOutOfRangeException("documentLength", documentLength, "Value must be at least 0");
 46			this.VisualLength = visualLength;
 47			this.DocumentLength = documentLength;
 48		}
 49		
 50		/// <summary>
 51		/// Gets the length of this element in visual columns.
 52		/// </summary>
 53		public int VisualLength { get; private set; }
 54		
 55		/// <summary>
 56		/// Gets the length of this element in the text document.
 57		/// </summary>
 58		public int DocumentLength { get; private set; }
 59		
 60		/// <summary>
 61		/// Gets the visual column where this element starts.
 62		/// </summary>
 63		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods",
 64		                                                 Justification = "This property holds the start visual column, use GetVisualColumn to get inner visual columns.")]
 65		public int VisualColumn { get; internal set; }
 66		
 67		/// <summary>
 68		/// Gets the text offset where this element starts, relative to the start text offset of the visual line.
 69		/// </summary>
 70		public int RelativeTextOffset { get; internal set; }
 71		
 72		/// <summary>
 73		/// Gets the text run properties.
 74		/// A unique <see cref="VisualLineElementTextRunProperties"/> instance is used for each
 75		/// <see cref="VisualLineElement"/>; colorizing code may assume that modifying the
 76		/// <see cref="VisualLineElementTextRunProperties"/> will affect only this
 77		/// <see cref="VisualLineElement"/>.
 78		/// </summary>
 79		public VisualLineElementTextRunProperties TextRunProperties { get; private set; }
 80		
 81		/// <summary>
 82		/// Gets/sets the brush used for the background of this <see cref="VisualLineElement" />.
 83		/// </summary>
 84		public Brush BackgroundBrush { get; set; }
 85		
 86		internal void SetTextRunProperties(VisualLineElementTextRunProperties p)
 87		{
 88			this.TextRunProperties = p;
 89		}
 90		
 91		/// <summary>
 92		/// Creates the TextRun for this line element.
 93		/// </summary>
 94		/// <param name="startVisualColumn">
 95		/// The visual column from which the run should be constructed.
 96		/// Normally the same value as the <see cref="VisualColumn"/> property is used to construct the full run;
 97		/// but when word-wrapping is active, partial runs might be created.
 98		/// </param>
 99		/// <param name="context">
100		/// Context object that contains information relevant for text run creation.
101		/// </param>
102		public abstract TextRun CreateTextRun(int startVisualColumn, ITextRunConstructionContext context);
103		
104		/// <summary>
105		/// Retrieves the text span immediately before the visual column.
106		/// </summary>
107		/// <remarks>This method is used for word-wrapping in bidirectional text.</remarks>
108		public virtual TextSpan<CultureSpecificCharacterBufferRange> GetPrecedingText(int visualColumnLimit, ITextRunConstructionContext context)
109		{
110			return null;
111		}
112		
113		/// <summary>
114		/// Gets if this VisualLineElement can be split.
115		/// </summary>
116		public virtual bool CanSplit {
117			get { return false; }
118		}
119		
120		/// <summary>
121		/// Splits the element.
122		/// </summary>
123		/// <param name="splitVisualColumn">Position inside this element at which it should be broken</param>
124		/// <param name="elements">The collection of line elements</param>
125		/// <param name="elementIndex">The index at which this element is in the elements list.</param>
126		public virtual void Split(int splitVisualColumn, IList<VisualLineElement> elements, int elementIndex)
127		{
128			throw new NotSupportedException();
129		}
130		
131		/// <summary>
132		/// Helper method for splitting this line element into two, correctly updating the
133		/// <see cref="VisualLength"/>, <see cref="DocumentLength"/>, <see cref="VisualColumn"/>
134		/// and <see cref="RelativeTextOffset"/> properties.
135		/// </summary>
136		/// <param name="firstPart">The element before the split position.</param>
137		/// <param name="secondPart">The element after the split position.</param>
138		/// <param name="splitVisualColumn">The split position as visual column.</param>
139		/// <param name="splitRelativeTextOffset">The split position as text offset.</param>
140		protected void SplitHelper(VisualLineElement firstPart, VisualLineElement secondPart, int splitVisualColumn, int splitRelativeTextOffset)
141		{
142			if (firstPart == null)
143				throw new ArgumentNullException("firstPart");
144			if (secondPart == null)
145				throw new ArgumentNullException("secondPart");
146			int relativeSplitVisualColumn = splitVisualColumn - VisualColumn;
147			int relativeSplitRelativeTextOffset = splitRelativeTextOffset - RelativeTextOffset;
148			
149			if (relativeSplitVisualColumn <= 0 || relativeSplitVisualColumn >= VisualLength)
150				throw new ArgumentOutOfRangeException("splitVisualColumn", splitVisualColumn, "Value must be between " + (VisualColumn + 1) + " and " + (VisualColumn + VisualLength - 1));
151			if (relativeSplitRelativeTextOffset < 0 || relativeSplitRelativeTextOffset > DocumentLength)
152				throw new ArgumentOutOfRangeException("splitRelativeTextOffset", splitRelativeTextOffset, "Value must be between " + (RelativeTextOffset) + " and " + (RelativeTextOffset + DocumentLength));
153			int oldVisualLength = VisualLength;
154			int oldDocumentLength = DocumentLength;
155			int oldVisualColumn = VisualColumn;
156			int oldRelativeTextOffset = RelativeTextOffset;
157			firstPart.VisualColumn = oldVisualColumn;
158			secondPart.VisualColumn = oldVisualColumn + relativeSplitVisualColumn;
159			firstPart.RelativeTextOffset = oldRelativeTextOffset;
160			secondPart.RelativeTextOffset = oldRelativeTextOffset + relativeSplitRelativeTextOffset;
161			firstPart.VisualLength = relativeSplitVisualColumn;
162			secondPart.VisualLength = oldVisualLength - relativeSplitVisualColumn;
163			firstPart.DocumentLength = relativeSplitRelativeTextOffset;
164			secondPart.DocumentLength = oldDocumentLength - relativeSplitRelativeTextOffset;
165			if (firstPart.TextRunProperties == null)
166				firstPart.TextRunProperties = TextRunProperties.Clone();
167			if (secondPart.TextRunProperties == null)
168				secondPart.TextRunProperties = TextRunProperties.Clone();
169		}
170		
171		/// <summary>
172		/// Gets the visual column of a text location inside this element.
173		/// The text offset is given relative to the visual line start.
174		/// </summary>
175		public virtual int GetVisualColumn(int relativeTextOffset)
176		{
177			if (relativeTextOffset >= this.RelativeTextOffset + DocumentLength)
178				return VisualColumn + VisualLength;
179			else
180				return VisualColumn;
181		}
182		
183		/// <summary>
184		/// Gets the text offset of a visual column inside this element.
185		/// </summary>
186		/// <returns>A text offset relative to the visual line start.</returns>
187		public virtual int GetRelativeOffset(int visualColumn)
188		{
189			if (visualColumn >= this.VisualColumn + VisualLength)
190				return RelativeTextOffset + DocumentLength;
191			else
192				return RelativeTextOffset;
193		}
194		
195		/// <summary>
196		/// Gets the next caret position inside this element.
197		/// </summary>
198		/// <param name="visualColumn">The visual column from which the search should be started.</param>
199		/// <param name="direction">The search direction (forwards or backwards).</param>
200		/// <param name="mode">Whether to stop only at word borders.</param>
201		/// <returns>The visual column of the next caret position, or -1 if there is no next caret position.</returns>
202		/// <remarks>
203		/// In the space between two line elements, it is sufficient that one of them contains a caret position;
204		/// though in many cases, both of them contain one.
205		/// </remarks>
206		public virtual int GetNextCaretPosition(int visualColumn, LogicalDirection direction, CaretPositioningMode mode)
207		{
208			int stop1 = this.VisualColumn;
209			int stop2 = this.VisualColumn + this.VisualLength;
210			if (direction == LogicalDirection.Backward) {
211				if (visualColumn > stop2 && mode != CaretPositioningMode.WordStart && mode != CaretPositioningMode.WordStartOrSymbol)
212					return stop2;
213				else if (visualColumn > stop1)
214					return stop1;
215			} else {
216				if (visualColumn < stop1)
217					return stop1;
218				else if (visualColumn < stop2 && mode != CaretPositioningMode.WordStart && mode != CaretPositioningMode.WordStartOrSymbol)
219					return stop2;
220			}
221			return -1;
222		}
223		
224		/// <summary>
225		/// Gets whether the specified offset in this element is considered whitespace.
226		/// </summary>
227		public virtual bool IsWhitespace(int visualColumn)
228		{
229			return false;
230		}
231		
232		/// <summary>
233		/// Gets whether the <see cref="GetNextCaretPosition"/> implementation handles line borders.
234		/// If this property returns false, the caller of GetNextCaretPosition should handle the line
235		/// borders (i.e. place caret stops at the start and end of the line).
236		/// This property has an effect only for VisualLineElements that are at the start or end of a
237		/// <see cref="VisualLine"/>.
238		/// </summary>
239		public virtual bool HandlesLineBorders {
240			get { return false; }
241		}
242		
243		/// <summary>
244		/// Queries the cursor over the visual line element.
245		/// </summary>
246		protected internal virtual void OnQueryCursor(QueryCursorEventArgs e)
247		{
248		}
249		
250		/// <summary>
251		/// Allows the visual line element to handle a mouse event.
252		/// </summary>
253		protected internal virtual void OnMouseDown(MouseButtonEventArgs e)
254		{
255		}
256		
257		/// <summary>
258		/// Allows the visual line element to handle a mouse event.
259		/// </summary>
260		protected internal virtual void OnMouseUp(MouseButtonEventArgs e)
261		{
262		}
263	}
264}