Browse Source

Implemented SD-1853 - AvalonEdit: Distinguish between 'end of line' and 'start of next line' at word wrap positions

Also, the Home/End keys now apply to the current TextLine, not the whole VisualLine.
pull/41/head
Daniel Grunwald 13 years ago
parent
commit
00d4408a57
  1. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Caret.cs
  2. 22
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs
  3. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/ImeNativeWrapper.cs
  4. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs
  5. 31
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs
  6. 12
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs
  7. 4
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/BackgroundGeometryBuilder.cs
  8. 8
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs
  9. 61
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs
  10. 22
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/TextViewPosition.cs

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Caret.cs

@ -348,7 +348,7 @@ namespace ICSharpCode.AvalonEdit.Editing
RevalidateVisualColumn(visualLine); RevalidateVisualColumn(visualLine);
} }
TextLine textLine = visualLine.GetTextLine(position.VisualColumn); TextLine textLine = visualLine.GetTextLine(position.VisualColumn, position.IsAtEndOfLine);
double xPos = visualLine.GetTextLineVisualXPosition(textLine, position.VisualColumn); double xPos = visualLine.GetTextLineVisualXPosition(textLine, position.VisualColumn);
double lineTop = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.TextTop); double lineTop = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.TextTop);
double lineBottom = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.TextBottom); double lineBottom = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.TextBottom);

22
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs

@ -177,7 +177,7 @@ namespace ICSharpCode.AvalonEdit.Editing
DocumentLine caretLine = textArea.Document.GetLineByNumber(textArea.Caret.Line); DocumentLine caretLine = textArea.Document.GetLineByNumber(textArea.Caret.Line);
VisualLine visualLine = textArea.TextView.GetOrConstructVisualLine(caretLine); VisualLine visualLine = textArea.TextView.GetOrConstructVisualLine(caretLine);
TextViewPosition caretPosition = textArea.Caret.Position; TextViewPosition caretPosition = textArea.Caret.Position;
TextLine textLine = visualLine.GetTextLine(caretPosition.VisualColumn); TextLine textLine = visualLine.GetTextLine(caretPosition.VisualColumn, caretPosition.IsAtEndOfLine);
switch (direction) { switch (direction) {
case CaretMovementType.CharLeft: case CaretMovementType.CharLeft:
MoveCaretLeft(textArea, caretPosition, visualLine, CaretPositioningMode.Normal); MoveCaretLeft(textArea, caretPosition, visualLine, CaretPositioningMode.Normal);
@ -204,10 +204,10 @@ namespace ICSharpCode.AvalonEdit.Editing
SetCaretPosition(textArea, -1, textArea.Document.TextLength); SetCaretPosition(textArea, -1, textArea.Document.TextLength);
break; break;
case CaretMovementType.LineStart: case CaretMovementType.LineStart:
MoveCaretToStartOfLine(textArea, visualLine); MoveCaretToStartOfLine(textArea, visualLine, textLine);
break; break;
case CaretMovementType.LineEnd: case CaretMovementType.LineEnd:
MoveCaretToEndOfLine(textArea, visualLine); MoveCaretToEndOfLine(textArea, visualLine, textLine);
break; break;
default: default:
throw new NotSupportedException(direction.ToString()); throw new NotSupportedException(direction.ToString());
@ -216,9 +216,11 @@ namespace ICSharpCode.AvalonEdit.Editing
#endregion #endregion
#region Home/End #region Home/End
static void MoveCaretToStartOfLine(TextArea textArea, VisualLine visualLine) static void MoveCaretToStartOfLine(TextArea textArea, VisualLine visualLine, TextLine textLine)
{ {
int newVC = visualLine.GetNextCaretPosition(-1, LogicalDirection.Forward, CaretPositioningMode.WordStart, textArea.Selection.EnableVirtualSpace); int newVC = visualLine.GetTextLineVisualStartColumn(textLine);
if (newVC == 0)
newVC = visualLine.GetNextCaretPosition(newVC - 1, LogicalDirection.Forward, CaretPositioningMode.WordStart, textArea.Selection.EnableVirtualSpace);
if (newVC < 0) if (newVC < 0)
throw ThrowUtil.NoValidCaretPosition(); throw ThrowUtil.NoValidCaretPosition();
// when the caret is already at the start of the text, jump to start before whitespace // when the caret is already at the start of the text, jump to start before whitespace
@ -228,11 +230,11 @@ namespace ICSharpCode.AvalonEdit.Editing
SetCaretPosition(textArea, newVC, offset); SetCaretPosition(textArea, newVC, offset);
} }
static void MoveCaretToEndOfLine(TextArea textArea, VisualLine visualLine) static void MoveCaretToEndOfLine(TextArea textArea, VisualLine visualLine, TextLine textLine)
{ {
int newVC = visualLine.VisualLength; int newVC = visualLine.GetTextLineVisualStartColumn(textLine) + textLine.Length - textLine.TrailingWhitespaceLength;
int offset = visualLine.FirstDocumentLine.Offset + visualLine.GetRelativeOffset(newVC); int offset = visualLine.FirstDocumentLine.Offset + visualLine.GetRelativeOffset(newVC);
SetCaretPosition(textArea, newVC, offset); SetCaretPosition(textArea, newVC, offset, isAtEndOfLine: true);
} }
#endregion #endregion
@ -365,9 +367,9 @@ namespace ICSharpCode.AvalonEdit.Editing
SetCaretPosition(textArea, newVisualColumn, newOffset); SetCaretPosition(textArea, newVisualColumn, newOffset);
} }
static void SetCaretPosition(TextArea textArea, int newVisualColumn, int newOffset) static void SetCaretPosition(TextArea textArea, int newVisualColumn, int newOffset, bool isAtEndOfLine = false)
{ {
textArea.Caret.Position = new TextViewPosition(textArea.Document.GetLocation(newOffset), newVisualColumn); textArea.Caret.Position = new TextViewPosition(textArea.Document.GetLocation(newOffset), newVisualColumn) { IsAtEndOfLine = isAtEndOfLine };
textArea.Caret.DesiredXPos = double.NaN; textArea.Caret.DesiredXPos = double.NaN;
} }
#endregion #endregion

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/ImeNativeWrapper.cs

