//------------------------------------------------------------------- // 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)); }
/// <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; }
// ------------------------------------------------------------------ // 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); }