Text Area

Aug 6, 2008 at 3:35 PM
Hi. I've been using your project and, boy has it been useful! Thanks!

However I lack one kind of component you don't seem to have implemented - a Text Area, i.e, an area where to put text that would create a scroll bar if the text is bigger than the area.
Do you intend to do something of the kind? Because I really needed something like that... I tried to do it but I got stuck in the part where labels don't wrap text...
I need this component because in my game I have to give instructions to the user and can have lots of text. Also, the text can vary a lot so writing the text "by hand" is not a solution.
At the very least I would need a component that would able me to write text one line below the other without having to separate the text throughout various labels and positioning them one below the other...
Any ideas?
Aug 7, 2008 at 2:06 AM
I created a TextArea using a very useful property of your ListBox - the vertical resizing when entries are more than the ListBox's vertical size.
TextArea inherits from ListBox. I brake the text I want to put in the TextArea into several lines and add them as entries of the ListBox.
I had to add a protected property to your project's ListBox class, because I needed to access the SpriteFont that is used for writing the text, so that I can know the width of the text in pixels.
The code is as follows:

ListBox.cs
// add the following code to this class:

        protected SpriteFont SpriteFont
        {
            get { return this.font; }
        }

TextArea.cs
// Add this class to the WindowSystem project
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework.Graphics;

namespace WindowSystem
{
    public class TextArea: ListBox
    {
        #region Fields
        private string text;
        #endregion

        #region Properties
        /// <summary>
        /// Get/Set the control text.
        /// </summary>
        public string Text
        {
            get { return this.text; }
            set
            {
                this.text = value;
                RefreshText();
            }
        }

        /// <summary>
        /// Get/Set the control width.
        /// </summary>
        public new int Width
        {
            get { return base.Width; }
            set
            {
                base.Width = value;
                RefreshText();
            }
        }

        /// <summary>
        /// Get/Set the control height.
        /// </summary>
        public new int Height
        {
            get { return base.Height; }
            set
            {
                base.Height = value;
                RefreshText();
            }
        }
        #endregion

        #region Constructors
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="game">The currently running Game object.</param>
        /// <param name="gui">GUIManager that this control is part of.</param>
        public TextArea(Game game, GUIManager gui)
            : base(game, gui)
        {
            this.text = "";
        }
        #endregion

        #region Private Methods
        /// <summary>
        /// Refreshes the text in the control.
        /// </summary>
        private void RefreshText()
        {
            // Clear all entries
            this.Clear();

            // Break the text into lines
            List<string> lines = BreakTextToEntries();

            // Add each line as an entry of the ListBox
            foreach (string str in lines)
            {
                this.AddEntry(str);
            }
        }

        /// <summary>
        /// Breaks the Text into several lines with the width of the TextArea.
        /// </summary>
        /// <returns>A list containing all the generated lines.</returns>
        private List<string> BreakTextToEntries()
        //private void BreakTextToEntries()
        {
            string[] words = Text.Split(' ');
            List<string> lines = new List<string>();
            string currentLine = "";
            string auxLine;
            int auxLineSize;
            int lineHSize = this.Width - this.HMargin * 4;

            foreach(string word in words)
            {
                auxLine = currentLine + word + " ";
                auxLineSize = GetTextWidth(auxLine, SpriteFont);

                if ( auxLineSize < lineHSize)
                {
                    currentLine = auxLine;
                }
                else
                {
                    lines.Add(currentLine);
                    currentLine = word + " ";
                }
            }
            lines.Add(currentLine);

            return lines;
        }

        /// <summary>
        /// Gets the width of a piece of text.
        /// </summary>
        /// <param name="txt">The text to be measured.</param>
        /// <returns>The number of pixels the text will occupy on screen.</returns>
        private int GetTextWidth(string txt, SpriteFont font)
        {
            int a = (int)font.MeasureString(txt).X;
            return a;
        }
        #endregion
    }
}


In conclusion, the TextArea will contain any text you give it and will create a vertical scroll if the text is longer than the vertical size of the box. However, the scroll in only vertical - there is no horizontal scroll (the scroll property is exactly the same of the ListBox). The text will adapt to the horizontal size.
The class in nothing special and can be improved, but feel free to use it if you like.

Carolina
Coordinator
Aug 19, 2008 at 6:07 PM
Thanks very much for the help. I'll try the control out and aim to get the functionality in the next release.

Thanks,
Aaron