@ -169,7 +169,7 @@ namespace ICSharpCode.AvalonEdit.Editing
// in those cases. It should be refreshed immediately. // in those cases. It should be refreshed immediately.
if (source.RootVisual == null || !source.RootVisual.IsAncestorOf(textView)) if (source.RootVisual == null || !source.RootVisual.IsAncestorOf(textView))
return EMPTY_RECT; return EMPTY_RECT;
TextLine line = vl.GetTextLine(pos.VisualColumn); TextLine line = vl.GetTextLine(pos.VisualColumn, pos.IsAtEndOfLine);
Rect displayRect; Rect displayRect;
// calculate the display rect for the current character // calculate the display rect for the current character
if (pos.VisualColumn < vl.VisualLengthWithEndOfLineMarker) { if (pos.VisualColumn < vl.VisualLengthWithEndOfLineMarker) {

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs

@ -148,7 +148,7 @@ namespace ICSharpCode.AvalonEdit.Editing
DocumentLine documentLine = textArea.Document.GetLineByNumber(pos.Line); DocumentLine documentLine = textArea.Document.GetLineByNumber(pos.Line);
VisualLine visualLine = textArea.TextView.GetOrConstructVisualLine(documentLine); VisualLine visualLine = textArea.TextView.GetOrConstructVisualLine(documentLine);
int vc = visualLine.ValidateVisualColumn(pos, true); int vc = visualLine.ValidateVisualColumn(pos, true);
TextLine textLine = visualLine.GetTextLine(vc); TextLine textLine = visualLine.GetTextLine(vc, pos.IsAtEndOfLine);
return visualLine.GetTextLineVisualXPosition(textLine, vc); return visualLine.GetTextLineVisualXPosition(textLine, vc);
} }

31
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs

