- Home /
How to return the texts in a GUI.Box after they got modified by the Box?
Hi
I have problem with right to left languages in unity, it is my last problem and if it get fixed i can finally start my project O_O
Look at the picture: when GUI.Box wrap texts in multi lines it sort them from bottom to top (in right to left languages)! That is why i need to know how many lines are in the GUI.Box after the wraping happens then i can put them in a string[] and reverse them to solve the problem. (well at least i think it should solve the problem ;p)

I tried this with no result:
GUI.Box(new Rect(20, 20, Screen.width - 40, Screen.height - 40), Text);
string[] Test1 = Text.Split('\n'); // Possible Problem O_O
foreach (string s in Test1)
{
Debug.Log(s);
}
I guess the problem is where i commented: I think i split the original text not that one which got wraped in GUI.Box?, But how can i get the Wraped/Modified text after GUI.Box did his job?
Possible problem 2 (same line i commented): GUI.Box doesn't break lines with '/n' ? :|
_ (keep in mind that i am a newbie so keep it simple! xD)
Answer by Bunny83 · Nov 06, 2014 at 09:34 AM
Unfortunately there's no straight forward method to get that information. However with a few tricks it's possible:
GUIContent singleLine = new GUIContent("H");
GUIContent doubleLine = new GUIContent("H\nH");
int GetLineCount(Rect aRect, GUIContent aText, GUIStyle aStyle)
{
float lineHeight = (aStyle.CalcHeight(doubleLine, 1000) - aStyle.CalcHeight(singleLine, 1000));
Vector2 pos = aStyle.GetCursorPixelPosition(aRect, aText, aText.text.Length) - aStyle.GetCursorPixelPosition(aRect, aText, 0);
return (int)(pos.y / lineHeight)+1;
}
This method will calculate the line count in an GUI control. Keep in mind that empty lines will count as well. If you have a newline character at the end it will count as another line.
You have to pass the same position Rect as you used for your control as well as the same GUIContent. The last parameter is the used style. If you didn't use a custom style, you have to pass the default style for that control as string.
Example:
Rect R = new Rect(20, 20, Screen.width - 40, Screen.height - 40);
GUI.Box(R, Text); // default style "box"
int lineCount = GetLineCount(R, new GUIContent(Text), "box");
This will return the actual line count taking wordwrap of the used style into account.
edit
However getting the line count won't probably help since you still don't know where a new line starts. For this you can use a helper like this:
string[] SplitAtWordWrap(Rect aRect, string aText, GUIStyle aStyle)
{
var lines = new List<int>();
var content = new GUIContent(aText);
float old = aStyle.GetCursorPixelPosition(aRect, content, 0).y;
for (int i = 1; i < aText.Length; i++)
{
float y = aStyle.GetCursorPixelPosition(aRect, content, i).y;
if (y > old)
{
old = y;
lines.Add(i);
}
}
if (lines.Count == 0)
return new string[]{aText};
string[] result = new string[lines.Count+1];
result[0] = aText.Substring(0,lines[0]).Replace("\n","");
for(int i = 0; i < lines.Count; i++)
{
if (i < lines.Count-1)
result[i + 1] = aText.Substring(lines[i], lines[i + 1] - lines[i]).Replace("\n", "");
else
result[i + 1] = aText.Substring(lines[i]).Replace("\n", "");
}
return result;
}
This method will "scan" for new lines and split the string at those positions. It will remove all "old" new line characters. Keep in mind that this need to be executed inside OnGUI. However calling it every OnGUI call would produce a huge amount of garbage and wouldn't be very fast, so consider doing this only once or when needed.
For the generic List you need of course this line on top:
using System.Collections.Generic;
edit
Copied the example from the comments below ;)
string someText = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n";
bool executed = false;
GUIStyle boxStyle;
void OnGUI()
{
if(!executed)
{
executed = true; // do it only once
boxStyle = new GUIStyle("box");
boxStyle.wordWrap = true; // set the style to word wrap
var res = "";
Rect r = new Rect(0, 0, 100, 200);
foreach (var line in SplitAtWordWrap(r, someText, boxStyle).Reverse())
{
res += line + "\n";
}
someText = res;
}
GUI.Box(new Rect(0, 0, 100, 200), someText, boxStyle);
}
@mohammad-alavi: That's what i thought, so i made another method ;)
@mohammad-alavi: Well, are you sure that you have "wordwrap" set to true for your box style? It works just fine for me. $$anonymous$$eep in $$anonymous$$d you have to execute this method from inside OnGUI. Doing it in Start or Awake won't work.
$$anonymous$$aybe it behaves differently for a right-to-left font. As far as i remember Unity doesn't support RTL out of the box. $$anonymous$$aybe that has already been implemented, if not you might want to look for an RTL converter in the assetstore. There are a few afaik.
This works for me:
string someText = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n";
bool executed = false;
GUIStyle boxStyle;
void OnGUI()
{
if(!executed)
{
executed = true; // do it only once
boxStyle = new GUIStyle("box");
boxStyle.wordWrap = true; // set the style to word wrap
var res = "";
Rect r = new Rect(0, 0, 100, 200);
foreach (var line in SplitAtWordWrap(r, someText, boxStyle).Reverse())
{
res += line + "\n";
}
someText = res;
}
GUI.Box(new Rect(0, 0, 100, 200), someText, boxStyle);
}
The actual GUI.Box wouldn't need the modified boxStyle since each line should now be short enough to fit into the rect. To use the Reverse method you have to add using System.Linq; at the top. For me it displays the text correctly wordwrapped but the lines in reverse order.
Of course it isn't a RTL text but i tried some random arabic text and it seems to work as well. At least the way you explained it in your question. Unfortunately I don't know anything about any of those RTL languages so i can't tell if it's correct :)
@mohammad-alavi:
Well, you just have to split your text before you use SplitAtWordWrap. So just split your text at new line characters into a seperate string for each paragraph. Now you can "reverse" each paragraph on it's own and finally just "concat" the result back together.
To split a string at the line feed character use:
string[] paragraphs = text.Split('\n');
@mohammad:
Hmm, sorry but i'm confused a bit, probably because i don't know how you read such a RTL text ^^. In your questions picture you just showed the two lines reversed and with the empty space in the top line (I guess you read from bottom to top, right?).
I'm not sure which lines you want to join together? If i got that right the paragraphs should be ordered from top to bottom but in each paragraph the lines should be swaped. So each paragraph is handled on it's own, or do you want to join parts of two different paragraphs together?
Each paragraph must not contain any new line characters. It should be one line of text, otherwise you can't split the paragraphs at that character.
I guess the word wrapping feature of Unity's GUI system might not be the best choice as it simply doesn't support RTL text. What you could do manually is splitting the whole paragraph manually into words (split at the " " (space) character), check the legnth of each word (using CalcSize with only one word + a space) and add up the x size value until you reach the size of your rect. Then you can simply rejoin the words and construct seperate lines yourself. There you have full control of the order of the words in a paragraph and which will be the first line.
Your answer
Follow this Question
Related Questions
How to create GUIBox with tools? 0 Answers
Fading between scenes 1 Answer
GUI box not moving with game object on X axis 0 Answers
GUI Box to draw Target Lock Icon 1 Answer