Word wrap (justify + minimum raggedness) + inner content / change font style

Showcase your libraries, tools and other projects that help your fellow love users.
denismr
Prole
Posts: 7
Joined: Thu Sep 15, 2016 1:24 am

Word wrap (justify + minimum raggedness) + inner content / change font style

Post by denismr »

Hi,

I've written the code for this for my personal use. However, I feel it may be useful for some of you.

What it offers:
  • Paragraph justification with minimum raggedness (it is prettier than just filling a line until it has no space for the next word, then creating a new line. The code minimizes the sum of the squares of the extra empty space of each line);
  • It gives the position and size of each word, so it is easy to track a specific word in order to turn it clickable;
  • Each word is actually an object that has a draw function (big texts are converted automatically), so it is possible to insert figures, different fonts, colors, etc., in the middle of the text. The code includes, as example, a special first letter for the paragraph and a random word of the text is turned blue;
  • Basic control over minimum line height, padding-top and minimum space between words.
Screenshot:
Image

Love file:
https://drive.google.com/open?id=0B1pb1 ... FRiemd3LXc

Enjoy :awesome:

Edit: I'm sill going to improve it. I want to use Ascent, Baseline and Descent information from the fonts, so that changing the font in the middle of the text gets prettier. Anyways...
User avatar
Positive07
Party member
Posts: 1014
Joined: Sun Aug 12, 2012 4:34 pm
Location: Argentina

Re: Word wrap (justify + minimum raggedness) + inner content / change font style

Post by Positive07 »

Awesome! I have a project coming really soon that would work great combined with this!

Two improvements you can make:
  • Getting which character is drawn at a specific point of the screen, say if I ask for the character at 154, 40 and that is the big L in your example then return 1 (the index of the letter), in this way I could for example highlight the letter under the cursor.
  • Getting where a specific character is drawn, say that I want to know where the n character of that blue word is, and I know that is the character number 249 you would give me its x, y, w and height, so I can draw something over it... This may be possible already, I haven't checked
Another thing you could do is put it on Github so other people can check your code, post issues and make changes to it easily
for i, person in ipairs(everybody) do
[tab]if not person.obey then person:setObey(true) end
end
love.system.openURL(github.com/pablomayobre)
denismr
Prole
Posts: 7
Joined: Thu Sep 15, 2016 1:24 am

Re: Word wrap (justify + minimum raggedness) + inner content / change font style

Post by denismr »

Hi. Thank you for your feedback!

