private void UpdateVisualInformationLine(int lineIndex, ITextSegmentVisual textSegment, int charDiff, TextSegmentVisualInfos infos) { var bounds = infos.GetSize(0); this.UpdateLineOverflow(textSegment, bounds.Width); var a = infos.GetLineCountVisual(0); var b = this.GetVisualInformation(lineIndex); var c = b.GetLineCountVisual(0); this._visualLineCount += a - c; this._textSegmentVisualInformations[lineIndex] = infos; if (Focused == false) { if (textSegment.Index <= this.SelectionStart) { this.SelectionStart += charDiff; } } }
public int GetCharIndexFromVirtualPosition(Point p, int textColumnIndex) { var textRectangle = this.GetTextRectangle(false); float y = textRectangle.Top; var lineCount = LineCount; var lineIndex = 0; TextSegmentVisualInfos visualInfos = null; for (; lineIndex < lineCount; lineIndex++) { // First we quickly go through all the lines just to find which line/Y we are on. visualInfos = this.GetVisualInformation(lineIndex); float lineTotalheight = (visualInfos.GetLineCountVisual(textColumnIndex) * this.LineHeight); if (y + lineTotalheight <= p.Y) { // We are still not on the same line as the clicked line. // So we iterate the loop again right away. y += lineTotalheight; } else { break; } } if (lineIndex == lineCount) { return(this.TextLength); } // We are now on the same line as the supplied position. var start = -1; var end = -1; if (visualInfos.GetLineSplitIndexes(textColumnIndex) == null) { y += this.LineHeight; start = 0; end = this.GetLineLength(lineIndex); } else { var linesplits = visualInfos.GetLineSplitIndexes(textColumnIndex); // Then we go through the possible wordwrappings and find the actual line that we are on. for (var i = 0; i < linesplits.Length + 1; i++) { if (p.Y <= y + this.LineHeight) { start = i == 0 ? 0 : linesplits[i - 1]; end = i == linesplits.Length ? this.GetLineLength(lineIndex) : linesplits[i]; break; } y += this.LineHeight; } } if (end <= start || p.X <= textRectangle.Left) { // If we are outside the text document, then we just return the first index of the line. return(this.GetFirstCharIndexFromLine(lineIndex)); } // Get the width of the whole string if rendered on one line. var lineWidth = this.GetLineSize(lineIndex, 0, start, end - start, textColumnIndex).Width; var averageCharWidth = lineWidth / (double)(end - start); // Get the average width of a character in the string. // And from that, guess the correct character index of the Point. var guessedStart = Math.Min(end, (int)Math.Round((p.X - (textRectangle.Left - Padding.Left)) / averageCharWidth)); var index = Math.Min(start + guessedStart, end); // And then to finetune, we check if we are in a match, and // iterate through the string to find the position. for (; index < end && index > start;) { // We get the current line (wordwrapping accounted for), and then we get the left and right characters' half width. // From that, we can see if we are in a fitting range for if this current index is the closest one to the position. var w = this.GetLineSize(lineIndex, 0, start, index - start, textColumnIndex).Width + (textRectangle.Left); var wl = this.GetLineSize(lineIndex, 0, index - 1, 1, textColumnIndex).Width *0.67; var wr = this.GetLineSize(lineIndex, 0, index, 1, textColumnIndex).Width *0.34; if (p.X >= (w - wl) && p.X <= (w + wr)) { return(this.GetFirstCharIndexFromLine(lineIndex) + index); } //bool? incrementing = w < p.X; //if (incrementing.Value) if (w < p.X) { //if (incrementing.HasValue && incrementing.Value == false) //{ // We are in a perfect location between two characters, and no definite match is available. // Which is noticed by first being told to look at a different index for a match, and then being told to go back. // Endless loop would ensue. // So we will just return from here and take the current index as the most likely. Which is fine. // This hapens mostly if we have many different kind of characters on the same line, // which disrupts the "averageCharWidth" to an irregular decimal number. // break; //} index++; } else { //if (incrementing.HasValue && incrementing.Value) //{ // See comment above. // break; //} index--; } } return(this.GetFirstCharIndexFromLine(lineIndex) + index); }