Browse Source

AvalonEdit: Use indentation from first line on all following lines when word-wrapping.

pull/14/head
Daniel Grunwald 15 years ago
parent
commit
8266dce10a
  1. 5
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/NewLineElementGenerator.cs
  2. 10
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/SingleCharacterElementGenerator.cs
  3. 50
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs
  4. 8
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLineElement.cs
  5. 7
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLineText.cs
  6. 8
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLineTextParagraphProperties.cs
  7. 37
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/TextEditorOptions.cs

5
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/NewLineElementGenerator.cs

@ -77,6 +77,11 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -77,6 +77,11 @@ namespace ICSharpCode.AvalonEdit.Rendering
}
}
public override bool IsWhitespace(int visualColumn)
{
return true;
}
public override bool HandlesLineBorders {
get { return true; }
}

10
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/SingleCharacterElementGenerator.cs

@ -118,6 +118,11 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -118,6 +118,11 @@ namespace ICSharpCode.AvalonEdit.Rendering
else
return -1;
}
public override bool IsWhitespace(int visualColumn)
{
return true;
}
}
sealed class TabTextElement : VisualLineElement
@ -148,6 +153,11 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -148,6 +153,11 @@ namespace ICSharpCode.AvalonEdit.Rendering
else
return -1;
}
public override bool IsWhitespace(int visualColumn)
{
return true;
}
}
sealed class TabGlyphRun : TextEmbeddedObject

50
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs

