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);
        }
Example #4
0
        /// <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);
        }