private void GetLspanFor(int pos, out RichTextBoxLayoutSpan lspan, out int lspanIndex, out int charIndexInLspan) { var nextLspanIndex = Enumerable.Range(0, LayoutSpans.Count).Where(x => pos < LayoutSpans[x].TextAbsPosition).FirstOrNull() ?? LayoutSpans.Count; lspanIndex = nextLspanIndex - 1; lspan = LayoutSpans[lspanIndex]; charIndexInLspan = pos - lspan.TextAbsPosition; }
private bool TryGetClosestSpanAt(Vector2 point, out RichTextBoxLayoutSpan lspan) { if (LayoutSpans.Count == 0) { lspan = default(RichTextBoxLayoutSpan); return(false); } lspan = LayoutSpans.Minimal(x => x.DistanceFrom(point)); return(true); }
private void FlushStrip(BuildingContext context, int paragraphIndex, float tabOffset, SubList <Subspan> subspans, bool isFirstStrip, bool isLastStrip) { // todo: consider direction var paragraph = context.Text.Paragraphs[paragraphIndex]; //if (!isLastStrip) // subspans = TrimEnd(subspans); var commonSize = MeasureSubspans(context, subspans); var stripSize = new Size2(context.RemainingShape.Width, commonSize.Height); if (paragraph.Style.Alignment != RtParagraphAlignment.Justify || isLastStrip) { // todo: tabs var mergedSubspans = MergeSubspans(subspans); var newRectangles = new RichTextBoxLayoutSpan[mergedSubspans.Count]; var strip = AaRectangle2.FromCornerAndDimensions( context.StripStartPoint.X, context.StripStartPoint.Y, commonSize.Width, commonSize.Height); var rectOffsetX = context.StripStartPoint.X + tabOffset; var charIndex = 0; for (var i = 0; i < mergedSubspans.Count; i++) { var subspan = mergedSubspans[i]; var subspanSize = MeasureSubspan(subspan); var charWidths = subspan.Text.Select(x => measurer.GetCharSize(x, subspan.Style).Width).ToArray(); var subspanWidthWithoutKerning = charWidths.Sum(); var kerningAdjustment = subspanSize.Width / subspanWidthWithoutKerning; var adjustedCharWidths = charWidths.Select(x => x * kerningAdjustment).ToArray(); var charOffsets = Enumerable.Range(0, subspan.Text.Length).Select(x => adjustedCharWidths.Take(x).Sum()).ToArray(); newRectangles[i] = new RichTextBoxLayoutSpan { TextRelPosition = subspan.TextRelPosition, TextAbsPosition = context.Text.GetGlobalIndex(subspan.TextRelPosition), Bounds = new AaRectangle2( new Vector2(rectOffsetX, context.StripStartPoint.Y), new Vector2(rectOffsetX + subspanSize.Width, context.StripStartPoint.Y + commonSize.Height)), Strip = strip, CharOffsets = charOffsets, Text = subspan.Text, Style = subspan.Style, Embedding = subspan.Embedding, EmbeddingHandler = subspan.EmbeddingHandler, EmbeddingImage = subspan.EmbeddingImage }; rectOffsetX += subspanSize.Width; charIndex += subspan.Text.Length; } var adjustment = 0f; switch (paragraph.Style.Alignment) { case RtParagraphAlignment.Left: break; case RtParagraphAlignment.Center: var leftCenterX = rectOffsetX / 2; var stripCenter = stripSize.Width / 2; adjustment = stripCenter - leftCenterX; break; case RtParagraphAlignment.Right: adjustment = stripSize.Width - rectOffsetX; break; case RtParagraphAlignment.Justify: default: throw new ArgumentOutOfRangeException(); } for (var i = 0; i < newRectangles.Length; i++) { newRectangles[i].Bounds.Center.X += adjustment; } context.LayoutSpans.AddRange(newRectangles); context.RemainingShape = new AaRectangle2(context.RemainingShape.MinMin + Vector2.UnitY * stripSize.Height, context.RemainingShape.MaxMax); if (isFirstStrip) { // todo: adjust for other directions var bulletStr = paragraph.Style.ListStyle.GetIconFor(paragraph.Style.TabCount, /*todo*/ 0); FlushBullet(context, new Vector2(tabOffset, strip.MaxY), bulletStr, subspans.First().Style); } } else { throw new NotImplementedException(); } }
private static int GetPositionInLspan(Vector2 point, RichTextBoxLayoutSpan lspan) { return(lspan.TextAbsPosition + lspan.ClosestIndexFor(point.X)); }
public bool TryGetSpanAt(Vector2 point, out RichTextBoxLayoutSpan lspan) { return(TryGetClosestSpanAt(point, out lspan) && lspan.Bounds.ContainsPoint(point)); }