After a little bit of work, I have a system that splits a string into a 3D array: the first dimension contains the entire string, split up into one line per element, the second dimension contains each part of line, as split up by arbitrary tags, and the third dimension contains the actual text and a cached ref to the style associated with it.
Anyway, to the example:
var notice = "Hello there. <blu>How are you? <nor>I'm fine, thank you for asking. <blu>How would you like to be my pet? <red>Oh, I'd love that. <nor>I do believe I'm going crazy as all <blu>balls <nor>else.";
var messageToReturn = ParseStyles(notice, null); // We can pass a default style here
function ParseStyles(notice : String, style : GUIStyle)
{
// <nor> = noticeNormal : GUIStyle
// <blu> = noticeBlue : GUIStyle
// <red> = noticeRed : GUIStyle
if (style != null)
var curStyle = style;
else
// Start with normal style
curStyle = noticeNormal;
var msg : Array = Array();
var leftovers : String = notice;
var cont : boolean = true;
while (cont)
{
var container : Array = Array();
var go : boolean = true;
// My lines will only be ~39 chars long
if (leftovers.length >= 39)
var charsToGo : int = 39;
else
{
charsToGo = leftovers.length-1;
// We've reached the end, so do not continue
cont = false;
}
var text : String = leftovers;
while (go)
{
// --- Find indexes of tags within the first chunk (39 chars) of the string
var normalIndex : int = text.IndexOf("<nor>",0, charsToGo);
if (normalIndex == -1) normalIndex = 100; // Infinity doesn't work, but 100 is guaranteed to be higher than 39, our max index
var blueIndex : int = text.IndexOf("<blu>",0, charsToGo);
if (blueIndex == -1) blueIndex = 100;
var redIndex : int = text.IndexOf("<red>",0, charsToGo);
if (redIndex == -1) redIndex = 100;
var lowest : int = Mathf.Min(normalIndex,blueIndex);
lowest = Mathf.Min(lowest, redIndex);
// ...etc. with all other styles compared to the previous lowest. May the lowest low win
if (lowest > 0 && lowest < 39)
{
// Put what we have so far plus the style into the end of the array
container.Add(Array(text.Substring(0,lowest), curStyle ));
// Remove what we added to container
text = text.Remove(0, lowest);
// Calculate the new style for the next iteration of the while loop. Mine starts at 1 and goes 3 because I'm evaluating what's between the <___>
var sub : String = text.Substring(1, 3);
switch (sub)
{
case "nor":
curStyle = noticeNormal;
break;
case "blu":
curStyle = noticeBlue;
break;
case "red":
curStyle = noticeRed;
break;
}
// Remove the tag characters and subtract from charsToGo. My tags are 5 chars long
print ("before: "+text);
text = text.Remove(0, 5);
charsToGo -= lowest + 5;
}
else
{
// No styles found in this segment, so put the rest of the line in and get ready for tail recursion
if (cont)
// We have more to do, cut at the last space.
var lastSpace = text.LastIndexOf(" ",charsToGo); // cut it off at the last space
else
// We have naught else to do, manually set lastSpace to force the whole thing into container
lastSpace = -1;
// Now check lastSpace
if (lastSpace != -1)
{
container.Add(Array(text.Substring(0,lastSpace), curStyle ));
leftovers = text.Remove(0, lastSpace); // Cuts everything up to lastSpace
}
// There is nothing more to parse
else
{
container.Add(Array(text, curStyle ));
}
msg.Add(container);
go = false;
}
}
}
return msg;
}
And for the GUI implementation you just need some Layouting:
GUILayout.BeginHorizontal(GUI.skin.box, GUILayout.Height(100), GUILayout.Width(760), GUILayout.ExpandHeight(true));
GUILayout.Space(30);
GUILayout.BeginVertical();
GUILayout.Space(10);
GUILayout.FlexibleSpace();
for (x in messageToReturn)
{
GUILayout.BeginHorizontal();
for (n in x)
{
GUILayout.Space(10);
GUILayout.Label(n[0], n[1]);
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.Space(1);
}
GUILayout.Space(10);
GUILayout.FlexibleSpace();
GUILayout.EndVertical();
GUILayout.Space(30);
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
All the extra spaces and such I have in there for alignment reasons.
Now, there are some flaws to this system, most noticeably that if style changes font size some clipping may occur, there's nothing to handle words longer than the arbitrary line limit, and tags all have to be the same length (3 characters right now). These can be fixed with a little tweaking, but I figured it was complete enough to share with the community at large now.
Enjoy! If you have questions, feel free to email me at cjcurrie@blackstormsstudios.com
This guy, (http://forum.unity3d.com/viewtopic.php?t=9808), used the approximation technique, with 5 pixels per character and GUILayout.Label's instead of manual GUI.Label's.
– anon43051525