GetTextWidth & Wrapping

Started by monkey0506, Sat 29/01/2005 03:47:29

Previous topic - Next topic

monkey0506

I have just discovered the "GetTextWidth" function, and I was wondering about it. Is there a way to test where (and/or if) the text exceeds a certain amount. For example, if the text width was 345, could I find what the text was at 320, and cut the rest into a separate string? Or does wrapping cause the text width to end, producing no greater value than 320? In any case, thanks for any help. I'm still looking for a way to provide multi-line text for my scrolling dialog workaround, so any ideas would be greatly appreciated. ;D

Scorpiorus

Yeah, here is an example:

function StrCutByWidth(string input, int width, int font, string output, string tail) {

   string text;
   string temp;
   
   StrCopy(text, input);
   StrCopy(temp, "");
   StrCopy(output, "");
   StrCopy(tail, "");
   
   int textLength = StrLen(text);
   
   int i = 0;
   int tail_index = 0;
   
   while (i < textLength)
   {
      StrFormat(temp, "%s%c", temp, StrGetCharAt(text, i));
      
      // if there is a space character or the end of string *ahead*:
      if ((StrGetCharAt(text, i+1) == ' ') || (i+1 == textLength))
      {
         if (GetTextWidth(temp, font) <= width)
         {
            StrCopy(output, temp);
            tail_index = i + 1;
         }
         else
         {
            i = textLength; // abort the while loop;
         }
      }
            
      i++;
   }
   
   if (tail_index < textLength)
   {
      // skip a space character unless it's beginning of the string:
      i = tail_index + (tail_index > 0);
      
      while (i < textLength)
      {
         StrFormat(tail, "%s%c", tail, StrGetCharAt(text, i));
         i++;
      }
   }
}

You provide an input string and width and font parameters.

output holds truncated string while tail stores cut off part.

monkey0506

I'm not exactly sure what the values of output and tail are in that script. Or why they are passed as parameters if they are just cleared with StrCopy at the beginning of the function. But I'll take a look at it.

Scorpiorus

Those are parameters you pass to the function in order to get the result, just like, for example, a buffer parameter for GetObjectName(int objNum, string buffer).

Example:

Ã,  int width = 50;
Ã,  int font = 0;
Ã,  Ã, 
Ã,  string output;
Ã,  string tail;
Ã, 
Ã,  StrCutByWidth("Hello world!", width, font, output, tail);
Ã, 
Ã,  Display("Output:%s", output);
Ã,  Display("Tail:%s", tail);

It displays...

Output:Hello

and...

Tail:world!

monkey0506

Ok... I get it now. Thanks for clearing that up. The problem is going to be actually implementing this information. I will get it figured out, but it's not looking easy.  And I've found an issue with my dialogue template (but I'm too lazy to log in and report it in the official thread):  You can't turn off a dialogue option in a scrolling dialogue (yet).  So, I have some issues to get worked out with my scrolling dialogue template, and then I'll have done something useful.

monkey0506

Sorry for digging this up (but it's good to see the search function working again), but I have a problem with the code Scorpiorus provided me with:

Code: ags
function StrCutByWidth(string input, short width, char font, string output, string tail) {
  /* cut string "input" into two strings "output" and "tail" where **  
  ** "output" when displayed in font "font" has width "width"      */
  string text;
  string temp;
  StrCopy(text, input);
  StrCopy(temp, "");
  StrCopy(output, "");
  StrCopy(tail, "");
  char textLength = StrLen(text);
  char i = 0;
  char tail_index = 0;
  while (i < textLength) {
    StrFormat(temp, "%s%c", temp, StrGetCharAt(text, i));
    /* if next char is space ' ' or end of string */
    if ((StrGetCharAt(text, i + 1) == ' ') || (i + 1 == textLength)) {
      if (GetTextWidth(temp, font) <= width) {
        StrCopy(output, temp);
        tail_index = i + 1;
        }
      else i = textLength; /* abort while loop */
      }
    i++;
    }
  if (tail_index < textLength) {
    /* skip a space character unless it's the beginning of the string */
    i = tail_index + (tail_index > 0);
    while (i < textLength) {
      StrFormat(tail, "%s%c", tail, StrGetCharAt(text, i));
      i++;
      }
    }
  }


I entered this --> "Holy crap!  I can't believe it worked!  This is so friggin' awesome!  I can't wait to finish it now!" <-- that string and the function said that "Holy crap!  I can't believe it worked!  This is so friggin' awesome!" would fit in the space allotted for one line (318 pixels in this case) but when I tested the game the "awesome!" was pushed by AGS to the next line (label stretching) making it impossible to read the rest of the string "  I can't wait to finish it now!" which I had stored in a label located beneath the one holding the first part of the string...  Sorry if I didn't make any sense, but I'm basically just asking for someone to explain where this function went wrong...

Scorpiorus

It's probably because AGS does label stretching a little bit different than the function in question, so I wouldn't rely on it to be working just like the internal mechanism. You could try making a label a little wider (2 or 3 pixels more) and see if it solves the problem.

monkey0506

I did solve the problem (after rewriting the function myself several times (probably successfully (but I got the same error)).  The problem was the first part "Holy crap!...awesome!" when displayed in the font I used had the exact same width as the label.  So, I changed the bounds from "while (GetTextWidth(temp, font) <= width)" to "while (GetTextWidth(temp, font) < width)".  Like I said before, I rewrote the function myself (as in, ditched the previous function and started from scratch) several times, so it's a might bit different from yours.  Also this function is now included in my SM, StrAdd (previously String Additions).  Which reminds me that I need to upload a new version.  I found a problem in one of the two functions I didn't test thoroughly...

Scorpiorus

Glad it's sorted out. :)

I just gave it a little test to see what can be wrong and it appears that the AGS editor does a check: GetTextWidth(...) <= width while the engine does: GetTextWidth(...) < width. Or something similar.

To test I made a label (width=68, font=0) and set its text to "______ ______".

The editor didn't push the text but when I run the game it was pushed like this:
______
______

It's a minor inconsistency though.

monkey0506

I had already discussed this earlier with Chris, and he told me that the wrapping of labels isn't defined and changing it now could have undesirable results or something to that effect.  Basically if the text on a label has a width greater than or equal to the width of the label when displayed in the specified font it will be pushed/wrapped.

Scorpiorus

QuoteBasically if the text on a label has a width greater than or equal to the width of the label when displayed in the specified font it will be pushed/wrapped.
Yeah, that's how the engine does it, the editor (GUIs pane), on the other hand, allows having a text of the same width as the label itself without pushing the tail to the next line. Logically, the editor is more correct here since if the text fits in a given width (even when text.width==label.width) then the text shouldn't be pushed but I appreciate that changing it now may lead to problems with running games made for older versions of AGS. Besides, as I said before, it's not a big deal.

SMF spam blocked by CleanTalk