Adventure Game Studio

AGS Support => Advanced Technical Forum => Topic started by: Rui 'Trovatore' Pires on Tue 06/11/2007 09:10:33

Title: Word-wrapping in ListBoxes [SOLVED]
Post by: Rui 'Trovatore' Pires on Tue 06/11/2007 09:10:33
Quick question:

For several reasons, in my IF template, I've substituted labels for list boxes. Which meant I'd have to find out a way to word-wrap (and to properly display "[" as paragraphs, but that's done, no prob). I did, but I'm not really happy with it.

Basically, when writing to the listbox, I use the following check:

desc.Length*LETTERWIDTH>lstRoomDesc.Width

"desc" is the string passed to the function this is on, i.e., it's the full string. It gets truncated as each line is added to the listbox.

LETTERWIDTH is #defined as 4. It's a guess-timate for the width of the average character in the font I'm using (default font).

lstRoomDesc.Width, as it suggests, is the width of the listbox.

Having a resizeable listbox doesn't make it any easier on myself... anyway.

The character 'i' is one pixel wide. The character 'L' is more than that. I have no idea how many pixels are in ' '. So most often, the line either wraps before reaching the end of the listbox (quite a bit before it does, in fact), or continues a bit past the end of the listbox. Fine-tuning is impossible - the difference between 3 and 4 is quite big, and I'm pretty sure I can't use a float... can I?

Basically, is there a better way to do this? I'm guessing not, but asking never hurt...
Title: Re: Word-wrapping in ListBoxes
Post by: Khris on Tue 06/11/2007 09:29:45
Have you tried using
GetTextWidth(desc.Length, lstRoomDesc.Font) > lstRoomDesc.Width
instead?
Title: Re: Word-wrapping in ListBoxes
Post by: Rui 'Trovatore' Pires on Tue 06/11/2007 18:16:13
...wow. What a great function! Had no idea it was there! Thanks a big bunch!

EDIT - Same for the FONT property. AGS is advancing way too fast for me to keep track.

EDIT 2 - Whoops, not solved after all. Err, I need a little more help, I forgot I had a second line which needs changing.

int lastletter=lstRoomDesc.Width/LETTERWIDTH;

This declares lastletter, which was, hopefully, the last character in the bit of string that fit in the ListBox.

Or something. Tell you the truth, the meaning of whatever code I'm writing eludes me 5 minutes after I find out it works. And I just can't get my brain around what I should change this line to...

BTW, probably not necessary, but here's the whole loop as is:

  while (desc.Length*LETTERWIDTH>lstRoomDesc.Width) { //while (GetTextWidth(desc.Length, lstRoomDesc.Font) > lstRoomDesc.Width) {
    int lastletter=lstRoomDesc.Width/LETTERWIDTH;
    while (desc.Chars[lastletter]!=' ') lastletter--;
    lstRoomDesc.AddItem(desc.Substring(0, lastletter));
    if (lstRoomDesc.Items[lstRoomDesc.ItemCount-1].Contains("[")!=-1) {
      int temp=lstRoomDesc.Items[lstRoomDesc.ItemCount-1].Contains("[")+1;
      lstRoomDesc.Items[lstRoomDesc.ItemCount-1]=lstRoomDesc.Items[lstRoomDesc.ItemCount-1].Substring(0,temp-1);
      desc=desc.Substring(temp, desc.Length-1);
    }
    else desc=desc.Substring(lastletter, desc.Length-1);
  }
Title: Re: Word-wrapping in ListBoxes
Post by: monkey0506 on Tue 06/11/2007 19:45:16
Untested but this might work.

  int i = 0;
  String buffer = "";
  while (i < desc.Length) {
    if (GetTextWidth(buffer.AppendChar(desc.Chars[i]), lstRoomDesc.Font) <= lstRoomDesc.Width) buffer = buffer.AppendChar(desc.Chars[i]);
    else {
      while ((buffer.Contains(" ") != -1) && (buffer.Chars[buffer.Length - 1] != ' ')) {
        buffer = buffer.Truncate(buffer.Length - 1); // since there's no reverse-contains, take off one character at a time
        i--;
        }
      lstRoomDesc.AddItem(buffer);
      i--;
      buffer = "";
      if (lstRoomDesc.Items[lstRoomDesc.ItemCount - 1].Contains("[") != -1) {
        int temp = lstRoomDesc.Items[lstRoomDesc.ItemCount - 1].Contains("[");
        buffer = lstRoomDesc.Items[lstRoomDesc.ItemCount - 1].Substring(temp + 1, lstRoomDesc.Items[lstRoomDesc.ItemCount - 1].Length);
        lstRoomDesc.Items[lstRoomDesc.ItemCount - 1] = lstRoomDesc.Items[lstRoomDesc.ItemCount - 1].Substring(0, temp);
        }
      }
    i++;
    }
  lstRoomDesc.AddItem(buffer);
  if (buffer.Contains("[") != -1) {
    int temp = buffer.Contains("[");
    lstRoomDesc.Items[lstRoomDesc.ItemCount - 1] = buffer.Truncate(temp);
    lstRoomDesc.AddItem(buffer.Substring(temp + 1, buffer.Length));
    }
Title: Re: Word-wrapping in ListBoxes
Post by: Rui 'Trovatore' Pires on Tue 06/11/2007 21:01:03
I have no idea what all that code does, Monkey, and therefore hope I never have to edit it. But it works wonders, wonders, wonders, thanks so muchly!

EDIT - Ok, think I've got it working now. BTW, monkey, I did have to change a little bit of your code.

At the end:

if (buffer.Contains("[") != -1) {
    int temp = buffer.Contains("[");
    lstRoomDesc.Items[lstRoomDesc.ItemCount - 1] = buffer.Truncate(temp);
    lstRoomDesc.AddItem(buffer.Substring(temp + 1, buffer.Length));
    }

...so if contained *2* line breaks in a line that fits within the listbox, the last line breaks would actually show up. But a little change to care of that, I did:

  while (buffer.Contains("[") != -1) {
    int temp = buffer.Contains("[");
    lstRoomDesc.Items[lstRoomDesc.ItemCount - 1] = buffer.Truncate(temp);
    lstRoomDesc.AddItem(buffer.Substring(temp + 1, buffer.Length));
    buffer=buffer.Substring(temp + 1, buffer.Length);
    }

And I was overreacting before, I did understand what you did... eventually. I'd never have thought of doing it character by character, and then going back to erase what was left over. So - thanks again, to both of you. It seems to be solved.
Title: Re: Word-wrapping in ListBoxes
Post by: monkey0506 on Tue 06/11/2007 23:20:25
Sometimes it might even be faster to seed the buffer like:

int i = desc.Length / 2;
String buffer = desc.Substring(0, i);


Then you could do this:

if (GetTextWidth(buffer.AppendChar(desc.Chars[i]), lstRoomDesc.Font) <= lstRoomDesc.Width) buffer = buffer.AppendChar(desc.Chars[i]);
else while (GetTextWidth(buffer, lstRoomDesc.Font) > lstRoomDesc.Width) {
  buffer = buffer.Truncate(buffer.Length - 1);
  i--;
  }


Glad you got it sorted out though. :)