Getting the width of a justified string?
jmasterx

I would like to add the ability for my textbox to deal with justified. But to do this I would need the width of a string of text when it is justified in order to get the correct caret positioning. Does Allegro 5 provide functions for this? I know I can draw a justified string but I do not know how to get its width.

Thanks

Trezker

Very good question IMO.
I think this feature might be of interest to me some time in the future since I'm a GUI developer.

LennyLen
jmasterx

I'm aware of these functions and use them a lot. However I do not see how they can apply to the width of part of a line which has had an arbitrary number of spaces added to it.

What I meant is something maybe like:

al_get_justfied_text_width(const char* textLine, ALLEGRO_FONT *f, int w, int subStrLen);

Which would return the width that that substring of characters would occupy if that line were justified.

This would allow me to accurately figure out where to position my caret

gnolam

A string should should have exactly the same width regardless of justification. The only difference is the offset, i.e. if it's drawn at x, x - width/2 or x - width.

Dario ff
gnolam said:

A string should should have exactly the same width regardless of justification. The only difference is the offset, i.e. if it's drawn at x, x - width/2 or x - width.

I know correcting gnolam is dangerous, but that sounds more like alignment rather than justfication. :P

All I can think for getting the width of a justified string, is separating the words and getting the width of each of 'em. If the necessary offset between them to cover the whole width is bigger than the offset you set in al_draw_justified_text, you get the normal text width. If it's smaller, then it's as big as x2-x in the first method. At least that's how I think it should work, I haven't worked with those functions too much.

LennyLen

If the string is being fully justified to fit into an area, then it's width should be the width of the area.

edit: I'd set it to whichever is larger out of the width you're justifying to, or the result of al_get_text_width()

edit 2:

Dario ff said:

I know correcting gnolam is dangerous, but that sounds more like alignment rather than justfication

The terms left- and right-justified used to be used extensively to describe what is generally called left- and right-aligned these days. I made the same assumption that gnolam did.

X-G

Text:
This is a short sentence.

Text when justified to 30 characters:
This is a short sentence.

What the OP wants:

This  is  a  short   sentence.
//           ^... the distance from the beginning of the line to here

See?

Trezker

What I thought this was about was getting the position of a character somewhere in the middle of a justified string.
Beaten by X-G.

Nazerith

It's not particularly pretty, but I filled out your function prototype from above:

#SelectExpand
1int al_get_justfied_text_width(const char* textLine, ALLEGRO_FONT *f, int w, int subStrLen) 2{ 3 string fullStr, subStr; 4 int strLength, subLength; 5 int fullSpaces, subSpaces; 6 int justifiedPos; 7 8 fullStr = textLine; 9 subStr = fullStr.substr(0,subStrLen); 10 11 fullSpaces = count(fullStr.begin(), fullStr.end(), ' '); 12 subSpaces = count(subStr.begin(), subStr.end(), ' '); 13 14 strLength = al_get_text_width(f, fullStr.c_str()); 15 subLength = al_get_text_width(f, subStr.c_str()); 16 17 justifiedPos = subLength + (((w-strLength) / fullSpaces) * subSpaces); 18 19 return (justifiedPos); 20}

That will give you the position of something like a cursor at a certain position. It assumes all spaces are set to equal width in order to justify the string to the width passed as 'w'.

Is that what you were looking for? I'm not sure if I totally misunderstood the question here.

Mark Oates

Getting the width of a text render can be an expensive operation, enough that if you fit it in to a box of, say, 500 pixels and it has more than 30 lines, you may see a drop in framerates.

You can curb that by creating a cache representing each line and its text width. Then you would only have to take a speed hit when you need to update the data.

The most flexible method I've come up with so far is to spit the text into words, and have a structure that contains the word and it's width. That way you can freely change the width of your box without a speed cost. Also, changing a single word would only require a change to a word-width pair of a single element. You would need to create your own justify function with this method, but it's not difficult.

However, this method has a few holes, but none that I've had to actually deal with in real applications.

Matthew Leverton

Getting the width of a text render can be an expensive operation, enough that if you fit it in to a box of, say, 500 pixels and it has more than 30 lines, you may see a drop in framerates.

You're doing something wrong. My GUI drops way before that. 8-)

jmasterx said:

Does Allegro 5 provide functions for this?

No. Its text drawing is quite limited, unfortunately. You're probably better off creating your own text justifying routine and keep track of lengths of individual words.

Are you really creating a text box that is justified while typing? That sounds like a weird experience. But I could understand the need for selecting or highlighting justified text.

Mark Oates

You're doing something wrong. My GUI drops way before that. 8-)

:P

Let's see... I did some tests a while back.

Here's an example where the spacing is calculated on each render. The text box is 500px wide, it ends up having about 14 lines.
{"name":"603446","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/0\/802b3d4e31829a226f2a7b35f4f46211.png","w":1075,"h":834,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/0\/802b3d4e31829a226f2a7b35f4f46211"}603446
It looks like the whole operation (User Render) takes about a frame and a half. So you'll get a frame hit at about 10 lines (!!!). :-X

This example already has a pre-calculated word-width set, and words are spaced and rendered each frame. same 500px width, and ends up with about 24 lines:
{"name":"603447","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/3\/2\/32f53e0a2d3e2f06a1e2d71f8b69bf5e.png","w":1075,"h":834,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/3\/2\/32f53e0a2d3e2f06a1e2d71f8b69bf5e"}603447
This one takes only about 1/8 of a frame.

That's a big difference. :-/

Trezker

Those texts aren't even justified, they're just word wrapped.

Mark Oates
Trezker said:

Those texts aren't even justified, they're just word wrapped.

Justification is just a basic calculation on top of that. This is an example of how expensive al_get_text_width() is - an important thing to consider if you're finding points in any text.

Matthew Leverton

Justifying the text would be simple. Just insert extra_space / (word_count - 1) pixels of spacing in between each word.

I haven't written a multiline text widget or display widget yet, but I would basically take a double linked list of pointers to lines. Each line would contain a double linked list of words. Each word would contain its width and spacing information.

From that you'd be able to determine which word the mouse was over. When clicking, you could easily compute the exact character.

Trezker

Yeah, I feel that's probably the proper approach to this problem.

Thread #606465. Printed from Allegro.cc