This xna code snip allows you to draw text, with the option of having that text
word wrapped to the specified rectangle or you can specify text alignment info like
weather or not the text should be drawn anchored to the bottom right of the rectangle
or top right etc.
///
<summary>
///
Draws a string.
///
</summary>
///
<param name="sb">A
reference to a SpriteBatch object that will draw the text.</param>
///
<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="performWordWrap">If true the words within the text will be aranged to rey and
///
fit within the bounds of the specified screen rectangle.</param>
///
<param name="offsett">Draws
the text at a specified offset relative to the screen
///
rectangles top left position. </param>
///
<param name="textBounds">Returns
a rectangle representing the size of the bouds of
///
the text that was drawn.</param>
public
static void DrawString(SpriteBatch
sb, SpriteFont fnt, string
text, Rectangle r,
Color col,
TextAlignment align,
bool performWordWrap, Vector2 offsett,
out Rectangle
textBounds)
{
// check if there
is text to draw
textBounds = r;
if (text
== null) return;
if (text
== string.Empty) return;
StringCollection
lines = new StringCollection();
lines.AddRange(text.Split(new
string[] { "\\n"},
StringSplitOptions.RemoveEmptyEntries));
// calc the size
of the rect for all the text
Rectangle
tmprect = ProcessLines(fnt, r, performWordWrap, lines);
// setup the position
where drawing will start
Vector2
pos = new Vector2(r.X,
r.Y);
int aStyle
= 0;
switch
(align)
{
case
TextAlignment.Bottom:
pos.Y = r.Bottom
- tmprect.Height;
aStyle = 1;
break;
case
TextAlignment.BottomLeft:
pos.Y = r.Bottom
- tmprect.Height;
aStyle = 0;
break;
case
TextAlignment.BottomRight:
pos.Y = r.Bottom
- tmprect.Height;
aStyle = 2;
break;
case
TextAlignment.Left:
pos.Y =
r.Y + ((r.Height / 2) - (tmprect.Height / 2));
aStyle = 0;
break;
case
TextAlignment.Middle:
pos.Y =
r.Y + ((r.Height / 2) - (tmprect.Height / 2));
aStyle = 1;
break;
case
TextAlignment.Right:
pos.Y = r.Y
+ ((r.Height / 2) - (tmprect.Height / 2));
aStyle = 2;
break;
case
TextAlignment.Top:
aStyle = 1;
break;
case
TextAlignment.TopLeft:
aStyle = 0;
break;
case
TextAlignment.TopRight:
aStyle = 2;
break;
}
// draw text
for (int idx = 0; idx < lines.Count; idx++)
{
string
txt = lines[idx];
Vector2 size = fnt.MeasureString(txt);
switch
(aStyle)
{
case 0:
pos.X = r.X;
break;
case 1:
pos.X = r.X + ((r.Width / 2) - (size.X / 2));
break;
case 2:
pos.X = r.Right - size.X;
break;
}
//
draw the line of text
sb.DrawString(fnt, txt,
pos + offsett, col);
pos.Y += fnt.LineSpacing;
}
textBounds = tmprect;
}
internal
static Rectangle ProcessLines(SpriteFont
fnt, Rectangle r, bool
performWordWrap, StringCollection lines)
{
// llop through
each line in the collection
Rectangle
bounds = r;
bounds.Width = 0;
bounds.Height = 0;
int index
= 0;
float
Width = 0;
bool
lineInserted = false;
while
(index < lines.Count)
{
//
get a line of text
string
linetext = lines[index];
//measure
the line of text
Vector2 size = fnt.MeasureString(linetext);
//
check if the line of text is geater then then the rect we want to draw it inside
of
if
(performWordWrap && size.X > r.Width)
{
// find last space character in line
string endspace = string.Empty;
// deal with trailing spaces
if (linetext.EndsWith(" "))
{
endspace = " ";
linetext = linetext.TrimEnd();
}
// get the index of the last space character
int i = linetext.LastIndexOf(" ");
if (i != -1)
{
// if there was a space grab the last word in the line
string lastword = linetext.Substring(i + 1);
// move word to next line
if (index == lines.Count - 1)
{
lines.Add(lastword);
lineInserted = true;
}
else
{
// prepend last word to begining of next line
if (lineInserted)
{
lines[index + 1] = lastword + endspace + lines[index
+ 1];
}
else
{
lines.Insert(index + 1, lastword);
lineInserted = true;
}
}
// crop last word from the line that is being processed
lines[index] = linetext.Substring(0, i + 1);
}
else
{
// there appear to be no space characters on this line s
move to the next line
lineInserted = false;
size = fnt.MeasureString(lines[index]);
if (size.X > bounds.Width) Width = size.X;
bounds.Height += fnt.LineSpacing;// size.Y - 1;
index++;
}
}
else
{
// this line will fit so we can skip to the next line
lineInserted
= false;
size = fnt.MeasureString(lines[index]);
if (size.X > bounds.Width) bounds.Width = (int)size.X;
bounds.Height
+= fnt.LineSpacing;//size.Y - 1;
index++;
}
}
// returns the
size of the text
return
bounds;
}