public GetTextLineVisualStartColumn ( System.Windows.Media.TextFormatting.TextLine textLine ) : int | ||
textLine | System.Windows.Media.TextFormatting.TextLine | |
return | int |
static IEnumerable<Rect> ProcessTextLines(TextView textView, VisualLine visualLine, int segmentStartVC, int segmentEndVC) { TextLine lastTextLine = visualLine.TextLines.Last(); Vector scrollOffset = textView.ScrollOffset; for (int i = 0; i < visualLine.TextLines.Count; i++) { TextLine line = visualLine.TextLines[i]; double y = visualLine.GetTextLineVisualYPosition(line, VisualYPosition.LineTop); int visualStartCol = visualLine.GetTextLineVisualStartColumn(line); int visualEndCol = visualStartCol + line.Length; if (line != lastTextLine) visualEndCol -= line.TrailingWhitespaceLength; if (segmentEndVC < visualStartCol) break; if (lastTextLine != line && segmentStartVC > visualEndCol) continue; int segmentStartVCInLine = Math.Max(segmentStartVC, visualStartCol); int segmentEndVCInLine = Math.Min(segmentEndVC, visualEndCol); y -= scrollOffset.Y; if (segmentStartVCInLine == segmentEndVCInLine) { // GetTextBounds crashes for length=0, so we'll handle this case with GetDistanceFromCharacterHit // We need to return a rectangle to ensure empty lines are still visible double pos = visualLine.GetTextLineVisualXPosition(line, segmentStartVCInLine); pos -= scrollOffset.X; // The following special cases are necessary to get rid of empty rectangles at the end of a TextLine if "Show Spaces" is active. // If not excluded once, the same rectangle is calculated (and added) twice (since the offset could be mapped to two visual positions; end/start of line), if there is no trailing whitespace. // Skip this TextLine segment, if it is at the end of this line and this line is not the last line of the VisualLine and the selection continues and there is no trailing whitespace. if (segmentEndVCInLine == visualEndCol && i < visualLine.TextLines.Count - 1 && segmentEndVC > segmentEndVCInLine && line.TrailingWhitespaceLength == 0) continue; if (segmentStartVCInLine == visualStartCol && i > 0 && segmentStartVC < segmentStartVCInLine && visualLine.TextLines[i - 1].TrailingWhitespaceLength == 0) continue; yield return new Rect(pos, y, 1, line.Height); } else { Rect lastRect = Rect.Empty; if (segmentStartVCInLine <= visualEndCol) { foreach (TextBounds b in line.GetTextBounds(segmentStartVCInLine, segmentEndVCInLine - segmentStartVCInLine)) { double left = b.Rectangle.Left - scrollOffset.X; double right = b.Rectangle.Right - scrollOffset.X; if (!lastRect.IsEmpty) yield return lastRect; // left>right is possible in RTL languages lastRect = new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height); } } if (segmentEndVC >= visualLine.VisualLengthWithEndOfLineMarker) { double left = (segmentStartVC > visualLine.VisualLengthWithEndOfLineMarker ? visualLine.GetTextLineVisualXPosition(lastTextLine, segmentStartVC) : line.Width) - scrollOffset.X; double right = ((segmentEndVC == int.MaxValue || line != lastTextLine) ? Math.Max(((IScrollInfo)textView).ExtentWidth, ((IScrollInfo)textView).ViewportWidth) : visualLine.GetTextLineVisualXPosition(lastTextLine, segmentEndVC)) - scrollOffset.X; Rect extendSelection = new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height); if (!lastRect.IsEmpty) { if (extendSelection.IntersectsWith(lastRect)) { lastRect.Union(extendSelection); yield return lastRect; } else { yield return lastRect; yield return extendSelection; } } else yield return extendSelection; } else yield return lastRect; } } }
static void SetCaretPosition(TextArea textArea, VisualLine targetVisualLine, TextLine targetLine, CharacterHit ch, bool allowWrapToNextLine) { int newVisualColumn = ch.FirstCharacterIndex + ch.TrailingLength; int targetLineStartCol = targetVisualLine.GetTextLineVisualStartColumn(targetLine); if (!allowWrapToNextLine && newVisualColumn >= targetLineStartCol + targetLine.Length) newVisualColumn = targetLineStartCol + targetLine.Length - 1; int newOffset = targetVisualLine.GetRelativeOffset(newVisualColumn) + targetVisualLine.FirstDocumentLine.Offset; SetCaretPosition(textArea, newVisualColumn, newOffset); }
static IEnumerable <Rect> ProcessTextLines(TextView textView, VisualLine visualLine, int segmentStartVC, int segmentEndVC) { TextLine lastTextLine = visualLine.TextLines.Last(); Vector scrollOffset = textView.ScrollOffset; for (int i = 0; i < visualLine.TextLines.Count; i++) { TextLine line = visualLine.TextLines[i]; double y = visualLine.GetTextLineVisualYPosition(line, VisualYPosition.LineTop); int visualStartCol = visualLine.GetTextLineVisualStartColumn(line); int visualEndCol = visualStartCol + line.Length; if (line != lastTextLine) { visualEndCol -= line.TrailingWhitespaceLength; } if (segmentEndVC < visualStartCol) { break; } if (lastTextLine != line && segmentStartVC > visualEndCol) { continue; } int segmentStartVCInLine = Math.Max(segmentStartVC, visualStartCol); int segmentEndVCInLine = Math.Min(segmentEndVC, visualEndCol); y -= scrollOffset.Y; if (segmentStartVCInLine == segmentEndVCInLine) { // GetTextBounds crashes for length=0, so we'll handle this case with GetDistanceFromCharacterHit // We need to return a rectangle to ensure empty lines are still visible double pos = visualLine.GetTextLineVisualXPosition(line, segmentStartVCInLine); pos -= scrollOffset.X; // The following special cases are necessary to get rid of empty rectangles at the end of a TextLine if "Show Spaces" is active. // If not excluded once, the same rectangle is calculated (and added) twice (since the offset could be mapped to two visual positions; end/start of line), if there is no trailing whitespace. // Skip this TextLine segment, if it is at the end of this line and this line is not the last line of the VisualLine and the selection continues and there is no trailing whitespace. if (segmentEndVCInLine == visualEndCol && i < visualLine.TextLines.Count - 1 && segmentEndVC > segmentEndVCInLine && line.TrailingWhitespaceLength == 0) { continue; } if (segmentStartVCInLine == visualStartCol && i > 0 && segmentStartVC < segmentStartVCInLine && visualLine.TextLines[i - 1].TrailingWhitespaceLength == 0) { continue; } yield return(new Rect(pos, y, textView.EmptyLineSelectionWidth, line.Height)); } else { Rect lastRect = Rect.Empty; if (segmentStartVCInLine <= visualEndCol) { foreach (TextBounds b in line.GetTextBounds(segmentStartVCInLine, segmentEndVCInLine - segmentStartVCInLine)) { double left = b.Rectangle.Left - scrollOffset.X; double right = b.Rectangle.Right - scrollOffset.X; if (!lastRect.IsEmpty) { yield return(lastRect); } // left>right is possible in RTL languages lastRect = new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height); } } if (segmentEndVC >= visualLine.VisualLengthWithEndOfLineMarker) { double left = (segmentStartVC > visualLine.VisualLengthWithEndOfLineMarker ? visualLine.GetTextLineVisualXPosition(lastTextLine, segmentStartVC) : line.WidthIncludingTrailingWhitespace) - scrollOffset.X; double right = ((segmentEndVC == int.MaxValue || line != lastTextLine) ? Math.Max(((IScrollInfo)textView).ExtentWidth, ((IScrollInfo)textView).ViewportWidth) : visualLine.GetTextLineVisualXPosition(lastTextLine, segmentEndVC)) - scrollOffset.X; Rect extendSelection = new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height); if (!lastRect.IsEmpty) { if (extendSelection.IntersectsWith(lastRect)) { lastRect.Union(extendSelection); yield return(lastRect); } else { yield return(lastRect); yield return(extendSelection); } } else { yield return(extendSelection); } } else { yield return(lastRect); } } } }
static IEnumerable <Rect> ProcessTextLines(TextView textView, VisualLine visualLine, int segmentStartVC, int segmentEndVC) { TextLine lastTextLine = visualLine.TextLines.Last(); Vector scrollOffset = textView.ScrollOffset; for (int i = 0; i < visualLine.TextLines.Count; i++) { TextLine line = visualLine.TextLines[i]; double y = visualLine.GetTextLineVisualYPosition(line, VisualYPosition.LineTop); int visualStartCol = visualLine.GetTextLineVisualStartColumn(line); int visualEndCol = visualStartCol + line.Length; if (line == lastTextLine) { visualEndCol -= 1; // 1 position for the TextEndOfParagraph } else { visualEndCol -= line.TrailingWhitespaceLength; } if (segmentEndVC < visualStartCol) { break; } if (lastTextLine != line && segmentStartVC > visualEndCol) { continue; } int segmentStartVCInLine = Math.Max(segmentStartVC, visualStartCol); int segmentEndVCInLine = Math.Min(segmentEndVC, visualEndCol); y -= scrollOffset.Y; Rect lastRect = Rect.Empty; if (segmentStartVCInLine == segmentEndVCInLine) { // GetTextBounds crashes for length=0, so we'll handle this case with GetDistanceFromCharacterHit // We need to return a rectangle to ensure empty lines are still visible double pos = visualLine.GetTextLineVisualXPosition(line, segmentStartVCInLine); pos -= scrollOffset.X; // The following special cases are necessary to get rid of empty rectangles at the end of a TextLine if "Show Spaces" is active. // If not excluded once, the same rectangle is calculated (and added) twice (since the offset could be mapped to two visual positions; end/start of line), if there is no trailing whitespace. // Skip this TextLine segment, if it is at the end of this line and this line is not the last line of the VisualLine and the selection continues and there is no trailing whitespace. if (segmentEndVCInLine == visualEndCol && i < visualLine.TextLines.Count - 1 && segmentEndVC > segmentEndVCInLine && line.TrailingWhitespaceLength == 0) { continue; } if (segmentStartVCInLine == visualStartCol && i > 0 && segmentStartVC < segmentStartVCInLine && visualLine.TextLines[i - 1].TrailingWhitespaceLength == 0) { continue; } lastRect = new Rect(pos, y, textView.EmptyLineSelectionWidth, line.Height); } else { if (segmentStartVCInLine <= visualEndCol) { foreach (TextBounds b in line.GetTextBounds(segmentStartVCInLine, segmentEndVCInLine - segmentStartVCInLine)) { double left = b.Rectangle.Left - scrollOffset.X; double right = b.Rectangle.Right - scrollOffset.X; if (!lastRect.IsEmpty) { yield return(lastRect); } // left>right is possible in RTL languages lastRect = new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height); } } } // If the segment ends in virtual space, extend the last rectangle with the rectangle the portion of the selection // after the line end. // Also, when word-wrap is enabled and the segment continues into the next line, extend lastRect up to the end of the line. if (segmentEndVC > visualEndCol) { double left, right; if (segmentStartVC > visualLine.VisualLengthWithEndOfLineMarker) { // segmentStartVC is in virtual space left = visualLine.GetTextLineVisualXPosition(lastTextLine, segmentStartVC); } else { // Otherwise, we already processed the rects from segmentStartVC up to visualEndCol, // so we only need to do the remainder starting at visualEndCol. // For word-wrapped lines, visualEndCol doesn't include the whitespace hidden by the wrap, // so we'll need to include it here. // For the last line, visualEndCol already includes the whitespace. left = (line == lastTextLine ? line.WidthIncludingTrailingWhitespace : line.Width); } if (line != lastTextLine || segmentEndVC == int.MaxValue) { // If word-wrap is enabled and the segment continues into the next line, // or if the extendToFullWidthAtLineEnd option is used (segmentEndVC == int.MaxValue), // we select the full width of the viewport. right = Math.Max(((IScrollInfo)textView).ExtentWidth, ((IScrollInfo)textView).ViewportWidth); } else { right = visualLine.GetTextLineVisualXPosition(lastTextLine, segmentEndVC); } Rect extendSelection = new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height); if (!lastRect.IsEmpty) { if (extendSelection.IntersectsWith(lastRect)) { lastRect.Union(extendSelection); yield return(lastRect); } else { // If the end of the line is in an RTL segment, keep lastRect and extendSelection separate. yield return(lastRect); yield return(extendSelection); } } else { yield return(extendSelection); } } else { yield return(lastRect); } } }
private static void SetCaretPosition(TextArea textArea, VisualLine targetVisualLine, TextLine targetLine, int newVisualColumn, bool allowWrapToNextLine) { int targetLineStartCol = targetVisualLine.GetTextLineVisualStartColumn(targetLine); if (!allowWrapToNextLine && newVisualColumn >= targetLineStartCol + targetLine.Length) { if (newVisualColumn <= targetVisualLine.VisualLength) newVisualColumn = targetLineStartCol + targetLine.Length - 1; } int newOffset = targetVisualLine.GetRelativeOffset(newVisualColumn) + targetVisualLine.FirstDocumentLine.Offset; SetCaretPosition(textArea, newVisualColumn, newOffset); }
static TextViewPosition GetEndOfLineCaretPosition(VisualLine visualLine, TextLine textLine) { int newVC = visualLine.GetTextLineVisualStartColumn(textLine) + textLine.Length - textLine.TrailingWhitespaceLength; TextViewPosition pos = visualLine.GetTextViewPosition(newVC); pos.IsAtEndOfLine = true; return pos; }
static TextViewPosition GetStartOfLineCaretPosition(int oldVC, VisualLine visualLine, TextLine textLine, bool enableVirtualSpace) { int newVC = visualLine.GetTextLineVisualStartColumn(textLine); if (newVC == 0) newVC = visualLine.GetNextCaretPosition(newVC - 1, LogicalDirection.Forward, CaretPositioningMode.WordStart, enableVirtualSpace); if (newVC < 0) throw ThrowUtil.NoValidCaretPosition(); // when the caret is already at the start of the text, jump to start before whitespace if (newVC == oldVC) newVC = 0; return visualLine.GetTextViewPosition(newVC); }
static IEnumerable<Rect> ProcessTextLines(TextView textView, VisualLine visualLine, int segmentStartVC, int segmentEndVC) { TextLine lastTextLine = visualLine.TextLines.Last(); Vector scrollOffset = textView.ScrollOffset; for (int i = 0; i < visualLine.TextLines.Count; i++) { TextLine line = visualLine.TextLines[i]; double y = visualLine.GetTextLineVisualYPosition(line, VisualYPosition.LineTop); int visualStartCol = visualLine.GetTextLineVisualStartColumn(line); int visualEndCol = visualStartCol + line.Length; if (line == lastTextLine) visualEndCol -= 1; // 1 position for the TextEndOfParagraph else visualEndCol -= line.TrailingWhitespaceLength; if (segmentEndVC < visualStartCol) break; if (lastTextLine != line && segmentStartVC > visualEndCol) continue; int segmentStartVCInLine = Math.Max(segmentStartVC, visualStartCol); int segmentEndVCInLine = Math.Min(segmentEndVC, visualEndCol); y -= scrollOffset.Y; Rect lastRect = Rect.Empty; if (segmentStartVCInLine == segmentEndVCInLine) { // GetTextBounds crashes for length=0, so we'll handle this case with GetDistanceFromCharacterHit // We need to return a rectangle to ensure empty lines are still visible double pos = visualLine.GetTextLineVisualXPosition(line, segmentStartVCInLine); pos -= scrollOffset.X; // The following special cases are necessary to get rid of empty rectangles at the end of a TextLine if "Show Spaces" is active. // If not excluded once, the same rectangle is calculated (and added) twice (since the offset could be mapped to two visual positions; end/start of line), if there is no trailing whitespace. // Skip this TextLine segment, if it is at the end of this line and this line is not the last line of the VisualLine and the selection continues and there is no trailing whitespace. if (segmentEndVCInLine == visualEndCol && i < visualLine.TextLines.Count - 1 && segmentEndVC > segmentEndVCInLine && line.TrailingWhitespaceLength == 0) continue; if (segmentStartVCInLine == visualStartCol && i > 0 && segmentStartVC < segmentStartVCInLine && visualLine.TextLines[i - 1].TrailingWhitespaceLength == 0) continue; lastRect = new Rect(pos, y, textView.EmptyLineSelectionWidth, line.Height); } else { if (segmentStartVCInLine <= visualEndCol) { foreach (TextBounds b in line.GetTextBounds(segmentStartVCInLine, segmentEndVCInLine - segmentStartVCInLine)) { double left = b.Rectangle.Left - scrollOffset.X; double right = b.Rectangle.Right - scrollOffset.X; if (!lastRect.IsEmpty) yield return lastRect; // left>right is possible in RTL languages lastRect = new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height); } } } // If the segment ends in virtual space, extend the last rectangle with the rectangle the portion of the selection // after the line end. // Also, when word-wrap is enabled and the segment continues into the next line, extend lastRect up to the end of the line. if (segmentEndVC > visualEndCol) { double left, right; if (segmentStartVC > visualLine.VisualLengthWithEndOfLineMarker) { // segmentStartVC is in virtual space left = visualLine.GetTextLineVisualXPosition(lastTextLine, segmentStartVC); } else { // Otherwise, we already processed the rects from segmentStartVC up to visualEndCol, // so we only need to do the remainder starting at visualEndCol. // For word-wrapped lines, visualEndCol doesn't include the whitespace hidden by the wrap, // so we'll need to include it here. // For the last line, visualEndCol already includes the whitespace. left = (line == lastTextLine ? line.WidthIncludingTrailingWhitespace : line.Width); } if (line != lastTextLine || segmentEndVC == int.MaxValue) { // If word-wrap is enabled and the segment continues into the next line, // or if the extendToFullWidthAtLineEnd option is used (segmentEndVC == int.MaxValue), // we select the full width of the viewport. right = Math.Max(((IScrollInfo)textView).ExtentWidth, ((IScrollInfo)textView).ViewportWidth); } else { right = visualLine.GetTextLineVisualXPosition(lastTextLine, segmentEndVC); } Rect extendSelection = new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height); if (!lastRect.IsEmpty) { if (extendSelection.IntersectsWith(lastRect)) { lastRect.Union(extendSelection); yield return lastRect; } else { // If the end of the line is in an RTL segment, keep lastRect and extendSelection separate. yield return lastRect; yield return extendSelection; } } else yield return extendSelection; } else yield return lastRect; } }
static void MoveCaretToEndOfLine(TextArea textArea, VisualLine visualLine, TextLine textLine) { int newVC = visualLine.GetTextLineVisualStartColumn(textLine) + textLine.Length - textLine.TrailingWhitespaceLength; int offset = visualLine.FirstDocumentLine.Offset + visualLine.GetRelativeOffset(newVC); SetCaretPosition(textArea, newVC, offset, isAtEndOfLine: true); }
static void MoveCaretToStartOfLine(TextArea textArea, VisualLine visualLine, TextLine textLine) { int newVC = visualLine.GetTextLineVisualStartColumn(textLine); if (newVC == 0) newVC = visualLine.GetNextCaretPosition(newVC - 1, LogicalDirection.Forward, CaretPositioningMode.WordStart, textArea.Selection.EnableVirtualSpace); if (newVC < 0) throw ThrowUtil.NoValidCaretPosition(); // when the caret is already at the start of the text, jump to start before whitespace if (newVC == textArea.Caret.VisualColumn) newVC = 0; int offset = visualLine.FirstDocumentLine.Offset + visualLine.GetRelativeOffset(newVC); SetCaretPosition(textArea, newVC, offset); }