@ -544,7 +544,7 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -544,7 +544,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
VisualLine l = GetVisualLine(documentLine.LineNumber);
if (l == null) {
TextRunProperties globalTextRunProperties = CreateGlobalTextRunProperties();
TextParagraphProperties paragraphProperties = CreateParagraphProperties(globalTextRunProperties);
VisualLineTextParagraphProperties paragraphProperties = CreateParagraphProperties(globalTextRunProperties);
while (heightTree.GetIsCollapsed(documentLine)) {
documentLine = documentLine.PreviousLine;
@ -710,7 +710,7 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -710,7 +710,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
double CreateAndMeasureVisualLines(Size availableSize)
{
TextRunProperties globalTextRunProperties = CreateGlobalTextRunProperties();
TextParagraphProperties paragraphProperties = CreateParagraphProperties(globalTextRunProperties);
VisualLineTextParagraphProperties paragraphProperties = CreateParagraphProperties(globalTextRunProperties);
Debug.WriteLine("Measure availableSize=" + availableSize + ", scrollOffset=" + scrollOffset);
var firstLineInView = heightTree.GetLineByVisualPosition(scrollOffset.Y);
@ -786,7 +786,7 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -786,7 +786,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
};
}
TextParagraphProperties CreateParagraphProperties(TextRunProperties defaultTextRunProperties)
VisualLineTextParagraphProperties CreateParagraphProperties(TextRunProperties defaultTextRunProperties)
{
return new VisualLineTextParagraphProperties {
defaultTextRunProperties = defaultTextRunProperties,
@ -797,7 +797,7 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -797,7 +797,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
VisualLine BuildVisualLine(DocumentLine documentLine,
TextRunProperties globalTextRunProperties,
TextParagraphProperties paragraphProperties,
VisualLineTextParagraphProperties paragraphProperties,
VisualLineElementGenerator[] elementGeneratorsArray,
IVisualLineTransformer[] lineTransformersArray,
Size availableSize)
@ -829,6 +829,8 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -829,6 +829,8 @@ namespace ICSharpCode.AvalonEdit.Rendering
int textOffset = 0;
TextLineBreak lastLineBreak = null;
var textLines = new List<TextLine>();
paragraphProperties.indent = 0;
paragraphProperties.firstLineInParagraph = true;
while (textOffset <= visualLine.VisualLength) {
TextLine textLine = formatter.FormatLine(
textSource,
@ -840,12 +842,52 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -840,12 +842,52 @@ namespace ICSharpCode.AvalonEdit.Rendering
textLines.Add(textLine);
textOffset += textLine.Length;
// exit loop so that we don't do the indentation calculation if there's only a single line
if (textOffset >= visualLine.VisualLength)
break;
if (paragraphProperties.firstLineInParagraph) {
paragraphProperties.firstLineInParagraph = false;
TextEditorOptions options = this.Options;
double indentation = 0;
if (options.InheritWordWrapIndentation) {
// determine indentation for next line:
int indentVisualColumn = GetIndentationVisualColumn(visualLine);
if (indentVisualColumn > 0 && indentVisualColumn < textOffset) {
indentation = textLine.GetDistanceFromCharacterHit(new CharacterHit(indentVisualColumn, 0));
}
}
indentation += options.WordWrapIndentation;
// apply the calculated indentation unless it's more than half of the text editor size:
if (indentation > 0 && indentation * 2 < availableSize.Width)
paragraphProperties.indent = indentation;
}
lastLineBreak = textLine.GetTextLineBreak();
}
visualLine.SetTextLines(textLines);
heightTree.SetHeight(visualLine.FirstDocumentLine, visualLine.Height);
return visualLine;
}
static int GetIndentationVisualColumn(VisualLine visualLine)
{
if (visualLine.Elements.Count == 0)
return 0;
int column = 0;
int elementIndex = 0;
VisualLineElement element = visualLine.Elements[elementIndex];
while (element.IsWhitespace(column)) {
column++;
if (column == element.VisualColumn + element.VisualLength) {
elementIndex++;
if (elementIndex == visualLine.Elements.Count)
break;
element = visualLine.Elements[elementIndex];
}
}
return column;
}
#endregion
#region Arrange

8
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLineElement.cs

@ -200,6 +200,14 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -200,6 +200,14 @@ namespace ICSharpCode.AvalonEdit.Rendering
return -1;
}
/// <summary>
/// Gets whether the specified offset in this element is considered whitespace.
/// </summary>
public virtual bool IsWhitespace(int visualColumn)
{
return false;
}
/// <summary>
/// Gets whether the <see cref="GetNextCaretPosition"/> implementation handles line borders.
/// If this property returns false, the caller of GetNextCaretPosition should handle the line

7
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLineText.cs

@ -57,6 +57,13 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -57,6 +57,13 @@ namespace ICSharpCode.AvalonEdit.Rendering
return new TextCharacters(text, 0, text.Length, this.TextRunProperties);
}
/// <inheritdoc/>
public override bool IsWhitespace(int visualColumn)
{
int offset = visualColumn - this.VisualColumn + parentVisualLine.FirstDocumentLine.Offset + this.RelativeTextOffset;
return char.IsWhiteSpace(parentVisualLine.Document.GetCharAt(offset));
}
/// <inheritdoc/>
public override TextSpan<CultureSpecificCharacterBufferRange> GetPrecedingText(int visualColumnLimit, ITextRunConstructionContext context)
{

8
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLineTextParagraphProperties.cs

@ -7,11 +7,13 @@ using System.Windows.Media.TextFormatting; @@ -7,11 +7,13 @@ using System.Windows.Media.TextFormatting;
namespace ICSharpCode.AvalonEdit.Rendering
{
class VisualLineTextParagraphProperties : TextParagraphProperties
sealed class VisualLineTextParagraphProperties : TextParagraphProperties
{
internal TextRunProperties defaultTextRunProperties;
internal TextWrapping textWrapping;
internal double tabSize;
internal double indent;
internal bool firstLineInParagraph;
public override double DefaultIncrementalTab {
get { return tabSize; }
@ -20,10 +22,10 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -20,10 +22,10 @@ namespace ICSharpCode.AvalonEdit.Rendering
public override FlowDirection FlowDirection { get { return FlowDirection.LeftToRight; } }
public override TextAlignment TextAlignment { get { return TextAlignment.Left; } }
public override double LineHeight { get { return double.NaN; } }
public override bool FirstLineInParagraph { get { return false; } }
public override bool FirstLineInParagraph { get { return firstLineInParagraph; } }
public override TextRunProperties DefaultTextRunProperties { get { return defaultTextRunProperties; } }
public override TextWrapping TextWrapping { get { return textWrapping; } }
public override TextMarkerProperties TextMarkerProperties { get { return null; } }
public override double Indent { get { return 0; } }
public override double Indent { get { return indent; } }
}
}

37
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/TextEditorOptions.cs

@ -267,5 +267,42 @@ namespace ICSharpCode.AvalonEdit @@ -267,5 +267,42 @@ namespace ICSharpCode.AvalonEdit
}
}
}
double wordWrapIndentation = 100;
/// <summary>
/// Gets/Sets the indentation used for all lines except the first when word-wrapping.
/// The default value is 0.
/// </summary>
[DefaultValue(100)]
public virtual double WordWrapIndentation {
get { return wordWrapIndentation; }
set {
if (double.IsNaN(value) || double.IsInfinity(value))
throw new ArgumentOutOfRangeException("value", value, "value must not be NaN/infinity");
if (value != wordWrapIndentation) {
wordWrapIndentation = value;
OnPropertyChanged("WordWrapIndentation");
}
}
}
bool inheritWordWrapIndentation = true;
/// <summary>
/// Gets/Sets whether the indentation is inherited from the first line when word-wrapping.
/// The default value is true.
/// </summary>
/// <remarks>When combined with <see cref="WordWrapIndentation"/>, the inherited indentation is added to the word wrap indentation.</remarks>
[DefaultValue(true)]
public virtual bool InheritWordWrapIndentation {
get { return inheritWordWrapIndentation; }
set {
if (value != inheritWordWrapIndentation) {
inheritWordWrapIndentation = value;
OnPropertyChanged("InheritWordWrapIndentation");
}
}
}
}
}

Loading…
Cancel
Save