This was just a draft code. That's the reason why I avoided publishing it on my github.
I published it here because I thought that somebody could want minimum raggedness (and many people don't know how to code a dynamic programming algorithm).

Anyway, I improved the code a bit.
Before, I was using recursive dynamic programming, and now I'm using iterative. Although I don't believe it will make any difference, in practice.
The code is much more readable, and now I'm using the baseline information so that all text is aligned, even when you change fonts in the middle of the text. The screenshot below shows that.

Image

Regarding your suggestions, although I did not implemented them directly, It's very easy to achieve what you want with the new JoinedWord type. You can see the GrandParagraphStarter as example of use.

The previous link now redirects to the new version of the love file.

Best,

Edit: I also coded the greedy algorithm for line wrap (to compare results). You can use it by calling LineWrap.Greed (I forgot the y) instead of LineWrap(). The cases where the greedy algorithm shows uggly results are rarer than I previously thought. But uggly results with minimum raggedness are even rarer.
fedkanaut
Prole
Posts: 6
Joined: Fri May 27, 2016 4:44 pm

Re: Word wrap (justify + minimum raggedness) + inner content / change font style

Post by fedkanaut »

Looks really neat! I don't see a license in the download, are you going to add one?
denismr
Prole
Posts: 7
Joined: Thu Sep 15, 2016 1:24 am

Re: Word wrap (justify + minimum raggedness) + inner content / change font style

Post by denismr »

fedkanaut wrote:Looks really neat! I don't see a license in the download, are you going to add one?
I kept the license files for the ttf fonts inside the love container (since they're not mine). As for the code, it's public domain. It is just a bunch of draft snippets, after all. I have to rework it almost completely to put it into production.

And I just noticed that I have introduced a bug in the vertical spacing between lines. It's very wrong :death: .
Unfortunately, I'm a bit busy with my work, so that I can't dig into this problem right now. When I do, I'll surely update this topic with the fixed version. But I'm confident that it is an easy-to-fix bug and if someone wants to reuse this code, he/she can fix it without much of a problem.
denismr
Prole
Posts: 7
Joined: Thu Sep 15, 2016 1:24 am

Re: Word wrap (justify + minimum raggedness) + inner content / change font style

Post by denismr »

Ok.. I basically remade everything from scratch, and implemented some nice features.
If you look at the scripts/test.lua, you are going to see this:

Code: Select all

Empty(30)
Justify()
Text
[[
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Nunc semper viverra urna, eget laoreet tortor tincidunt at.
Aenean eget scelerisque mi, ut lacinia ex.
Pellentesque sodales felis at lobortis rhoncus.
Praesent finibus tortor massa, a aliquet nisl consequat a.
]]

NewParagraph 'I'
Color 'HotPink'
Font 'CourierPrimeBig'
Text 'löve'
Font 'Default'
Color 'AntiqueWhite'
Text 'you!'
Center()

NewParagraph 'Come to'
Bold 'the'
Italic 'right'
BoldItalic()
HSV {.3, .8, 1}
Text 'side!'
Right()
And this becomes this:

Image
User avatar
Positive07
Party member
Posts: 1014
Joined: Sun Aug 12, 2012 4:34 pm
Location: Argentina

Re: Word wrap (justify + minimum raggedness) + inner content / change font style

Post by Positive07 »

Okey sir! You impress me A LOT!

Have you thought about the proposals I made before? I suggested both this things because I'm working on a general textarea module that can be plugged to any rendering engine (be it the console, LÖVE or maybe your text) but in order to handle cursors and such there must exist a way to go from the string to the screen and vice-versa.

Anyway your end results look AMAZING! I haven't taken a look at your code yet, I insist this needs to be in Github but well, I can wait
for i, person in ipairs(everybody) do
[tab]if not person.obey then person:setObey(true) end
end
love.system.openURL(github.com/pablomayobre)
User avatar
SiENcE
Party member
Posts: 805
Joined: Thu Jul 24, 2008 2:25 pm
Location: Berlin/Germany
Contact:

Re: Word wrap (justify + minimum raggedness) + inner content / change font style

Post by SiENcE »

A good richtext library without rendering that can be integrated...would be welcome :).
User avatar
zorg
Party member
Posts: 3465
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Word wrap (justify + minimum raggedness) + inner content / change font style

Post by zorg »

How about RtL, or TtB, BtT, or arbitrary writing directions? :3
Oh, also arbitrary glyph rotations.
Who wouldn't want to be able to render Ferengi writing, right? :D
I am being serious. Not about Ferengis, but about the other stuff
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
denismr
Prole
Posts: 7
Joined: Thu Sep 15, 2016 1:24 am

Re: Word wrap (justify + minimum raggedness) + inner content / change font style

Post by denismr »

Before anything else, I'll want to make it clear that I wrote this code for a prototype of a text-based game I intend to make.
Positive07 wrote:Okey sir! You impress me A LOT!

Have you thought about the proposals I made before? I suggested both this things because I'm working on a general textarea module that can be plugged to any rendering engine (be it the console, LÖVE or maybe your text) but in order to handle cursors and such there must exist a way to go from the string to the screen and vice-versa.

Anyway your end results look AMAZING! I haven't taken a look at your code yet, I insist this needs to be in Github but well, I can wait
Hi. Thank you very much :nyu: !
I have thought about what you said.
For each paragraph, there is a list of words. Each word has x and y information. Both are relative to the top-left corner of the paragraph. Similarly, you can easily set an additional list of x information for the divisions between consecutive letters, relatively to the beginning of the word. I previously said that you could draw each letter individually, but this is actually a bad idea, since you would have to worry about kerning and the love api does not give that information directly. There is an easy way that would be something like this:

Code: Select all

local acc = 0
for i = 1, #str do
  acc = acc + font:getWidth(str:sub(1, i))
  divisions[#divisions + 1] = acc
end
That would be enough for what you want inside a word. Other problem, however, would be the spaces between words.
Currently, I don't store that information at all. I completely ignore the spaces in the original text and tokenize the words. This is enough for my objectives. If you just forget about the justification alignment (and assumes it will only have left, center and right alignments), then it would be fairly easy to modify the code. Space character could be treated as a word like any other. The only part that would need special care would be the LineWrap. When it decides to start a new line with the first word being a blank space, it would have to ignore its width (this is valid for both Dynamic Programming and Greedy solutions).

One more thing.. If you want to constantly recompute line wrapping for many paragraphs, perhaps you would have to give up on minimum raggedness. The algorithm to compute this is O(n^2), where n is the number of words in the paragraph. It's is generally cheap (none paragraph is too long to make it slow), but it's not ideal when you are doing it a lot of times. In any case, I don't feel like the visual difference is very noticeable.
SiENcE wrote:A good richtext library without rendering that can be integrated...would be welcome :).
As I'm not really making a text library of any sort, I decided to take the easiest and quickest route, that is just proxying Lua. I load a file and set its environment so that the "global" functions are changing an internal state. This looks good enough for now. I wish I have the time to write down something more robust like a parser/syntactic analysis for a markup language. However, my VIVA is on next Tuesday and I'm bit busy with my work/research right now :death:
zorg wrote:How about RtL, or TtB, BtT, or arbitrary writing directions? :3
Oh, also arbitrary glyph rotations.
Who wouldn't want to be able to render Ferengi writing, right? :D
I am being serious. Not about Ferengis, but about the other stuff
That would be nice, indeed. I have to look at how languages that are written these ways are stored. No previous experience with that, here.
Post Reply

Who is online

Users browsing this forum: No registered users and 0 guests