/// <summary> /// Returns an ArrayList of rectangles (Rect) that form the bounds of the region specified between /// the start and end points /// </summary> /// <param name="cp"></param> /// int offset indicating the starting point of the region for which bounds are required /// <param name="cch"> /// Length in characters of the region for which bounds are required /// </param> /// <param name="xOffset"> /// Offset of line in x direction, to be added to line bounds to get actual rectangle for line /// </param> /// <param name="yOffset"> /// Offset of line in y direction, to be added to line bounds to get actual rectangle for line /// </param> /// <remarks> /// This function calls GetTextBounds for the line, and then checks if there are text run bounds. If they exist, /// it uses those as the bounding rectangles. If not, it returns the rectangle for the first (and only) element /// of the text bounds. /// </remarks> internal List <Rect> GetRangeBounds(int cp, int cch, double xOffset, double yOffset) { List <Rect> rectangles = new List <Rect>(); // Adjust x offset for trailing spaces double delta = CalculateXOffsetShift(); double adjustedXOffset = xOffset + delta; IList <TextBounds> textBounds; if (_line.HasOverflowed && _owner.ParagraphProperties.TextTrimming != TextTrimming.None) { // We should not shift offset in this case Invariant.Assert(DoubleUtil.AreClose(delta, 0)); System.Windows.Media.TextFormatting.TextLine line = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties)); Invariant.Assert(line.HasCollapsed, "Line has not been collapsed"); textBounds = line.GetTextBounds(cp, cch); } else { textBounds = _line.GetTextBounds(cp, cch); } Invariant.Assert(textBounds.Count > 0); for (int boundIndex = 0; boundIndex < textBounds.Count; boundIndex++) { Rect rect = textBounds[boundIndex].Rectangle; rect.X += adjustedXOffset; rect.Y += yOffset; rectangles.Add(rect); } return(rectangles); }
// ------------------------------------------------------------------ // Get length of content hidden by ellipses. // // wrappingWidth - Wrapping width for the line. // // Returns: Length of collapsed content (number of characters hidden // by ellipses). // ------------------------------------------------------------------ internal int GetEllipsesLength() { // There are no ellipses, if: // * there is no overflow in the line // * text trimming is turned off if (!_line.HasOverflowed) { return(0); } if (_owner.ParagraphProperties.TextTrimming == TextTrimming.None) { return(0); } // Create collapsed text line to get length of collapsed content. System.Windows.Media.TextFormatting.TextLine collapsedLine = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties)); Debug.Assert(collapsedLine.HasCollapsed, "Line has not been collapsed"); IList <TextCollapsedRange> collapsedRanges = collapsedLine.GetTextCollapsedRanges(); if (collapsedRanges != null) { Debug.Assert(collapsedRanges.Count == 1, "Multiple collapsed ranges are not supported."); TextCollapsedRange collapsedRange = collapsedRanges[0]; return(collapsedRange.Length); } return(0); }
/// <summary> /// Creates a new FormattedTextElement that displays the specified text /// and occupies the specified length in the document. /// </summary> public FormattedTextElement(TextLine text, int documentLength) : base(1, documentLength) { if (text == null) throw new ArgumentNullException("text"); this.textLine = text; this.BreakBefore = LineBreakCondition.BreakPossible; this.BreakAfter = LineBreakCondition.BreakPossible; }
/// <inheritdoc/> public override TextRun CreateTextRun(int startVisualColumn, ITextRunConstructionContext context) { if (textLine == null) { var formatter = TextFormatterFactory.Create(context.TextView); textLine = PrepareText(formatter, this.text, this.TextRunProperties); this.text = null; } return new FormattedTextRun(this, this.TextRunProperties); }
internal LineNumberVisual(WpfTextLine textLine) { _textLine = textLine ?? throw new ArgumentNullException(nameof(textLine)); _renderTargets = new List <Point>(); IsHitTestVisible = false; }
//------------------------------------------------------------------- // Retrieve text position index from the distance. // // distance - distance relative to the beginning of the line // // Returns: Text position index. //------------------------------------------------------------------- internal CharacterHit GetTextPositionFromDistance(double distance) { // Adjust distance to account for a line shift due to rendering of trailing spaces double delta = CalculateXOffsetShift(); if (_line.HasOverflowed && _owner.ParagraphProperties.TextTrimming != TextTrimming.None) { System.Windows.Media.TextFormatting.TextLine line = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties)); Invariant.Assert(DoubleUtil.AreClose(delta, 0)); Invariant.Assert(line.HasCollapsed, "Line has not been collapsed"); return(line.GetCharacterHitFromDistance(distance)); } return(_line.GetCharacterHitFromDistance(distance - delta)); }
// ------------------------------------------------------------------ // Render formatted line. // // ctx - Drawing context to be used for rendering. // lineOffset - Offset of the line. // wrappingWidth - Wrapping width for the line. // ------------------------------------------------------------------ internal void Render(DrawingContext ctx, Point lineOffset) { Debug.Assert(_line != null, "Rendering line that has not been measured yet."); // Handle text trimming. System.Windows.Media.TextFormatting.TextLine line = _line; if (_line.HasOverflowed && _owner.ParagraphProperties.TextTrimming != TextTrimming.None) { line = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties)); Debug.Assert(line.HasCollapsed, "Line has not been collapsed"); } double delta = CalculateXOffsetShift(); line.Draw(ctx, new Point(lineOffset.X + delta, lineOffset.Y), (_mirror ? InvertAxes.Horizontal : InvertAxes.None)); }
// ------------------------------------------------------------------ // Gets width of content, collapsed at wrappingWidth (if necessary) // // wrappingWidth - Wrapping width for the line. // // Returns: Width of content, after collapse (may be greater than wrappingWidth) // // ------------------------------------------------------------------ internal double GetCollapsedWidth() { // There are no ellipses, if: // * there is no overflow in the line // * text trimming is turned off if (!_line.HasOverflowed) { return(Width); } if (_owner.ParagraphProperties.TextTrimming == TextTrimming.None) { return(Width); } // Create collapsed text line to get length of collapsed content. System.Windows.Media.TextFormatting.TextLine collapsedLine = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties)); Debug.Assert(collapsedLine.HasCollapsed, "Line has not been collapsed"); return(collapsedLine.Width); }
//------------------------------------------------------------------- // // Protected Methods // //------------------------------------------------------------------- #region Protected Methods // ------------------------------------------------------------------ // Retrieve bounds of an object/character at specified text index. // // cp - character index of an object/character // cch - number of positions occupied by object/character // flowDirection - flow direction of object/character // // Returns: Bounds of an object/character. // ------------------------------------------------------------------ protected Rect GetBoundsFromPosition(int cp, int cch, out FlowDirection flowDirection) { Rect rect; // Adjust x offset for trailing spaces double delta = CalculateXOffsetShift(); IList <TextBounds> textBounds; if (_line.HasOverflowed && _owner.ParagraphProperties.TextTrimming != TextTrimming.None) { // We should not shift offset in this case Invariant.Assert(DoubleUtil.AreClose(delta, 0)); System.Windows.Media.TextFormatting.TextLine line = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties)); Invariant.Assert(line.HasCollapsed, "Line has not been collapsed"); textBounds = line.GetTextBounds(cp, cch); } else { textBounds = _line.GetTextBounds(cp, cch); } Invariant.Assert(textBounds != null && textBounds.Count == 1, "Expecting exactly one TextBounds for a single text position."); IList <TextRunBounds> runBounds = textBounds[0].TextRunBounds; if (runBounds != null) { Debug.Assert(runBounds.Count == 1, "Expecting exactly one TextRunBounds for a single text position."); rect = runBounds[0].Rectangle; } else { rect = textBounds[0].Rectangle; } rect.X += delta; flowDirection = textBounds[0].FlowDirection; return(rect); }
/// <summary> /// Sets the enumerator to its initial position, /// which is before the first element in the collection /// </summary> public void Reset() { _textStorePosition = 0; _lineCount = 0; _totalHeight = 0; _currentLine = null; _nextLine = null; }
private void FindSelectedArea(int idx, int txtLen, int txtOffset, double x, TextLine line, ref double start, ref double end) { int first = Math.Max(txtOffset, this.SelectionStart - idx); int last = Math.Min(txtLen - 1 + txtOffset, this.SelectionEnd - idx); if (last >= first) { start = Math.Min(start, line.GetDistanceFromCharacterHit(new CharacterHit(first, 0)) + x); end = Math.Max(end, line.GetDistanceFromCharacterHit(new CharacterHit(last, 1)) + x); } }
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; }
double GetVisualPos(VisualLine vl, TextLine tl) { double pos = vl.GetTextLineVisualYPosition(tl, VisualYPosition.LineTop) + tl.Height / 2 - TextView.VerticalOffset; return Math.Round(pos) + 0.5; }
public WpfTextViewLine(IBufferGraph bufferGraph, LinePartsCollection linePartsCollection, int linePartsIndex, int linePartsLength, int startColumn, int endColumn, ITextSnapshotLine bufferLine, SnapshotSpan span, ITextSnapshot visualSnapshot, TextLine textLine, double indentation, double virtualSpaceWidth) { if (bufferGraph == null) throw new ArgumentNullException(nameof(bufferGraph)); if (linePartsCollection == null) throw new ArgumentNullException(nameof(linePartsCollection)); if (linePartsIndex < 0) throw new ArgumentOutOfRangeException(nameof(linePartsIndex)); if (linePartsLength < 0) throw new ArgumentOutOfRangeException(nameof(linePartsLength)); if (linePartsIndex + linePartsLength > linePartsCollection.LineParts.Count) throw new ArgumentOutOfRangeException(nameof(linePartsLength)); if (bufferLine == null) throw new ArgumentNullException(nameof(bufferLine)); if (span.Snapshot != bufferLine.Snapshot) throw new ArgumentException(); if (visualSnapshot == null) throw new ArgumentNullException(nameof(visualSnapshot)); if (textLine == null) throw new ArgumentNullException(nameof(textLine)); IsValid = true; this.linePartsIndex = linePartsIndex; this.linePartsLength = linePartsLength; this.bufferGraph = bufferGraph; this.linePartsCollection = linePartsCollection; this.startColumn = startColumn; this.endColumn = endColumn; this.visualSnapshot = visualSnapshot; textLines = new ReadOnlyCollection<TextLine>(new[] { textLine }); Debug.Assert(textLines.Count == 1);// Assumed by all code accessing TextLine prop realTopSpace = 0; realBottomSpace = 0; realBaseline = TextLine.Baseline; double baseLineHeight = TextLine.TextHeight - TextLine.Baseline; var lineParts = linePartsCollection.LineParts; for (int i = 0; i < linePartsLength; i++) { var adornmentElement = lineParts[linePartsIndex + i].AdornmentElement; if (adornmentElement == null) continue; double adornmentBaseLineHeight = adornmentElement.TextHeight - adornmentElement.Baseline; if (adornmentBaseLineHeight > baseLineHeight) baseLineHeight = adornmentBaseLineHeight; if (adornmentElement.Baseline > realBaseline) realBaseline = adornmentElement.Baseline; if (adornmentElement.TopSpace > realTopSpace) realTopSpace = adornmentElement.TopSpace; if (adornmentElement.BottomSpace > realBottomSpace) realBottomSpace = adornmentElement.BottomSpace; } realTextHeight = Math.Ceiling(baseLineHeight + realBaseline); isFirstTextViewLineForSnapshotLine = span.Start == bufferLine.Start; isLastTextViewLineForSnapshotLine = span.End == bufferLine.EndIncludingLineBreak; IsLastVisualLine = bufferLine.LineNumber + 1 == bufferLine.Snapshot.LineCount && IsLastTextViewLineForSnapshotLine; lineBreakLength = isLastTextViewLineForSnapshotLine ? bufferLine.LineBreakLength : 0; this.virtualSpaceWidth = virtualSpaceWidth; textLeft = indentation; textWidth = TextLine.WidthIncludingTrailingWhitespace; extentIncludingLineBreak = span; endOfLineWidth = Math.Floor(realTextHeight * 0.58333333333333337);// Same as VS width = textWidth + (lineBreakLength == 0 ? 0 : endOfLineWidth); change = TextViewLineChange.NewOrReformatted; SetLineTransform(DefaultLineTransform); }
/// <summary> /// Gets the start visual column from the specified text line. /// </summary> public int GetTextLineVisualStartColumn(TextLine textLine) { if (!TextLines.Contains(textLine)) throw new ArgumentException("textLine is not a line in this VisualLine"); int col = 0; foreach (TextLine tl in TextLines) { if (tl == textLine) break; else col += tl.Length; } return col; }
/// <summary> /// Gets the visual top from the specified text line. /// </summary> /// <returns>Distance in device-independent pixels /// from the top of the document to the top of the specified text line.</returns> public double GetTextLineVisualYPosition(TextLine textLine, VisualYPosition yPositionMode) { if (textLine == null) throw new ArgumentNullException("textLine"); double pos = VisualTop; foreach (TextLine tl in TextLines) { if (tl == textLine) { switch (yPositionMode) { case VisualYPosition.LineTop: return pos; case VisualYPosition.LineMiddle: return pos + tl.Height / 2; case VisualYPosition.LineBottom: return pos + tl.Height; case VisualYPosition.TextTop: return pos + tl.Baseline - textView.DefaultBaseline; case VisualYPosition.TextBottom: return pos + tl.Baseline - textView.DefaultBaseline + textView.DefaultLineHeight; case VisualYPosition.TextMiddle: return pos + tl.Baseline - textView.DefaultBaseline + textView.DefaultLineHeight / 2; case VisualYPosition.Baseline: return pos + tl.Baseline; default: throw new ArgumentException("Invalid yPositionMode:" + yPositionMode); } } else { pos += tl.Height; } } throw new ArgumentException("textLine is not a line in this VisualLine"); }
public int GetTextLineVisualStartColumn(TextLine textLine) { //TODO: VisualLine.GetTextLineVisualStartColumn() throw new NotImplementedException(); }
public double GetTextLineVisualTop(TextLine textLine) { //TODO: VisualLine.GetTextLineVisualTop() throw new NotImplementedException(); }
/// <summary> /// Advances the enumerator to the next text line of the collection /// </summary> /// <returns>true if the enumerator was successfully advanced to the next element; /// false if the enumerator has passed the end of the collection</returns> public bool MoveNext() { if (_currentLine == null) { // this is the first line if (_that._text.Length == 0) return false; _currentLine = FormatLine( _that._textSourceImpl, _textStorePosition, MaxLineLength(_lineCount), _that._defaultParaProps, null // no previous line break ); // check if this line fits the text height if (_totalHeight + _currentLine.Height > _that._maxTextHeight) { _currentLine.Dispose(); _currentLine = null; return false; } Debug.Assert(_nextLine == null); } else { // there is no next line or it didn't fit // either way we're finished if (_nextLine == null) return false; _totalHeight += _previousHeight; _textStorePosition += _previousLength; ++_lineCount; _currentLine = _nextLine; _nextLine = null; } TextLineBreak currentLineBreak = _currentLine.GetTextLineBreak(); // this line is guaranteed to fit the text height Debug.Assert(_totalHeight + _currentLine.Height <= _that._maxTextHeight); // now, check if the next line fits, we need to do this on this iteration // because we might need to add ellipsis to the current line // as a result of the next line measurement // maybe there is no next line at all if (_textStorePosition + _currentLine.Length < _that._text.Length) { bool nextLineFits; if (_lineCount + 1 >= _that._maxLineCount) nextLineFits = false; else { _nextLine = FormatLine( _that._textSourceImpl, _textStorePosition + _currentLine.Length, MaxLineLength(_lineCount + 1), _that._defaultParaProps, currentLineBreak ); nextLineFits = (_totalHeight + _currentLine.Height + _nextLine.Height <= _that._maxTextHeight); } if (!nextLineFits) { // next line doesn't fit if (_nextLine != null) { _nextLine.Dispose(); _nextLine = null; } if (_that._trimming != TextTrimming.None && !_currentLine.HasCollapsed) { // recreate the current line with ellipsis added // Note: Paragraph ellipsis is not supported today. We'll workaround // it here by faking a non-wrap text on finite column width. TextWrapping currentWrap = _that._defaultParaProps.TextWrapping; _that._defaultParaProps.SetTextWrapping(TextWrapping.NoWrap); if (currentLineBreak != null) currentLineBreak.Dispose(); _currentLine.Dispose(); _currentLine = FormatLine( _that._textSourceImpl, _textStorePosition, MaxLineLength(_lineCount), _that._defaultParaProps, _previousLineBreak ); currentLineBreak = _currentLine.GetTextLineBreak(); _that._defaultParaProps.SetTextWrapping(currentWrap); } } } _previousHeight = _currentLine.Height; _previousLength = _currentLine.Length; if (_previousLineBreak != null) _previousLineBreak.Dispose(); _previousLineBreak = currentLineBreak; return true; }
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); }
public void Dispose() { if (_currentLine != null) { _currentLine.Dispose(); _currentLine = null; } if (_nextLine != null) { _nextLine.Dispose(); _nextLine = null; } }
internal LineEnumerator(FormattedText text) { _previousHeight = 0; _previousLength = 0; _previousLineBreak = null; _textStorePosition = 0; _lineCount = 0; _totalHeight = 0; _currentLine = null; _nextLine = null; _formatter = TextFormatter.FromCurrentDispatcher(text._textFormattingMode); _that = text; if (_that._textSourceImpl == null) _that._textSourceImpl = new TextSourceImplementation(_that); }
private void AdvanceLineOrigin(ref Point lineOrigin, TextLine currentLine) { double height = currentLine.Height; // advance line origin according to the flow direction switch (_defaultParaProps.FlowDirection) { case FlowDirection.LeftToRight: case FlowDirection.RightToLeft: lineOrigin.Y += height; break; } }
public TabTextElement(TextLine text) : base(2, 1) { this.text = text; }
double GetVisualPos(VisualLine vl, TextLine tl, double pixelHeight) { double pos = vl.GetTextLineVisualYPosition(tl, VisualYPosition.TextMiddle) - TextView.VerticalOffset; return PixelSnapHelpers.PixelAlign(pos, pixelHeight); }
public NewLineTextElement(TextLine text) : base(text, 0) { BreakBefore = LineBreakCondition.BreakPossible; BreakAfter = LineBreakCondition.BreakRestrained; }
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); }
/// <summary> /// Gets the distance to the left border of the text area of the specified visual column. /// The visual column must belong to the specified text line. /// </summary> public double GetTextLineVisualXPosition(TextLine textLine, int visualColumn) { if (textLine == null) throw new ArgumentNullException("textLine"); double xPos = textLine.GetDistanceFromCharacterHit( new CharacterHit(Math.Min(visualColumn, VisualLengthWithEndOfLineMarker), 0)); if (visualColumn > VisualLengthWithEndOfLineMarker) { xPos += (visualColumn - VisualLengthWithEndOfLineMarker) * textView.WideSpaceWidth; } return xPos; }
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); }
/// <summary> /// 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. /// </summary> public int GetVisualColumn(TextLine textLine, double xPos, bool allowVirtualSpace) { if (xPos > textLine.WidthIncludingTrailingWhitespace) { if (allowVirtualSpace && textLine == TextLines[TextLines.Count - 1]) { int virtualX = (int)Math.Round((xPos - textLine.WidthIncludingTrailingWhitespace) / textView.WideSpaceWidth); return VisualLengthWithEndOfLineMarker + virtualX; } } CharacterHit ch = textLine.GetCharacterHitFromDistance(xPos); return ch.FirstCharacterIndex + ch.TrailingLength; }
public Line(int number, TextLine textLine, double right, double top) { if (number <= 0) throw new ArgumentOutOfRangeException(nameof(number)); if (textLine == null) throw new ArgumentNullException(nameof(textLine)); Number = number; this.textLine = textLine; this.right = right; this.top = top; }
public FoldingLineElement(FoldingSection fs, TextLine text, int documentLength) : base(text, documentLength) { this.fs = fs; }
void MakeNewText() { if (fmt == null) fmt = TextFormatterFactory.Create(this, provider); if (line != null) line.Dispose(); src.UpdateParent(this); line = fmt.FormatLine(src.Source, 0, 0, new ParaProps(this), null); }
public static void HandleLine(LinkedList <CharInfo> allCharInfos, Point linePosition, TextLine myTextLine, CustomTextSource4 customTextSource4, int runCount, int nRuns, int lineNo, int textStorePosition, List <TextRunInfo> runsInfos, LinkedListNode <CharInfo> curCharInfoNode, out LinkedListNode <CharInfo> lastCharInfoNode, RoslynCodeBase.DebugDelegate?debugFn = null, TextChange?change = null, LineInfo2?curLineInfo = null) { lastCharInfoNode = null; var curPos = linePosition; // var positions = new List<Rect>(); var indexedGlyphRuns = myTextLine.GetIndexedGlyphRuns(); var runs = customTextSource4.Runs; debugFn?.Invoke($"Runs is count is {runs.Count}", 1); var textRuns = runs.Skip(runCount).Take(nRuns).ToList(); debugFn?.Invoke($"{runCount} {nRuns} TextRuns enumerator count is {textRuns.Count}", 1); var curCi = curCharInfoNode; using (var enum1 = textRuns.GetEnumerator()) { var moveNext = enum1.MoveNext(); var lineCharIndex = 0; var xOrigin = linePosition.X; if (indexedGlyphRuns == null) { return; } foreach (var glyphRunC in indexedGlyphRuns) { var gl = glyphRunC.GlyphRun; var advanceSum = gl.AdvanceWidths.Sum(); var startCi = curCi; for (var i = 0; i < gl.Characters.Count; i++) { var i0 = gl.ClusterMap?[i] ?? i; var glAdvanceWidth = gl.AdvanceWidths[i0]; var glCharacter = gl.Characters[i]; var glCaretStop = gl.CaretStops?[i0]; if (curCi != null && curLineInfo != null) { // ReSharper disable once PossibleInvalidOperationException #pragma warning disable 8629 if (lineCharIndex + curLineInfo.Offset >= change.Value.Span.Start) #pragma warning restore 8629 { curCi.Value.Index = textStorePosition + lineCharIndex; curCi.Value.RunIndex = i; curCi.Value.Character = glCharacter; curCi.Value.AdvanceWidth = glAdvanceWidth; curCi.Value.XOrigin = xOrigin; if (Math.Abs(curCi.Value.YOrigin - linePosition.Y) > 0.5) { curCi.Value.YOrigin = linePosition.Y; } } if (curCi.Value.RunIndex != i) { curCi.Value.RunIndex = i; } curCi = curCi.Next; } else { var ci = new CharInfo(lineNo, textStorePosition + lineCharIndex, lineCharIndex, i, glCharacter, glAdvanceWidth, glCaretStop, xOrigin, linePosition.Y); allCharInfos.AddLast(ci); } lineCharIndex++; xOrigin += glAdvanceWidth; } var item = new Rect(curPos, new Size(advanceSum, myTextLine.Height)); if (!moveNext) { StringBuilder sb = new StringBuilder(); for (var c = curCharInfoNode; c != null; c = c.Next) { sb.Append(c.Value.Character); } throw new CodeControlException("enumerator empty " + sb); } var enum1Current = enum1.Current; var textRunInfo = new TextRunInfo(enum1Current, item, startCi); debugFn?.Invoke(textRunInfo.ToString(), 2); runsInfos?.Add(textRunInfo); curPos.X += advanceSum; } } #pragma warning disable 8601 lastCharInfoNode = allCharInfos.Last; #pragma warning restore 8601 }
public SpaceTextElement(TextLine textLine) : base(textLine, 1) { BreakBefore = LineBreakCondition.BreakPossible; BreakAfter = LineBreakCondition.BreakDesired; }
static TextViewPosition GetUpDownCaretPosition(TextView textView, TextViewPosition caretPosition, CaretMovementType direction, VisualLine visualLine, TextLine textLine, bool enableVirtualSpace, ref double xPos) { // moving up/down happens using the desired visual X position if (double.IsNaN(xPos)) xPos = visualLine.GetTextLineVisualXPosition(textLine, caretPosition.VisualColumn); // now find the TextLine+VisualLine where the caret will end up in VisualLine targetVisualLine = visualLine; TextLine targetLine; int textLineIndex = visualLine.TextLines.IndexOf(textLine); switch (direction) { case CaretMovementType.LineUp: { // Move up: move to the previous TextLine in the same visual line // or move to the last TextLine of the previous visual line int prevLineNumber = visualLine.FirstDocumentLine.LineNumber - 1; if (textLineIndex > 0) { targetLine = visualLine.TextLines[textLineIndex - 1]; } else if (prevLineNumber >= 1) { DocumentLine prevLine = textView.Document.GetLineByNumber(prevLineNumber); targetVisualLine = textView.GetOrConstructVisualLine(prevLine); targetLine = targetVisualLine.TextLines[targetVisualLine.TextLines.Count - 1]; } else { targetLine = null; } break; } case CaretMovementType.LineDown: { // Move down: move to the next TextLine in the same visual line // or move to the first TextLine of the next visual line int nextLineNumber = visualLine.LastDocumentLine.LineNumber + 1; if (textLineIndex < visualLine.TextLines.Count - 1) { targetLine = visualLine.TextLines[textLineIndex + 1]; } else if (nextLineNumber <= textView.Document.LineCount) { DocumentLine nextLine = textView.Document.GetLineByNumber(nextLineNumber); targetVisualLine = textView.GetOrConstructVisualLine(nextLine); targetLine = targetVisualLine.TextLines[0]; } else { targetLine = null; } break; } case CaretMovementType.PageUp: case CaretMovementType.PageDown: { // Page up/down: find the target line using its visual position double yPos = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.LineMiddle); if (direction == CaretMovementType.PageUp) yPos -= textView.RenderSize.Height; else yPos += textView.RenderSize.Height; DocumentLine newLine = textView.GetDocumentLineByVisualTop(yPos); targetVisualLine = textView.GetOrConstructVisualLine(newLine); targetLine = targetVisualLine.GetTextLineByVisualYPosition(yPos); break; } default: throw new NotSupportedException(direction.ToString()); } if (targetLine != null) { double yPos = targetVisualLine.GetTextLineVisualYPosition(targetLine, VisualYPosition.LineMiddle); int newVisualColumn = targetVisualLine.GetVisualColumn(new Point(xPos, yPos), enableVirtualSpace); // prevent wrapping to the next line; TODO: could 'IsAtEnd' help here? int targetLineStartCol = targetVisualLine.GetTextLineVisualStartColumn(targetLine); if (newVisualColumn >= targetLineStartCol + targetLine.Length) { if (newVisualColumn <= targetVisualLine.VisualLength) newVisualColumn = targetLineStartCol + targetLine.Length - 1; } return targetVisualLine.GetTextViewPosition(newVisualColumn); } else { return caretPosition; } }
public SpecialCharacterBoxElement(TextLine text) : base(text, 1) { }
static void MoveCaretUpDown(TextArea textArea, CaretMovementType direction, VisualLine visualLine, TextLine textLine, int caretVisualColumn) { // moving up/down happens using the desired visual X position double xPos = textArea.Caret.DesiredXPos; if (double.IsNaN(xPos)) xPos = textLine.GetDistanceFromCharacterHit(new CharacterHit(caretVisualColumn, 0)); // now find the TextLine+VisualLine where the caret will end up in VisualLine targetVisualLine = visualLine; TextLine targetLine; int textLineIndex = visualLine.TextLines.IndexOf(textLine); switch (direction) { case CaretMovementType.LineUp: { // Move up: move to the previous TextLine in the same visual line // or move to the last TextLine of the previous visual line int prevLineNumber = visualLine.FirstDocumentLine.LineNumber - 1; if (textLineIndex > 0) { targetLine = visualLine.TextLines[textLineIndex - 1]; } else if (prevLineNumber >= 1) { DocumentLine prevLine = textArea.Document.GetLineByNumber(prevLineNumber); targetVisualLine = textArea.TextView.GetOrConstructVisualLine(prevLine); targetLine = targetVisualLine.TextLines[targetVisualLine.TextLines.Count - 1]; } else { targetLine = null; } break; } case CaretMovementType.LineDown: { // Move down: move to the next TextLine in the same visual line // or move to the first TextLine of the next visual line int nextLineNumber = visualLine.LastDocumentLine.LineNumber + 1; if (textLineIndex < visualLine.TextLines.Count - 1) { targetLine = visualLine.TextLines[textLineIndex + 1]; } else if (nextLineNumber <= textArea.Document.LineCount) { DocumentLine nextLine = textArea.Document.GetLineByNumber(nextLineNumber); targetVisualLine = textArea.TextView.GetOrConstructVisualLine(nextLine); targetLine = targetVisualLine.TextLines[0]; } else { targetLine = null; } break; } case CaretMovementType.PageUp: case CaretMovementType.PageDown: { // Page up/down: find the target line using its visual position double yPos = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.LineMiddle); if (direction == CaretMovementType.PageUp) yPos -= textArea.TextView.RenderSize.Height; else yPos += textArea.TextView.RenderSize.Height; DocumentLine newLine = textArea.TextView.GetDocumentLineByVisualTop(yPos); targetVisualLine = textArea.TextView.GetOrConstructVisualLine(newLine); targetLine = targetVisualLine.GetTextLineByVisualYPosition(yPos); break; } default: throw new NotSupportedException(direction.ToString()); } if (targetLine != null) { CharacterHit ch = targetLine.GetCharacterHitFromDistance(xPos); SetCaretPosition(textArea, targetVisualLine, targetLine, ch, false); textArea.Caret.DesiredXPos = xPos; } }
// ------------------------------------------------------------------ // Hit tests to the correct ContentElement within the line. // // offset - offset within the line. // // Returns: ContentElement which has been hit. // ------------------------------------------------------------------ internal override IInputElement InputHitTest(double offset) { TextContainer tree; DependencyObject element; CharacterHit charHit; TextPointer position; TextPointerContext type = TextPointerContext.None; element = null; // We can only support hittesting text elements in a TextContainer. // If the TextContainer is not a TextContainer, return null which higher up the stack // will be converted into a reference to the control itself. tree = _owner.TextContainer as TextContainer; // Adjusted offset for shift due to trailing spaces rendering double delta = CalculateXOffsetShift(); if (tree != null) { if (_line.HasOverflowed && _owner.ParagraphProperties.TextTrimming != TextTrimming.None) { // We should not shift offset in this case Invariant.Assert(DoubleUtil.AreClose(delta, 0)); System.Windows.Media.TextFormatting.TextLine line = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties)); Invariant.Assert(line.HasCollapsed, "Line has not been collapsed"); // Get TextPointer from specified distance. charHit = line.GetCharacterHitFromDistance(offset); } else { charHit = _line.GetCharacterHitFromDistance(offset - delta); } position = new TextPointer(_owner.ContentStart, CalcPositionOffset(charHit), LogicalDirection.Forward); if (position != null) { if (charHit.TrailingLength == 0) { // Start of character. Look forward type = position.GetPointerContext(LogicalDirection.Forward); } else { // End of character. Look backward type = position.GetPointerContext(LogicalDirection.Backward); } // Get element only for Text & Start/End element, for all other positions // return null (it means that the line owner has been hit). if (type == TextPointerContext.Text || type == TextPointerContext.ElementEnd) { element = position.Parent as TextElement; } else if (type == TextPointerContext.ElementStart) { element = position.GetAdjacentElementFromOuterPosition(LogicalDirection.Forward); } } } return(element as IInputElement); }