/// <summary> /// Measures the specified text string. Parameter bounds contains the bounds of the text.<br/> /// Measured values are returned in local coordinate space. /// </summary> /// <param name="bounds">Contains the bounds of the text when returned.</param> /// <returns>The horizontal advance of the measured text (i.e. where the next character should be drawn).</returns> public static float TextBounds(this Nvg nvg, Vector2D <float> pos, string @string, string end, out Rectangle <float> bounds) { bounds = default; Fontstash fons = nvg.fontManager.Fontstash; State state = nvg.stateStack.CurrentState; float scale = nvg.fontManager.GetFontScale() * nvg.pixelRatio.DevicePxRatio; float invscale = 1.0f / scale; if (state.FontId == Fontstash.INVALID) { return(0); } fons.SetSize(state.FontSize * scale); fons.SetSpacing(state.LetterSpacing * scale); fons.SetBlur(state.FontBlur * scale); fons.SetAlign((int)state.TextAlign); fons.SetFont(state.FontId); float width = fons.TextBounds(pos.X * scale, pos.Y * scale, @string, end, out float[] bs); if (bs != null) { fons.LineBounds(pos.Y * scale, out bs[1], out bs[3]); bounds = new Rectangle <float>() { Origin = new Vector2D <float>(bs[0] * invscale, bs[1] * invscale), Size = new Vector2D <float>((bs[2] - bs[0]) * invscale, (bs[3] - bs[1]) * invscale) }; } return(width * invscale); }
/// <summary> /// Measures the specified multi-text string.<br/> /// Measured values are returned in local space. /// </summary> /// <param name="bounds">Contains the bounds box of the multi-text when returned.</param> public static void TextBoxBounds(this Nvg nvg, Vector2D <float> pos, float breakRowWidth, string @string, string end, out Rectangle <float> bounds) { Fontstash fons = nvg.fontManager.Fontstash; State state = nvg.stateStack.CurrentState; float scale = nvg.fontManager.GetFontScale() * nvg.pixelRatio.DevicePxRatio; float invscale = 1.0f / scale; int nrows; Align oldAlign = state.TextAlign; Align hAlign = state.TextAlign & (Align.Left | Align.Centre | Align.Right); Align vAlign = state.TextAlign & (Align.Top | Align.Middle | Align.Bottom | Align.Baseline); if (state.FontId == Fontstash.INVALID) { bounds = default; return; } nvg.TextMetrics(out _, out _, out float lineh); state.TextAlign = Align.Left | vAlign; float minX = pos.X, maxX = pos.X; float minY = pos.Y, maxY = pos.Y; fons.SetSize(state.FontSize * scale); fons.SetSpacing(state.LetterSpacing * scale); fons.SetBlur(state.FontBlur * scale); fons.SetAlign((int)state.TextAlign); fons.SetFont(state.FontId); fons.LineBounds(0, out float rMinY, out float rMaxY); rMinY *= invscale; rMaxY *= invscale; while ((nrows = TextBreakLines(nvg, @string, end, breakRowWidth, out TextRow[] rows, 2)) != 0) { for (uint i = 0; i < nrows; i++) { float rMinX, rMaxX; float dx = 0.0f; if (hAlign.HasFlag(Align.Left)) { dx = 0.0f; } else if (hAlign.HasFlag(Align.Centre)) { dx = breakRowWidth * 0.5f - rows[i].Width * 0.5f; } else if (hAlign.HasFlag(Align.Right)) { dx = breakRowWidth - rows[i].Width; } rMinX = pos.X + rows[i].MinX + dx; rMaxX = pos.X + rows[i].MaxX + dx; minX = MathF.Min(minX, rMinX); maxX = MathF.Max(maxX, rMaxX); minY = MathF.Min(minY, pos.Y + rMinY); maxY = MathF.Max(maxY, pos.Y + rMaxY); pos.Y += lineh * state.LineHeight; } @string = rows[nrows - 1].Next; } state.TextAlign = oldAlign; bounds = new Rectangle <float>(new Vector2D <float>(minX, minY), new Vector2D <float>(maxX, maxY) - new Vector2D <float>(minX, minY)); }