@ -166,9 +166,10 @@ namespace ICSharpCode.AvalonEdit.Editing
if (e.Data.GetDataPresent(DataFormats.UnicodeText, true)) { if (e.Data.GetDataPresent(DataFormats.UnicodeText, true)) {
e.Handled = true; e.Handled = true;
int visualColumn; int visualColumn;
int offset = GetOffsetFromMousePosition(e.GetPosition(textArea.TextView), out visualColumn); bool isAtEndOfLine;
int offset = GetOffsetFromMousePosition(e.GetPosition(textArea.TextView), out visualColumn, out isAtEndOfLine);
if (offset >= 0) { if (offset >= 0) {
textArea.Caret.Position = new TextViewPosition(textArea.Document.GetLocation(offset), visualColumn); textArea.Caret.Position = new TextViewPosition(textArea.Document.GetLocation(offset), visualColumn) { IsAtEndOfLine = isAtEndOfLine };
textArea.Caret.DesiredXPos = double.NaN; textArea.Caret.DesiredXPos = double.NaN;
if (textArea.ReadOnlySectionProvider.CanInsert(offset)) { if (textArea.ReadOnlySectionProvider.CanInsert(offset)) {
if ((e.AllowedEffects & DragDropEffects.Move) == DragDropEffects.Move if ((e.AllowedEffects & DragDropEffects.Move) == DragDropEffects.Move
@ -359,7 +360,8 @@ namespace ICSharpCode.AvalonEdit.Editing
Point p = e.GetPosition(textArea.TextView); Point p = e.GetPosition(textArea.TextView);
if (p.X >= 0 && p.Y >= 0 && p.X <= textArea.TextView.ActualWidth && p.Y <= textArea.TextView.ActualHeight) { if (p.X >= 0 && p.Y >= 0 && p.X <= textArea.TextView.ActualWidth && p.Y <= textArea.TextView.ActualHeight) {
int visualColumn; int visualColumn;
int offset = GetOffsetFromMousePosition(e, out visualColumn); bool isAtEndOfLine;
int offset = GetOffsetFromMousePosition(e, out visualColumn, out isAtEndOfLine);
if (textArea.Selection.Contains(offset)) if (textArea.Selection.Contains(offset))
e.Cursor = Cursors.Arrow; e.Cursor = Cursors.Arrow;
else else
@ -380,7 +382,8 @@ namespace ICSharpCode.AvalonEdit.Editing
bool shift = (modifiers & ModifierKeys.Shift) == ModifierKeys.Shift; bool shift = (modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;
if (enableTextDragDrop && e.ClickCount == 1 && !shift) { if (enableTextDragDrop && e.ClickCount == 1 && !shift) {
int visualColumn; int visualColumn;
int offset = GetOffsetFromMousePosition(e, out visualColumn); bool isAtEndOfLine;
int offset = GetOffsetFromMousePosition(e, out visualColumn, out isAtEndOfLine);
if (textArea.Selection.Contains(offset)) { if (textArea.Selection.Contains(offset)) {
if (textArea.CaptureMouse()) { if (textArea.CaptureMouse()) {
mode = SelectionMode.PossibleDragStart; mode = SelectionMode.PossibleDragStart;
@ -488,12 +491,12 @@ namespace ICSharpCode.AvalonEdit.Editing
} }
} }
int GetOffsetFromMousePosition(MouseEventArgs e, out int visualColumn) int GetOffsetFromMousePosition(MouseEventArgs e, out int visualColumn, out bool isAtEndOfLine)
{ {
return GetOffsetFromMousePosition(e.GetPosition(textArea.TextView), out visualColumn); return GetOffsetFromMousePosition(e.GetPosition(textArea.TextView), out visualColumn, out isAtEndOfLine);
} }
int GetOffsetFromMousePosition(Point positionRelativeToTextView, out int visualColumn) int GetOffsetFromMousePosition(Point positionRelativeToTextView, out int visualColumn, out bool isAtEndOfLine)
{ {
visualColumn = 0; visualColumn = 0;
TextView textView = textArea.TextView; TextView textView = textArea.TextView;
@ -507,9 +510,10 @@ namespace ICSharpCode.AvalonEdit.Editing
pos.Y = textView.DocumentHeight - ExtensionMethods.Epsilon; pos.Y = textView.DocumentHeight - ExtensionMethods.Epsilon;
VisualLine line = textView.GetVisualLineFromVisualTop(pos.Y); VisualLine line = textView.GetVisualLineFromVisualTop(pos.Y);
if (line != null) { if (line != null) {
visualColumn = line.GetVisualColumn(pos, textArea.Selection.EnableVirtualSpace); visualColumn = line.GetVisualColumn(pos, textArea.Selection.EnableVirtualSpace, out isAtEndOfLine);
return line.GetRelativeOffset(visualColumn) + line.FirstDocumentLine.Offset; return line.GetRelativeOffset(visualColumn) + line.FirstDocumentLine.Offset;
} }
isAtEndOfLine = false;
return -1; return -1;
} }
@ -568,16 +572,19 @@ namespace ICSharpCode.AvalonEdit.Editing
void SetCaretOffsetToMousePosition(MouseEventArgs e, ISegment allowedSegment) void SetCaretOffsetToMousePosition(MouseEventArgs e, ISegment allowedSegment)
{ {
int visualColumn; int visualColumn;
bool isAtEndOfLine;
int offset; int offset;
if (mode == SelectionMode.Rectangular) if (mode == SelectionMode.Rectangular) {
offset = GetOffsetFromMousePositionFirstTextLineOnly(e.GetPosition(textArea.TextView), out visualColumn); offset = GetOffsetFromMousePositionFirstTextLineOnly(e.GetPosition(textArea.TextView), out visualColumn);
else isAtEndOfLine = true;
offset = GetOffsetFromMousePosition(e, out visualColumn); } else {
offset = GetOffsetFromMousePosition(e, out visualColumn, out isAtEndOfLine);
}
if (allowedSegment != null) { if (allowedSegment != null) {
offset = offset.CoerceValue(allowedSegment.Offset, allowedSegment.EndOffset); offset = offset.CoerceValue(allowedSegment.Offset, allowedSegment.EndOffset);
} }
if (offset >= 0) { if (offset >= 0) {
textArea.Caret.Position = new TextViewPosition(textArea.Document.GetLocation(offset), visualColumn); textArea.Caret.Position = new TextViewPosition(textArea.Document.GetLocation(offset), visualColumn) { IsAtEndOfLine = isAtEndOfLine };
textArea.Caret.DesiredXPos = double.NaN; textArea.Caret.DesiredXPos = double.NaN;
} }
} }

12
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs

@ -84,11 +84,13 @@ namespace ICSharpCode.AvalonEdit.Editing
{ {
if (e == null) if (e == null)
throw new ArgumentNullException("e"); throw new ArgumentNullException("e");
return Selection.Create( TextViewPosition newStart = start;
textArea, TextViewPosition newEnd = end;
new TextViewPosition(textArea.Document.GetLocation(e.GetNewOffset(startOffset, AnchorMovementType.Default)), start.VisualColumn), // by changing the existing TextViewPosition, we preserve the VisualColumn (though it might become invalid)
new TextViewPosition(textArea.Document.GetLocation(e.GetNewOffset(endOffset, AnchorMovementType.Default)), end.VisualColumn) // and the IsAtEndOfLine property.
); newStart.Location = textArea.Document.GetLocation(e.GetNewOffset(startOffset, AnchorMovementType.Default));
newEnd.Location = textArea.Document.GetLocation(e.GetNewOffset(endOffset, AnchorMovementType.Default));
return Selection.Create(textArea, newStart, newEnd);
} }
/// <inheritdoc/> /// <inheritdoc/>

4
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/BackgroundGeometryBuilder.cs

@ -125,8 +125,8 @@ namespace ICSharpCode.AvalonEdit.Rendering
start = new TextViewPosition(textView.Document.GetLocation(sel.StartOffset), sel.StartVisualColumn); start = new TextViewPosition(textView.Document.GetLocation(sel.StartOffset), sel.StartVisualColumn);
end = new TextViewPosition(textView.Document.GetLocation(sel.EndOffset), sel.EndVisualColumn); end = new TextViewPosition(textView.Document.GetLocation(sel.EndOffset), sel.EndVisualColumn);
} else { } else {
start = new TextViewPosition(textView.Document.GetLocation(segmentStart), -1); start = new TextViewPosition(textView.Document.GetLocation(segmentStart));
end = new TextViewPosition(textView.Document.GetLocation(segmentEnd), -1); end = new TextViewPosition(textView.Document.GetLocation(segmentEnd));
} }
foreach (VisualLine vl in textView.VisualLines) { foreach (VisualLine vl in textView.VisualLines) {

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

@ -1757,9 +1757,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
VisualLine line = GetVisualLineFromVisualTop(visualPosition.Y); VisualLine line = GetVisualLineFromVisualTop(visualPosition.Y);
if (line == null) if (line == null)
return null; return null;
int visualColumn = line.GetVisualColumn(visualPosition); return line.GetTextViewPosition(visualPosition, Options.EnableVirtualSpace);
int documentOffset = line.GetRelativeOffset(visualColumn) + line.FirstDocumentLine.Offset;
return new TextViewPosition(document.GetLocation(documentOffset), visualColumn);
} }
/// <summary> /// <summary>
@ -1777,9 +1775,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
VisualLine line = GetVisualLineFromVisualTop(visualPosition.Y); VisualLine line = GetVisualLineFromVisualTop(visualPosition.Y);
if (line == null) if (line == null)
return null; return null;
int visualColumn = line.GetVisualColumnFloor(visualPosition); return line.GetTextViewPositionFloor(visualPosition, Options.EnableVirtualSpace);
int documentOffset = line.GetRelativeOffset(visualColumn) + line.FirstDocumentLine.Offset;
return new TextViewPosition(document.GetLocation(documentOffset), visualColumn);
} }
#endregion #endregion

61
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs

@ -307,13 +307,21 @@ namespace ICSharpCode.AvalonEdit.Rendering
/// Gets the text line containing the specified visual column. /// Gets the text line containing the specified visual column.
/// </summary> /// </summary>
public TextLine GetTextLine(int visualColumn) public TextLine GetTextLine(int visualColumn)
{
return GetTextLine(visualColumn, false);
}
/// <summary>
/// Gets the text line containing the specified visual column.
/// </summary>
public TextLine GetTextLine(int visualColumn, bool isAtEndOfLine)
{ {
if (visualColumn < 0) if (visualColumn < 0)
throw new ArgumentOutOfRangeException("visualColumn"); throw new ArgumentOutOfRangeException("visualColumn");
if (visualColumn >= VisualLengthWithEndOfLineMarker) if (visualColumn >= VisualLengthWithEndOfLineMarker)
return TextLines[TextLines.Count - 1]; return TextLines[TextLines.Count - 1];
foreach (TextLine line in TextLines) { foreach (TextLine line in TextLines) {
if (visualColumn < line.Length) if (isAtEndOfLine ? visualColumn <= line.Length : visualColumn < line.Length)
return line; return line;
else else
visualColumn -= line.Length; visualColumn -= line.Length;
@ -437,6 +445,14 @@ namespace ICSharpCode.AvalonEdit.Rendering
return GetVisualColumn(GetTextLineByVisualYPosition(point.Y), point.X, allowVirtualSpace); return GetVisualColumn(GetTextLineByVisualYPosition(point.Y), point.X, allowVirtualSpace);
} }
internal int GetVisualColumn(Point point, bool allowVirtualSpace, out bool isAtEndOfLine)
{
var textLine = GetTextLineByVisualYPosition(point.Y);
int vc = GetVisualColumn(textLine, point.X, allowVirtualSpace);
isAtEndOfLine = (vc >= GetTextLineVisualStartColumn(textLine) + textLine.Length);
return vc;
}
/// <summary> /// <summary>
/// Gets the visual column from a document position (relative to top left of the document). /// Gets the visual column from a document position (relative to top left of the document).
/// If the user clicks between two visual columns, rounds to the nearest column. /// If the user clicks between two visual columns, rounds to the nearest column.
@ -497,9 +513,16 @@ namespace ICSharpCode.AvalonEdit.Rendering
/// If the user clicks between two visual columns, returns the first of those columns. /// If the user clicks between two visual columns, returns the first of those columns.
/// </summary> /// </summary>
public int GetVisualColumnFloor(Point point, bool allowVirtualSpace) public int GetVisualColumnFloor(Point point, bool allowVirtualSpace)
{
bool tmp;
return GetVisualColumnFloor(point, allowVirtualSpace, out tmp);
}
internal int GetVisualColumnFloor(Point point, bool allowVirtualSpace, out bool isAtEndOfLine)
{ {
TextLine textLine = GetTextLineByVisualYPosition(point.Y); TextLine textLine = GetTextLineByVisualYPosition(point.Y);
if (point.X > textLine.WidthIncludingTrailingWhitespace) { if (point.X > textLine.WidthIncludingTrailingWhitespace) {
isAtEndOfLine = true;
if (allowVirtualSpace && textLine == TextLines[TextLines.Count - 1]) { if (allowVirtualSpace && textLine == TextLines[TextLines.Count - 1]) {
// clicking virtual space in the last line // clicking virtual space in the last line
int virtualX = (int)((point.X - textLine.WidthIncludingTrailingWhitespace) / textView.WideSpaceWidth); int virtualX = (int)((point.X - textLine.WidthIncludingTrailingWhitespace) / textView.WideSpaceWidth);
@ -510,11 +533,47 @@ namespace ICSharpCode.AvalonEdit.Rendering
// specially and return the line's end column instead. // specially and return the line's end column instead.
return GetTextLineVisualStartColumn(textLine) + textLine.Length; return GetTextLineVisualStartColumn(textLine) + textLine.Length;
} }
} else {
isAtEndOfLine = false;
} }
CharacterHit ch = textLine.GetCharacterHitFromDistance(point.X); CharacterHit ch = textLine.GetCharacterHitFromDistance(point.X);
return ch.FirstCharacterIndex; return ch.FirstCharacterIndex;
} }
/// <summary>
/// Gets the text view position from the specified visual position.
/// If the position is within a character, it is rounded to the next character boundary.
/// </summary>
/// <param name="visualPosition">The position in WPF device-independent pixels relative
/// to the top left corner of the document.</param>
/// <param name="allowVirtualSpace">Controls whether positions in virtual space may be returned.</param>
public TextViewPosition GetTextViewPosition(Point visualPosition, bool allowVirtualSpace)
{
bool isAtEndOfLine;
int visualColumn = GetVisualColumn(visualPosition, allowVirtualSpace, out isAtEndOfLine);
int documentOffset = GetRelativeOffset(visualColumn) + this.FirstDocumentLine.Offset;
TextViewPosition pos = new TextViewPosition(this.Document.GetLocation(documentOffset), visualColumn);
pos.IsAtEndOfLine = isAtEndOfLine;
return pos;
}
/// <summary>
/// Gets the text view position from the specified visual position.
/// If the position is inside a character, the position in front of the character is returned.
/// </summary>
/// <param name="visualPosition">The position in WPF device-independent pixels relative
/// to the top left corner of the document.</param>
/// <param name="allowVirtualSpace">Controls whether positions in virtual space may be returned.</param>
public TextViewPosition GetTextViewPositionFloor(Point visualPosition, bool allowVirtualSpace)
{
bool isAtEndOfLine;
int visualColumn = GetVisualColumnFloor(visualPosition, allowVirtualSpace, out isAtEndOfLine);
int documentOffset = GetRelativeOffset(visualColumn) + this.FirstDocumentLine.Offset;
TextViewPosition pos = new TextViewPosition(this.Document.GetLocation(documentOffset), visualColumn);
pos.IsAtEndOfLine = isAtEndOfLine;
return pos;
}
/// <summary> /// <summary>
/// Gets whether the visual line was disposed. /// Gets whether the visual line was disposed.
/// </summary> /// </summary>

22
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/TextViewPosition.cs

@ -13,6 +13,7 @@ namespace ICSharpCode.AvalonEdit
public struct TextViewPosition : IEquatable<TextViewPosition> public struct TextViewPosition : IEquatable<TextViewPosition>
{ {
int line, column, visualColumn; int line, column, visualColumn;
bool isAtEndOfLine;
/// <summary> /// <summary>
/// Gets/Sets Location. /// Gets/Sets Location.
@ -52,6 +53,21 @@ namespace ICSharpCode.AvalonEdit
set { visualColumn = value; } set { visualColumn = value; }
} }
/// <summary>
/// When word-wrap is enabled and a line is wrapped at a position where there is no space character;
/// then both the end of the first TextLine and the beginning of the second TextLine
/// refer to the same position in the document, and also have the same visual column.
/// In this case, the IsAtEndOfLine property is used to distinguish between the two cases:
/// the value <c>true</c> indicates that the position refers to the end of the previous TextLine;
/// the value <c>false</c> indicates that the position refers to the beginning of the next TextLine.
///
/// If this position is not at such a wrapping position, the value of this property has no effect.
/// </summary>
public bool IsAtEndOfLine {
get { return isAtEndOfLine; }
set { isAtEndOfLine = value; }
}
/// <summary> /// <summary>
/// Creates a new TextViewPosition instance. /// Creates a new TextViewPosition instance.
/// </summary> /// </summary>
@ -60,6 +76,7 @@ namespace ICSharpCode.AvalonEdit
this.line = line; this.line = line;
this.column = column; this.column = column;
this.visualColumn = visualColumn; this.visualColumn = visualColumn;
this.isAtEndOfLine = false;
} }
/// <summary> /// <summary>
@ -78,6 +95,7 @@ namespace ICSharpCode.AvalonEdit
this.line = location.Line; this.line = location.Line;
this.column = location.Column; this.column = location.Column;
this.visualColumn = visualColumn; this.visualColumn = visualColumn;
this.isAtEndOfLine = false;
} }
/// <summary> /// <summary>
@ -92,8 +110,8 @@ namespace ICSharpCode.AvalonEdit
public override string ToString() public override string ToString()
{ {
return string.Format(CultureInfo.InvariantCulture, return string.Format(CultureInfo.InvariantCulture,
"[TextViewPosition Line={0} Column={1} VisualColumn={2}]", "[TextViewPosition Line={0} Column={1} VisualColumn={2} IsAtEndOfLine={3}]",
this.line, this.column, this.visualColumn); this.line, this.column, this.visualColumn, this.isAtEndOfLine);
} }
/// <summary> /// <summary>

Loading…
Cancel
Save