public static float LineWidth(this Paragraph para, int lineIndex) { if (para.Breaks.Count == 0) { return(para.Glyphs.Sum(gx => gx.Width)); } BreakList.Node n = para.Breaks.Head.Skip(lineIndex - 1); if (n == null) { return(0); } GlyphList.Node g = para.Glyphs.Head; int idx = n.Value; g = g.Skip(idx); n = n.Next; float w = 0; while (g != null && (n == null || idx++ < n.Value)) { w += g.Value.Width; g = g.Next; } return(w); }
public static IEnumerable <float> LineWidths(this Paragraph para) { if (para.Breaks.Count == 0) { yield return(para.Glyphs.Sum(g => g.Width)); } else { BreakList.Node n = para.Breaks.Head; GlyphList.Node g = para.Glyphs.Head; float w = 0; int i = 0; while (n != null) { while (g != null && ++i <= n.Value) { w += g.Value.Width; g = g.Next; } i--; yield return(w); n = n.Next; w = 0; } while (g != null) { w += g.Value.Width; g = g.Next; } yield return(w); } }
// used for cursor placement public static ParagraphPosition PositionAtLineWidth(this Paragraph para, float width, int line) { if (para.Glyphs == null || para.Glyphs.Count == 0 || line < 0 || line >= para.LineCount) { return(ParagraphPosition.Empty); } GlyphList.Node ng = para.Glyphs.Head; int breakIndex = -1; BreakList.Node nb = para.Breaks.Head; if (nb != null) { breakIndex = nb.Value; } int i = 0; float w = 0; float whalf = (int)(ng.Value.Width / 2f + 0.5f); int x = 0; int y = 0; while ((y < line || (w + whalf <= width)) && ng.Next != null) { if (i == breakIndex - 1) { if (y >= line) { return(new ParagraphPosition(i, x, y, w.Ceil(), ng.Value.Width)); } w = 0; whalf = (int)(ng.Value.Width / 2f + 0.5f); x = 0; y++; nb = nb.Next; if (nb != null) { breakIndex = nb.Value; } } else { x++; w += ng.Value.Width; whalf = (int)(ng.Value.Width / 2f + 0.5f); } ng = ng.Next; i++; } return(new ParagraphPosition(i, x, y, w.Ceil(), ng.Value.Width)); }
public static int EolIndex(this Paragraph para, int line) { if (para.Breaks.Count == 0) { return(para.Length - 1); } BreakList.Node n = para.Breaks.Head; n = n.Skip(line); if (n == null) { return(para.Length - 1); } return(n.Value - 1); }
public static int LineFromPosition(this Paragraph para, int pos) { if (pos == 0 || para.Breaks.Count == 0) { return(0); } BreakList.Node n = para.Breaks.Head; int line = 0; while (n != null && n.Value <= pos) { n = n.Next; line++; } return(line); }
// used for general purpose public static ParagraphPosition PositionAtIndex(this Paragraph para, int pos) { if (para.Glyphs == null || para.Glyphs.Count == 0 || pos <= 0) { return(ParagraphPosition.Empty); } pos = pos.Clamp(0, para.Glyphs.Count - 1); GlyphList.Node ng = para.Glyphs.Head; int breakIndex = -1; BreakList.Node nb = para.Breaks.Head; if (nb != null) { breakIndex = nb.Value; } int i = 0; int x = 0; int w = 0; int y = 0; while (i < pos && ng.Next != null) { if (i == breakIndex - 1) { w = 0; x = 0; y++; nb = nb.Next; if (nb != null) { breakIndex = nb.Value; } } else { x++; w += ng.Value.Width; } i++; ng = ng.Next; } return(new ParagraphPosition(pos, x, y, w, ng.Value.Width)); }
public static int FastPositionAtIndex(this Paragraph para, int pos) { if (para.Breaks.Count == 0) { return(pos); } BreakList.Node n = para.Breaks.Head; while (n != null && n.Next != null && n.Next.Value - 1 < pos) { n = n.Next; } if (n == null) { return(pos); } if (pos < n.Value) { return(pos); } return(pos - n.Value); }
public static int PositionAtLineIndex(this Paragraph para, int col, int line) { if (para.Breaks.Count == 0) { return(col.Clamp(0, para.Length - 1)); } BreakList.Node n = para.Breaks.Head; if (line == 0) { return(col.Clamp(0, n.Value - 1)); } n = n.Skip(line - 1); if (n == null) { return(para.Length - 1); } if (n.Next == null) { return(Math.Min(n.Value + col, para.Length - 1)); } return(Math.Min(n.Value + col, n.Next.Value - 1)); }