How can i justify label text ?

Started by uswin, Tue 19/10/2010 15:53:16

Previous topic - Next topic

uswin

Hi guys, I have created a custom speech gui using label to display string
here is my screenshot :



any idea how can i justify the text in this gui, just like in microsoft word ?

here is my code so far :

function ccPlayerSpeak(String speech)
{
  ggspeech.SetPosition(10, 10);
  int gameloops = ((speech.Length / game.text_speed) + 1) * GetGameSpeed();
  Labelspeech.Text=speech;
  ggspeech.Visible= true;
  WaitMouseKey(gameloops);
  ggspeech.Visible= false;
}

really appreciate for any of your help. thanks

Khris

You can't. Due to the way AGS renders text in labels, there's no Justify setting in the properties of GUI Labels and consequently no way to do it manually.

You'd have to write your own function, calculating the width of every word and drawing them one by one.

monkey0506

#2
I haven't tested this code, but I worked it up using three functions from my StringPlus module (String.SplitByWidth, String.SplitByString, and StringMergeArray):

Code: ags
String JustifyText(String text, int width, FontType font) {
  if ((String.IsNullOrEmpty(text)) || (width <= 0) || (font < 0) || (font >= Game.FontCount)) return null;
  String lines[] = text.SplitByWidth(width, font, " .,:;!?'""); // you can supply your own delimiter set here if you want; this defines what characters should be used to determine where a line ends at
  if ((lines == null) || (String.IsNullOrEmpty(lines[0])) || (!lines[0].AsInt)) return null;
  int lineCount = lines[0].AsInt;
  int line = 1;
  while (line <= lineCount) { // change this to (line < lineCount) to skip justifying last line
    String words[] = lines[line].SplitByString(" "); // since we're using whitespace to justify the text, use it to find the words in the line
    if ((words != null) && (!String.IsNullOrEmpty(words[0])) && (words[0].AsInt)) {
      // if there's at least two words, we can justify it here
      int wordCount = words[0].AsInt;
      String lineBuffer = lines[line]; // buffer to see how much justification is needed (if any)
      if (lineBuffer == null) lineBuffer = ""; // prevent null pointer errors
      int lineLength = lineBuffer.Length; // store the length before justification
      while (GetTextWidth(lineBuffer.AppendChar(' '), font) <= width) lineBuffer = lineBuffer.AppendChar(' '); // calculate justification needed
      int lineJustification = (lineBuffer.Length - lineLength); // get difference in previous and current length
      int word = wordCount - 1; // justification starts on the right at the second to last word
      while (lineJustification) { // while justification is needed
        words[word] = words[word].AppendChar(' '); // add an extra space to the end of this word
        lineJustification--; // update counter
        word--; // update which word to add justification to
        if (word <= 0) word = wordCount - 1; // if we've reached the first word, go back to the second to last
      }
      if (lineBuffer != lines[line]) lines[line] = StringMergeArray(words, " "); // if the line has been justified, update it
    }
    line++;
  }
  return StringMergeArray(lines, "["); // merge it back together using AGS line-breaks to keep our justification in place
}


Presuming it actually works (I don't have AGS on this computer), you should be able to now do:

Code: ags
Labelspeech.Text = JustifyText(speech, Labelspeech.Width, Labelspeech.Font);


As per your prior example code.

P.S. If you want to use the code without the other 40 or so functions in the StringPlus module, I could PM you modified versions of the module functions (modified to remove references to other module functions).

Edit: I forgot one thing that might have caused some issues with the StringPlus functions. Seeing as I'm using index 0 as the array size the word index shouldn't ever be set to 0 in the above example. It should be iterating through words[1] to words[wordCount - 1] to provide justification of the text.

uswin

I use Monkey_05_06 StringPlus Module and here is my implementation :

Code: ags

String JustifyText(String text, int width, FontType font) {
  if ((String.IsNullOrEmpty(text)) || (width <= 0) || (font < 0) || (font >= Game.FontCount)) return null;
  String lines[] = text.SplitByWidth(width, font, " "); // you can supply your own delimiter set here if you want; this defines what characters should be used to determine where a line ends at
  if ((lines == null) || (String.IsNullOrEmpty(lines[0])) || (!lines[0].AsInt)) return null;
  int lineCount = lines[0].AsInt;
  int line = 1;
  while (line < lineCount) { // change this to (line < lineCount) to skip justifying last line
    String words[] = lines[line].SplitByString(" "); // since we're using whitespace to justify the text, use it to find the words in the line
    if ((words != null) && (!String.IsNullOrEmpty(words[0])) && (words[0].AsInt)) {
      // if there's at least two words, we can justify it here
      int wordCount = words[0].AsInt;
      String lineBuffer = lines[line]; // buffer to see how much justification is needed (if any)
      if (lineBuffer == null) lineBuffer = ""; // prevent null pointer errors
      int lineLength = lineBuffer.Length; // store the length before justification
      while (GetTextWidth(lineBuffer.AppendChar(' '), font) <= width) lineBuffer = lineBuffer.AppendChar(' '); // calculate justification needed
      int lineJustification = (lineBuffer.Length - lineLength); // get difference in previous and current length
      int word = wordCount - 1; // justification starts on the right at the second to last word
      while (lineJustification) { // while justification is needed
        words[word] = words[word].AppendChar(' '); // add an extra space to the end of this word
        lineJustification--; // update counter
        word--; // update which word to add justification to
        if (word < 0) word = wordCount - 1; // if we've reached the first word, go back to the second to last
      }
      if (lineBuffer != lines[line]) lines[line] = StringMergeArray(words, " "); // if the line has been justified, update it
    }
    line++;
  }
  return StringMergeArray(lines, "["); // merge it back together using AGS line-breaks to keep our justification in place
}


and for my custom speech GUI

Code: ags

function ccPemainSpeak(String Kalimat)
{
  ggspeech.SetPosition(10, 10);
  int gameloops = ((Kalimat.Length / game.text_speed) + 1) * GetGameSpeed();
	Labelspeech.Text=JustifyText(Kalimat, Labelspeech.Width - GetTextWidth("[", Labelspeech.Font),Labelspeech.Font);
  ggspeech.Visible= true;
  WaitMouseKey(gameloops);
  ggspeech.Visible= false;
}


here is the result :


The first two line seems justified correctly, the remaining are still repeating the last word at end of the line twice.

SMF spam blocked by CleanTalk