![]() |
|
Text Wrapping in Allegro |
cadatoiva
Member #7,074
March 2006
|
Is there anything in the allegro libraries the allows text to be drawn within a specified box? I just spent three weeks developing my own class that uses strings to draw, but I would like to know if there was an easier way.:'( |
miran
Member #2,407
June 2002
|
Quote: Is there anything in the allegro libraries the allows text to be drawn within a specified box? Yes. Take a look at these: text_length() text_height() textout() textprintf() There are more functions like that, for working with strings, copying, splitting, finding delimiters, etc. All in the manual... -- |
cadatoiva
Member #7,074
March 2006
|
But is there something like That is what I am looking for. |
miran
Member #2,407
June 2002
|
Not until your write it. You might find it if you search the forums though. This has probably been asked a few times before. -- |
Evert
Member #794
November 2000
![]() |
You can achieve the same effect by adjusting the clipping rectangle of the bitmap or by using a subbitmap. |
miran
Member #2,407
June 2002
|
Adjusting the clipping rectangle turns word wrapping on in Allegro? Wow, I didn't know that! -- |
Evert
Member #794
November 2000
![]() |
No, but it keeps the text from flowing out of the specified region. One way to do it, using only plain Allegro functions, is by using the d_text_proc function. This can be a bit messy and hackish, but it can be done. |
Kitty Cat
Member #2,815
October 2002
![]() |
This might work... void draw_wrapping_text(BITMAP *bmp, FONT *font, const char *str, int x, int y, int w, int h, int color) { DIALOG d = { d_text_proc, x, y, w, h, color, 0/*unused?*/, 0, 0, 0, 0, (void*)str, (void*)font, NULL }; BITMAP *old_bmp = gui_get_screen(); gui_set_screen(bmp); d.proc(MSG_START, &d, 0); d.proc(MSG_DRAW, &d, 0); d.proc(MSG_END, &d, 0); gui_set_screen(old_bmp); }
-- |
Andrei Ellman
Member #3,434
April 2003
|
In addition to the functions that Miran pointed out, you would need a function for finding the length of each character. Unfortunately, the only way you can do this in the Allegro public API is by converting each character into a string (copying it to a buffer that is followed by a terminating \0) and using text_length() on the string. However, the internal API has a char_length() method for the font, which will come in useful as we need to measure each character. To make use if it, add the line #include <allegro/internal/aintern.h> to the file where the multiline text-out code is stored. It just so happens that I've written some code to do just that, so I thought I'd share it (see attatchment). The code can handle unicode characters (although this is currently untested). Use the function aeGetNumTextLinesWithLengthLimit() to get the number of lines that the rendered text will take up, and aeTextoutMultiline() to actually render the text. The code is well commented (it even uses Doxygen-style comments so it can automatically generate docs if passed through Doxygen). There are still a few things I could do to improve the code. Currently, the code uses a static buffer for the output of each line. This is determined by AEMULTILINEBUFSIZE (currently 512). Also, the code does not do tabs or hyphens, and the helper-function aeAdvanceToStartOfCurrentLineandGetNextLine() could be split into two separate functions. Anyway, let me know if this is what you're after. AE. -- |
Fladimir da Gorf
Member #1,565
October 2001
![]() |
Easiest way: Download OpenLayer and turn on word wrapping. It even allows for several text alignments, like centered or justified text. Also line breaks inside text are supported. OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori) |
Andrei Ellman
Member #3,434
April 2003
|
Fladimir da Gorf said: Also line breaks inside text are supported. See edit to my previous post. AE. -- |
Johan Halmén
Member #1,550
September 2001
|
tfm said: int d_textbox_proc(int msg, DIALOG *d, int c); A text box object. The dp field points to the text which is to be displayed in the box. If the text is long, there will be a vertical scrollbar on the right hand side of the object which can be used to scroll through the text. The default is to print the text with word wrapping, but if the D_SELECTED flag is set, the text will be printed with character wrapping. The d1 field is used internally to store the number of lines of text, and d2 is used to store how far it has scrolled through the text. I would use this one. I would create my text box function, which would create a simple Allegro dialog with only one item, d_my_textbox_proc(), which would call d_textbox_proc() with the proper parameters and then return D_CLOSE. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Years of thorough research have revealed that what people find beautiful about the Mandelbrot set is not the set itself, but all the rest. |
Fladimir da Gorf
Member #1,565
October 2001
![]() |
Quote: aeAdvanceToStartOfCurrentLineandGetNextLine
OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori) |
Johan Halmén
Member #1,550
September 2001
|
I tried the auto-complete thing on all my projects, but it didn't work. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Years of thorough research have revealed that what people find beautiful about the Mandelbrot set is not the set itself, but all the rest. |
ImLeftFooted
Member #3,935
October 2003
![]() |
Quote: One way to do it, using only plain Allegro functions, is by using the d_text_proc function. This can be a bit messy and hackish, but it can be done. Yeah I've done this before. You have to use an internal function that d_text_proc uses and hack it a bit and then you can kind of use it to do it. Its all very messy and hacky though, probably only a little bit harder and way cleaner to just write your own word wrapping method. I have one laying around somewhere, maybe I'll come back and paste it sometime if I can find the thing. [edit]
|
Johan Halmén
Member #1,550
September 2001
|
My idea wouldn't be very ugly hacking. Inside this function: ...I'd create a DIALOG, DIALOG *dlg[] = { { d_mytextbox_proc, x, y, width, height, color, bgcolor, -1, D_EXIT, 0, 0, str, NULL, NULL }, { NULL, 0, // etc }; ...then I'd run it. d_mytextbox_proc would do the following: int d_mytextbox_proc(int msg, DIALOG *d, int c) { int hlp; hlp = d_textbox_proc(msg, d, c); if (msg == MSG_DRAW && hlp == D_O_K) return D_CLOSE; return hlp; } That is, it should in all aspects behave like d_textbox_proc, but as soon as it has been drawn, it closes the dialog, leaving the drawn textbox on the screen. I haven't tested that, but the idea should work. You get your text box sith word wrapped text. You need the background colour parameter, too. If your text doesn't fit in the given box size, you get automatic scrollbars, but you can't use them. If you want usable scrollbars, you simply have to do the whole thing as a dialog. What I don't have there is a way to draw to bmp instead of screen, which is the Allegro dialog system's standard output. I haven't tested it but I guess one could start with:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Years of thorough research have revealed that what people find beautiful about the Mandelbrot set is not the set itself, but all the rest. |
Evert
Member #794
November 2000
![]() |
Quote: What I don't have there is a way to draw to bmp instead of screen, which is the Allegro dialog system's standard output. I haven't tested it but I guess one could start with:
Yeach. |
Kitty Cat
Member #2,815
October 2002
![]() |
Quote:
My idea wouldn't be very ugly hacking. Inside this function: ...then I'd run it.
Which is basically what my function does, just a lot cleaner and more straight-forward. -- |
ImLeftFooted
Member #3,935
October 2003
![]() |
You'll proably want to be able to scroll the box up and down. |
Andrei Ellman
Member #3,434
April 2003
|
If you're not using Allegro's GUI for anything else than drawing wrapped text, then doing so will bloat your program. Use my solution instead, and keep your EXEs small. AE. -- |
Mae Mutts
Member #3,766
August 2003
![]() |
What I did to accomplish this was to create a class that understood simple markups. The way it worked was you passed the class your modifiers: Then, you could pass it your display string, with markups, and it would return you a transparent BITMAP with your text. I think that is your best solution. I coded for center, left, right, bold, underline, and italic markups. For the bold/underline/italic markups, you will need to create a "Smart" Font library that can correctly upgrade your base font to the appropriate style based on the markups. Good luck! Mae |
cadatoiva
Member #7,074
March 2006
|
All of your ideas really helped. My Text Wrapping functions weren't as good as I thought they were. I think that Andrei's idea was best and will use it. But I have one question, how does nMaxLength (width of each line?) and npMaxLineLength(number of lines to draw?) work?;D |
Andrei Ellman
Member #3,434
April 2003
|
nMaxLength is the maximum length you are permitting your line to be (although this will be exceded if one line consists of only one character who'se width is greater than nMaxLength). npMaxLineLength is a running count of the longest length we have so far. This is useful so we can find out the actual length of the longest line that will be printed. Often, this is shorter than nMaxLength, so we may want to shrink the horizontal size of the text-area to take this into account. aeGetNumTextLinesWithLengthLimit() and aeTextoutMultiline() both update the value pointed to by the npMaxLineLength paramater (although in practice, you will usually end up passing in NULL to aeTextoutMultiline()). Note that npMaxLineLength is optional, and you can pass in NULL if you don't want to print your text as compactly as possible. Below is an example of the usage of the code.
note: this code is untested The two strings will be printed. Both strings will have the same right-most border when they are justified. If the longest line-length is shorter than the maximum line-length, then the right-most border will be moved to the left to make the string more compact. AE. -- |
Fladimir da Gorf
Member #1,565
October 2001
![]() |
Quote: Below is an example of the usage of the code.
What about just implementing a print( font, text, width, alignment ) -function? OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori) |
Andrei Ellman
Member #3,434
April 2003
|
Quote: What about just implementing a print( font, text, width, alignment ) -function? You can do that with aeTextoutMultiline(bitmapdest, text, font, x, y, fgcol, bgcol, width, NULL); The only reason why you need all the rest of the code in my example is if you want to find out how long the longest line is going to be and adjust the right-boundry accordingly. My code lacs the ability to set the alignment (the text always justified, except for the last line before each newline or \0 which are left-aligned). AE. -- |
|