public MultilineString(string text, Rectangle rect, TextAlignment alignment, BitmapFontGroup font,
                        List <MultilineFragment> cachedLines, Color color, bool degrading)
 {
     this.CachedLines = cachedLines;
     this.text        = text;
     rectangle        = rect;
     textAlignment    = alignment;
     this.font        = font;
     this.color       = color;
     this.degrading   = degrading;
 }
        /// <summary>
        /// Draws a multiline text using the Primitives spritebatch.
        /// </summary>
        /// <param name="text">Text to be drawn.</param>
        /// <param name="rectangle">The rectangle bounding the text.</param>
        /// <param name="color">Text color.</param>
        /// <param name="font">Text font (Verdana 14, if null).</param>
        /// <param name="degrading"></param>
        /// <param name="alignment">Text alignment.</param>
        public static void DrawString(string text,
                                      Rectangle rectangle,
                                      Color?color             = null,
                                      BitmapFontGroup font    = null,
                                      TextAlignment alignment = TextAlignment.TopLeft,
                                      bool degrading          = false)
        {
            // TODO complete degrading
            Color           baseColor = color ?? Color.Black;
            BitmapFontGroup baseFont  = font ?? BitmapFontGroup.DefaultFont;
            MultilineString ms        = new MultilineString(text, rectangle, alignment, baseFont, null, baseColor, degrading);
            MultilineString msCache   = MultilineStringCache.GetValueOrDefault(ms, null);

            if (msCache != null)
            {
                foreach (MultilineFragment line in msCache.CachedLines)
                {
                    if (line.Icon != null)
                    {
                        SpriteBatch.Draw(line.Icon,
                                         new Rectangle(rectangle.X + (int)line.PositionOffset.X,
                                                       rectangle.Y + (int)line.PositionOffset.Y,
                                                       line.IconWidth, line.IconWidth), Color.White);
                    }
                    else
                    {
                        SpriteBatch.DrawString(line.Font,
                                               line.Text,
                                               new Vector2(rectangle.X + (int)line.PositionOffset.X,
                                                           rectangle.Y + (int)line.PositionOffset.Y),
                                               line.Color);
                    }
                }

                return;
            }


            Rectangle rrr;

            SetupNewMultilineString(baseFont, text, rectangle, baseColor, alignment, out rrr, out List <MultilineFragment> cachedLines, degrading);
            var multilineString = new MultilineString(text, rectangle, alignment, baseFont, cachedLines, baseColor, degrading);

            MultilineStringCache.Add(multilineString, multilineString);
            DrawString(text, rectangle, baseColor, baseFont, alignment);
        }
