private void IterateString(string text, Vector2 Position, bool Draw, float scale, Color4 Color, CoordinateType CoordinateType, out StringMetrics Metrics) { Metrics = new StringMetrics(); Vector2 StartPosition = Position; float scalY = CoordinateType == CoordinateType.SNorm ? -1 : 1; foreach (char c in text) { var CD = GetCharDescription(c); var CharMetrics = CD.ToStringMetrics(Position, scale, scale * scalY); if (Draw) { if (CharMetrics.FullRectSize.X != 0 && CharMetrics.FullRectSize.Y != 0) { float posY = Position.Y - scalY * CharMetrics.OverhangTop; float posX = Position.X - CharMetrics.OverhangLeft; Sprite.Draw(CD.TableDescription.SRV, new Vector2(posX, posY), CharMetrics.FullRectSize, CD.TexCoordsStart, CD.TexCoordsSize, Color, CoordinateType); } } Metrics.Merge(CharMetrics); Position.X += CharMetrics.Size.X; //Break newlines if (c == '\r') { Position.X = Metrics.TopLeft.X; } if (c == '\n') { Position.Y = Metrics.BottomRight.Y - CharMetrics.Size.Y / 2; } } }
/// <summary> /// Draws the string in the specified coordinate system aligned in the given rectangle. The text is not clipped or wrapped. /// </summary> /// <param name="text">The text to draw</param> /// <param name="Rect">The rectangle in which to align the text</param> /// <param name="Align">Alignment of text in rectangle</param> /// <param name="RealFontSize">The real font size in the chosen coordinate system</param> /// <param name="Color">The color in which to draw the text</param> /// <param name="CoordinateType">The chosen coordinate system</param> /// <returns>The StringMetrics for the rendered text</returns> public StringMetrics DrawString(string text, RectangleF Rect, TextAlignment Align, float RealFontSize, Color4 Color, CoordinateType CoordinateType) { //If text is aligned top and left, no adjustment has to be made if (Align.HasFlag(TextAlignment.Top) && Align.HasFlag(TextAlignment.Left)) { return(DrawString(text, new Vector2(Rect.X, Rect.Y), RealFontSize, Color, CoordinateType)); } text = text.Replace("\r", ""); var RawTextMetrics = MeasureString(text, RealFontSize, CoordinateType); var mMetrics = MeasureString("m", RealFontSize, CoordinateType); float startY; if (Align.HasFlag(TextAlignment.Top)) { startY = Rect.Top; } else if (Align.HasFlag(TextAlignment.VerticalCenter)) { startY = Rect.Top + Rect.Height / 2 - RawTextMetrics.Size.Y / 2; } else //Bottom { startY = Rect.Bottom - RawTextMetrics.Size.Y; } var TotalMetrics = new StringMetrics(); //break text into lines var lines = text.Split('\n'); foreach (var line in lines) { float startX; if (Align.HasFlag(TextAlignment.Left)) { startX = Rect.X; } else { var lineMetrics = MeasureString(line, RealFontSize, CoordinateType); if (Align.HasFlag(TextAlignment.HorizontalCenter)) { startX = Rect.X + Rect.Width / 2 - lineMetrics.Size.X / 2; } else //Right { startX = Rect.Right - lineMetrics.Size.X; } } var lineMetrics2 = DrawString(line, new Vector2(startX, startY), RealFontSize, Color, CoordinateType); float lineHeight; if (mMetrics.Size.Y < 0) { lineHeight = Math.Min(lineMetrics2.Size.Y, mMetrics.Size.Y); } else { lineHeight = Math.Max(lineMetrics2.Size.Y, mMetrics.Size.Y); } startY += lineHeight; TotalMetrics.Merge(lineMetrics2); } return(TotalMetrics); }
private void IterateStringEm(string text, Vector2 Position, bool Draw, float RealFontSize, Color4 Color, CoordinateType CoordinateType, out StringMetrics Metrics) { float scale = RealFontSize / _FontSize; IterateString(text, Position, Draw, scale, Color, CoordinateType, out Metrics); }
/// <summary> /// Merges this instance of StringMetrics with another instance. /// The textblock and overhangs of this instance will be increased to cover both instances. /// </summary> /// <param name="second">The second StringMetrics instance. This object will not be changed.</param> /// <exception cref="System.ArgumentException">Thrown when one instance has flipped axes and the other does not.</exception> public void Merge(StringMetrics second) { //if current instance has no values yet, take the values of the second instance if (Size.X == 0 && Size.Y == 0) { TopLeft = second.TopLeft; Size = second.Size; OverhangLeft = second.OverhangLeft; OverhangRight = second.OverhangRight; OverhangTop = second.OverhangTop; OverhangBottom = second.OverhangBottom; return; } //if second instance is not visible, do nothing if (second.FullRectSize.X == 0 && second.FullRectSize.Y == 0) { return; } //Flipped y axis means that positive y points upwards //Flipped x axis means that positive x points to the right bool xAxisFlipped = Size.X < 0; bool yAxisFlipped = Size.Y < 0; //Check, if axes of both instances point in the same direction if (this.Size.X * second.Size.X < 0) { throw new ArgumentException("The x-axis of the current instance is " + (xAxisFlipped ? "" : "not ") + "flipped. The x-axis of the second instance has to point in the same direction"); } if (this.Size.Y * second.Size.Y < 0) { throw new ArgumentException("The y-axis of the current instance is " + (yAxisFlipped ? "" : "not ") + "flipped. The y-axis of the second instance has to point in the same direction"); } //Update flipped info if it cannot be obtained from the current instance if (Size.X == 0) { xAxisFlipped = second.Size.X < 0; } if (Size.Y == 0) { yAxisFlipped = second.Size.Y < 0; } //Find the functions to determine the topmost of two values and so on Func <float, float, float> FindTopMost, FindBottomMost; Func <float, float, float> FindLeftMost, FindRightMost; if (yAxisFlipped) { FindTopMost = Math.Max; FindBottomMost = Math.Min; } else { FindTopMost = Math.Min; FindBottomMost = Math.Max; } if (xAxisFlipped) { FindLeftMost = Math.Max; FindRightMost = Math.Min; } else { FindLeftMost = Math.Min; FindRightMost = Math.Max; } //Find new textblock float Top = FindTopMost(this.TopLeft.Y, second.TopLeft.Y); float Bottom = FindBottomMost(this.TopLeft.Y + this.Size.Y, second.TopLeft.Y + second.Size.Y); float Left = FindLeftMost(this.TopLeft.X, second.TopLeft.X); float Right = FindRightMost(this.TopLeft.X + this.Size.X, second.TopLeft.X + second.Size.X); //Find new overhangs float TopOverhangPos = FindTopMost(this.FullRectTopLeft.Y, second.FullRectTopLeft.Y); float BottomOverhangPos = FindBottomMost(this.FullRectTopLeft.Y + this.FullRectSize.Y, second.FullRectTopLeft.Y + second.FullRectSize.Y); float LeftOverhangPos = FindLeftMost(this.FullRectTopLeft.X, second.FullRectTopLeft.X); float RightOverhangPos = FindRightMost(this.FullRectTopLeft.X + this.FullRectSize.X, second.FullRectTopLeft.X + second.FullRectSize.X); TopLeft = new Vector2(Left, Top); Size = new Vector2(Right - Left, Bottom - Top); OverhangLeft = (Left - LeftOverhangPos) * (xAxisFlipped ? -1 : 1); OverhangRight = (RightOverhangPos - Right) * (xAxisFlipped ? -1 : 1); OverhangTop = (Top - TopOverhangPos) * (yAxisFlipped ? -1 : 1); OverhangBottom = (BottomOverhangPos - Bottom) * (yAxisFlipped ? -1 : 1); }