Beispiel #3
0
 public BitmapFontGroup(BitmapFont regular, BitmapFont italics, BitmapFont bold, BitmapFont boldItalics, BitmapFontGroup degradesTo = null)
 {
     DegradesTo = degradesTo;
     Regular    = regular; Italics = italics; Bold = bold; BoldItalics = boldItalics;
 }
        /// <summary>
        /// If the text were written to the specified rectangle, how much width and height would it actually use?
        /// This method ignores the rectangle's X and Y properties.
        /// </summary>
        /// <param name="text">Text to draw.</param>
        /// <param name="rectangle">Rectangle bounding the text.</param>
        /// <param name="font">Font to use.</param>
        public static Rectangle GetMultiLineTextBounds(string text, Rectangle rectangle, BitmapFontGroup font = null)
        {
            Rectangle bounds;
            List <MultilineFragment> _;

            SetupNewMultilineString(font ?? BitmapFontGroup.DefaultFont, text, rectangle, Color.Black, TextAlignment.TopLeft, out bounds, out _, false);
            return(bounds);
        }
        /// <summary>
        /// Draws a multi-string.
        /// WARNING! This grows more CPU-intensive as the number of words grow (only if word wrap enabled). It is recommended to use the DrawMultiLineText method instead - it uses caching.
        /// </summary>
        /// <param name="fnt">A reference to a SpriteFont object.</param>
        /// <param name="text">The text to be drawn. <remarks>If the text contains \n it
        /// will be treated as a new line marker and the text will drawn acordingy.</remarks></param>
        /// <param name="r">The screen rectangle that the rext should be drawn inside of.</param>
        /// <param name="col">The color of the text that will be drawn.</param>
        /// <param name="align">Specified the alignment within the specified screen rectangle.</param>
        /// <param name="textBounds">Returns a rectangle representing the size of the bouds of
        /// the text that was drawn.</param>
        /// <param name="cachedLines">This parameter is internal. Do not use it, merely throw away the variable.</param>
        private static void SetupNewMultilineString(BitmapFontGroup fnt, string text, Rectangle r,
                                                    Color col, TextAlignment align, out Rectangle textBounds, out List <MultilineFragment> cachedLines, bool degrading)
        {
            textBounds = r;
            if (text == string.Empty)
            {
                cachedLines = new List <MultilineFragment>();
                return;
            }

            Data d = new Data();

            d.FontGroup          = fnt;
            d.ReadyFragment      = new StringBuilder();
            d.Builder            = new StringBuilder();
            d.CurrentFont        = d.FontGroup.Regular;
            d.CurrentX           = 0;
            d.CurrentY           = 0;
            d.TotalNumberOfLines = 0;
            d.Width      = r.Width;
            d.Height     = r.Height;
            d.IsBold     = false;
            d.IsItalics  = false;
            d.LineHeight = d.FontGroup.Regular.LineHeight;
            d.Color      = col;
            d.End        = false;
            d.Lines      = new List <List <MultilineFragment> >();
            d.ThisLine   = new List <MultilineFragment>();
            if (d.Height >= d.LineHeight)
            {
                foreach (char t in text)
                {
                    if (t == '{')
                    {
                        // Flush and write.
                        FlushAndWrite(d);
                        // Ready to change mode.
                    }
                    else if (t == '}')
                    {
                        // Change mode.
                        switch (d.Builder.ToString())
                        {
                        case "b":
                            d.IsBold = !d.IsBold;
                            d.UpdateFont();
                            break;

                        case "i":
                            d.IsItalics = !d.IsItalics;
                            d.UpdateFont();
                            break;

                        case "/b":
                            d.IsBold = !d.IsBold;
                            d.UpdateFont();
                            break;

                        case "/i":
                            d.IsItalics = !d.IsItalics;
                            d.UpdateFont();
                            break;

                        default:
                            string tag = d.Builder.ToString();
                            if (tag.StartsWith("icon:"))
                            {
                                Texture2D icon = Library.Icons[tag.Substring(5)];
                                d.Builder.Clear();
                                // Now add icon.
                                int iconwidth      = d.LineHeight;
                                int remainingSpace = (int)(d.Width - d.CurrentX);
                                if (remainingSpace > iconwidth + 3)
                                {
                                    d.ThisLine.Add(new MultilineFragment(icon,
                                                                         new Vector2(d.CurrentX, d.CurrentY), iconwidth));
                                    d.CurrentX += iconwidth + 3;
                                }
                                else
                                {
                                    FlushAndWrite(d);
                                    GoToNextLine(d);

                                    d.ThisLine.Add(new MultilineFragment(icon,
                                                                         new Vector2(d.CurrentX, d.CurrentY), iconwidth));
                                    d.CurrentX += iconwidth + 3;
                                }

                                break;
                            }
                            else if (tag[0] == '/')
                            {
                                d.Color = col;
                            }
                            else
                            {
                                d.Color = ColorFromString(tag);
                            }

                            break;
                        }

                        d.Builder.Clear();
                    }
                    else if (t == ' ')
                    {
                        // Flush.
                        // Add builder to ready.
                        string without = d.ReadyFragment.ToString();
                        d.ReadyFragment.Append(d.Builder);
                        if (d.CurrentFont.MeasureString(d.ReadyFragment.ToString()).Width <= d.Width - d.CurrentX)
                        {
                            // It will fit.
                            d.ReadyFragment.Append(' ');
                            d.Builder.Clear();
                        }
                        else
                        {
                            // It would not fit.
                            d.ReadyFragment = new StringBuilder(without);
                            string newone = d.Builder.ToString();
                            d.Builder = new StringBuilder();
                            FlushAndWrite(d, true);
                            if (!d.End)
                            {
                                d.Builder.Append(newone);
                                FlushAndWrite(d);
                                d.Builder.Clear();
                                d.Builder.Append(' ');
                            }
                        }

                        // Write if overflowing.
                    }
                    else if (t == '\n')
                    {
                        // Flush and write.
                        FlushAndWrite(d);
                        // Skip to new line automatically.
                        GoToNextLine(d);
                    }
                    else
                    {
                        d.Builder.Append(t);
                    }

                    if (d.End)
                    {
                        break;
                    }
                }

                // Flush and write.
                FlushAndWrite(d);
                if (d.ThisLine.Count > 0)
                {
                    FinishLine(d);
                    d.TotalNumberOfLines += 1;
                }
            }

            if (d.End && degrading && fnt.DegradesTo != null)
            {
                SetupNewMultilineString(fnt.DegradesTo, text, r, col, align, out textBounds, out cachedLines, degrading);
                return;
            }

            // Output.
            textBounds = new Rectangle(r.X, r.Y, (int)d.Maximumwidthencountered, d.TotalNumberOfLines * d.LineHeight);
            int yoffset = 0;

            switch (align)
            {
            case TextAlignment.TopLeft:
            case TextAlignment.Top:
            case TextAlignment.TopRight:
                break;

            case TextAlignment.Bottom:
            case TextAlignment.BottomLeft:
            case TextAlignment.BottomRight:
                yoffset = r.Height - d.TotalNumberOfLines * d.LineHeight;
                break;

            case TextAlignment.Middle:
            case TextAlignment.Left:
            case TextAlignment.Right:
                yoffset = (r.Height - (d.TotalNumberOfLines * d.LineHeight)) / 2;
                break;
            }
            cachedLines = new List <MultilineFragment>();
            foreach (var line in d.Lines)
            {
                foreach (var fragment in line)
                {
                    if (fragment.Text == "")
                    {
                        continue;
                    }
                    float xoffset   = 0;
                    float lineWidth = line.Sum(frg => frg.Width);
                    switch (align)
                    {
                    case TextAlignment.Right:
                    case TextAlignment.TopRight:
                    case TextAlignment.BottomRight:
                        xoffset = r.Width - lineWidth;
                        break;

                    case TextAlignment.Middle:
                    case TextAlignment.Top:
                    case TextAlignment.Bottom:
                        xoffset = (r.Width - lineWidth) / 2;
                        break;
                    }
                    fragment.PositionOffset += new Vector2(xoffset, yoffset);
                    fragment.PositionOffset  = new Vector2((int)fragment.PositionOffset.X, (int)fragment.PositionOffset.Y);
                    cachedLines.Add(fragment);
                }
            }
        }