Accept

Walk back with the blue arrow until we reach the first letter of the word.

lay out text

reset

layout When whole contents isEmpty not Do maxHeight := whole first ascent. maxDescent := whole first descent. missingHeight := 0. whole first pivotBecomes ((whole shape leftAtY 0) , maxHeight) + inset. rule tell whole first successor to 'place'. When Always Do rule tellLater rule to 'showSelection'. rule processActions.

whole contents isEmpty not

maxHeight := whole first ascent. maxDescent := whole first descent. missingHeight := 0. whole first pivotBecomes ((whole shape leftAtY 0) , maxHeight) + inset. rule tell whole first successor to 'place'.

pivotBecomes

leftAtY

tell

to

Always

rule tellLater rule to 'showSelection'. rule processActions.

tellLater

to

Accept

Move that letter to the next line. Resume placing letters to the right of the "o", as indicated by the red arrow. Notice that all letters in the word "over" are placed more than once during the layout.

Noticing going beyond the right margin isClipped is the most important rule for specifying word wrap. It returns true if current letter overlaps the right margin. It does this by comparing the letter's right x-value with the margin's x. The margin can be curved, so we ask the text field box for the margin's actual x value at this y. Containers can have irregular shapes, and line lengths can be different. White space such as a space or a tab are allowed to extend beyond the margin. Return false for white space letters.

sClipped is the most important rule for specifying word wrap. It returns true if current letter overlaps the right margin. It does this by comparing the letter's right x-value with the margin's x. The margin can be curved, so we ask the text field box for the margin's actual x value at this y. Containers can have irregular shapes, and line lengths can be different. White space such as a space or a tab are allowed to extend beyond the margin. Return false for white space letters.

is the most important rule for specifying word wrap. It returns true if current letter overlaps the right margin. It does this by comparing the letter's right x-value with the margin's x. The margin can be curved, so we ask the text field box for the margin's actual x value at this y. Containers can have irregular shapes, and line lengths can be different. White space such as a space or a tab are allowed to extend beyond the margin. Return false for white space letters.

The main problem is to do "word wrap" so that each word is entirely on one line. We don't want half the word at the end of one line and the other half on the next line.

backToWordStart When Always Do letterToMove := self startOfWord me. When self isStartOfLine letterToMove index Do "Word takes entire line, break at the clipped character" letterToMove := me. When Always Do maxHeight := letterToMove ascent. letterToMove pivotYIncreaseBy maxHeight + maxDescent + 2. letterToMove pivotPosition ((whole shape leftAtY letterToMove pivotPosition y) + inset x) , letterToMove pivotPosition y. missingHeight := 0. rule tell letterToMove successor to 'place'.

Always

letterToMove := self startOfWord me.

startOfWord

self isStartOfLine letterToMove index

isStartOfLine

"Word takes entire line, break at the clipped character" letterToMove := me.

Always

maxHeight := letterToMove ascent. letterToMove pivotYIncreaseBy maxHeight + maxDescent + 2. letterToMove pivotPosition ((whole shape leftAtY letterToMove pivotPosition y) + inset x) , letterToMove pivotPosition y. missingHeight := 0. rule tell letterToMove successor to 'place'.

pivotYIncreaseBy

pivotPosition

leftAtY

tell

to

lay out text

To layout the text in the field, place the next letter just to the right of the previous one. The red arrow points to the letter that was just placed, in this case an "r". That letter extends beyond the right margin, so we need to move its entire word to the next line.

place When I amNil Do return me When Always Do my positionBecomes whole width atRandom, whole height atRandom. rule tell my successor to 'place'.

I amNil

return me

Always

my positionBecomes whole width atRandom, whole height atRandom. rule tell my successor to 'place'.

positionBecomes

tell

to

If the walk back (blue arrow) gets all the way to the left margin, a single word covers the entire line. Which letter should be moved to the next line? The original clipped letter (red arrow) is the proper letter to move. A single word that covers the entire line is a special case, and we must test for it.

Text Field Specification

Finding the Start of a Word We know that the current letter hangs over the right margin. We need to move the entire word to the start of the next line. backToWordStart first calls startOfWord, which finds the first letter of the current word. If that letter is already at the start of a line, we should not move it. The line is wider than the field and has no white space in it. The original clipped character should be forced to start a new line. Otherwise, use the start of the word as the letter to be moved. Once we have the proper letter in letterToMove, put it at the start of the next line.

We know that the current letter hangs over the right margin. We need to move the entire word to the start of the next line. backToWordStart first calls startOfWord, which finds the first letter of the current word. If that letter is already at the start of a line, we should not move it. The line is wider than the field and has no white space in it. The original clipped character should be forced to start a new line. Otherwise, use the start of the word as the letter to be moved. Once we have the proper letter in letterToMove, put it at the start of the next line.

We know that the current letter hangs over the right margin. We need to move the entire word to the start of the next line.

ackToWordStart first calls startOfWord, which finds the first letter of the current word. If that letter is already at the start of a line, we should not move it. The line is wider than the field and has no white space in it. The original clipped character should be forced to start a new line. Otherwise, use the start of the word as the letter to be moved. Once we have the proper letter in letterToMove, put it at the start of the next line.

first calls

which finds the first letter of the current word. If that letter is already at the start of a line, we should not move it. The line is wider than the field and has no white space in it. The original clipped character should be forced to start a new line. Otherwise, use the start of the word as the letter to be moved. Once we have the proper letter in letterToMove, put it at the start of the next line.

startOfWord travels back along the word to find the first letter. We are looking for a letter that is not white space. If we happen come to the first letter of the text, return it instead. startOfWord considers just one letter. If that letter is not the start of a word, it calls itself again to consider the preceeding letter.

startOfWord

startOfWord

Is a Letter at the Start of a Line? Finally, we need a little test to tell if the current letter is at the start of a line of text. 'me' is the index of a letter. Return true if the letter is at the left margin. This only works on letters that have been placed.

Finally, we need a little test to tell if the current letter is at the start of a line of text. 'me' is the index of a letter. Return true if the letter is at the left margin. This only works on letters that have been placed.

Finally, we need a little test to tell if the current letter is at the start of a line of text. 'me' is the index of a letter. Return true if the letter is at the left margin. This only works on letters that have been placed.

The main problem is to do "word wrap" so that each word is entirely on one line. We don't want half the word at the end of one line and the other half on the next line.

lay out text

reset

Accept

startOfWord travels back along the word to find the first letter. We are looking for a letter that is not white space. If we happen come to the first letter of the text, return it instead. startOfWord considers just one letter. If that letter is not the start of a word, it calls itself again to consider the preceeding letter.

startOfWord

startOfWord

Accept

The main problem is to do "word wrap" so that each word is entirely on one line. We don't want half the word at the end of one line and the other half on the next line.

Place each letter just to the right of the previous letter on the current line. Then, look for special cases. If the letter follows a carriage return, move it to the next line. (This is done inside placeIfAfterReturn). The letter has the goal of not being clipped by the right margin. When a letter is not white space and finds that it is being clipped, run the backToWordStart rule. It looks backwards to find the start of the current word, and moves that letter to the next line.

Place

placeIfAfterReturn

backToWordStart

Wrapping the Text to a New Line When a line of text is longer than the width of the text field, we want to wrap it to the next line. The goal of text wrapping is to determine where to break the text to start a new line. Each letter follows its prececessor on the current horizontal line. When a letter hangs over the right margin, its entire word needs to be moved to the next line. A carriage return causes the next letter to start a new line. A single word can be wider than entire line. Break it where it touches the right margin. We also need to handle the cases when a letter has no prececessor (it is the first), and has no successor (it is the last). We start with a general layout rule. It moves the first letter to the upper left. Then, it the tells the next letter to place itself in the field. (Ignore the part about maxHeight and missingHeight for the moment.) When each letter is finished being placed, it must tell its successor to place.

When a line of text is longer than the width of the text field, we want to wrap it to the next line. The goal of text wrapping is to determine where to break the text to start a new line. Each letter follows its prececessor on the current horizontal line. When a letter hangs over the right margin, its entire word needs to be moved to the next line. A carriage return causes the next letter to start a new line. A single word can be wider than entire line. Break it where it touches the right margin. We also need to handle the cases when a letter has no prececessor (it is the first), and has no successor (it is the last). We start with a general

When a line of text is longer than the width of the text field, we want to wrap it to the next line. The goal of text wrapping is to determine where to break the text to start a new line. Each letter follows its prececessor on the current horizontal line. When a letter hangs over the right margin, its entire word needs to be moved to the next line. A carriage return causes the next letter to start a new line. A single word can be wider than entire line. Break it where it touches the right margin. We also need to handle the cases when a letter has no prececessor (it is the first), and has no successor (it is the last). We start with a general

ayout rule. It moves the first letter to the upper left. Then, it the tells the next letter to place itself in the field. (Ignore the part about maxHeight and missingHeight for the moment.) When each letter is finished being placed, it must tell its successor to place.

rule. It moves the first letter to the upper left. Then, it the tells the next letter to

itself in the field. (Ignore the part about maxHeight and missingHeight for the moment.) When each letter is finished being placed, it must tell its successor to

.

isStartOfLine When Always Do return (whole at me) pivotPosition x - inset x <=? "left margin" (whole shape leftAtY (whole at me) pivotPosition y)

Always

return (whole at me) pivotPosition x - inset x <=? "left margin" (whole shape leftAtY (whole at me) pivotPosition y)

at

leftAtY

at

Accept

Finding the Start of a Word We know that the current letter hangs over the right margin. We need to move the entire word to the start of the next line. backToWordStart first calls startOfWord, which finds the first letter of the current word. If that letter is already at the start of a line, we should not move it. The line is wider than the field and has no white space in it. The original clipped character should be forced to start a new line. Otherwise, use the start of the word as the letter to be moved. Once we have the proper letter in letterToMove, put it at the start of the next line.

We know that the current letter hangs over the right margin. We need to move the entire word to the start of the next line. backToWordStart first calls startOfWord, which finds the first letter of the current word. If that letter is already at the start of a line, we should not move it. The line is wider than the field and has no white space in it. The original clipped character should be forced to start a new line. Otherwise, use the start of the word as the letter to be moved. Once we have the proper letter in letterToMove, put it at the start of the next line.

We know that the current letter hangs over the right margin. We need to move the entire word to the start of the next line.

ackToWordStart first calls startOfWord, which finds the first letter of the current word. If that letter is already at the start of a line, we should not move it. The line is wider than the field and has no white space in it. The original clipped character should be forced to start a new line. Otherwise, use the start of the word as the letter to be moved. Once we have the proper letter in letterToMove, put it at the start of the next line.

first calls

which finds the first letter of the current word. If that letter is already at the start of a line, we should not move it. The line is wider than the field and has no white space in it. The original clipped character should be forced to start a new line. Otherwise, use the start of the word as the letter to be moved. Once we have the proper letter in letterToMove, put it at the start of the next line.

Is a Letter at the Start of a Line? Finally, we need a little test to tell if the current letter is at the start of a line of text. 'me' is the index of a letter. Return true if the letter is at the left margin. This only works on letters that have been placed.

Finally, we need a little test to tell if the current letter is at the start of a line of text. 'me' is the index of a letter. Return true if the letter is at the left margin. This only works on letters that have been placed.

Finally, we need a little test to tell if the current letter is at the start of a line of text. 'me' is the index of a letter. Return true if the letter is at the left margin. This only works on letters that have been placed.

Accept

placeIfAfterReturn When my predecessor shape notNil and [my predecessor shape isNewline] Do "start of the next line" my pivotPosition 0 , (my predecessor pivotPosition y + maxHeight + maxDescent + 2). my pivotPosition ((whole shape leftAtY my pivotPosition y) + inset x) , my pivotPosition y. maxDescent := my descent. missingHeight := 0. return true. When Always Do return false.

my predecessor shape notNil and [my predecessor shape isNewline]

and

"start of the next line" my pivotPosition 0 , (my predecessor pivotPosition y + maxHeight + maxDescent + 2). my pivotPosition ((whole shape leftAtY my pivotPosition y) + inset x) , my pivotPosition y. maxDescent := my descent. missingHeight := 0. return true.

pivotPosition

pivotPosition

leftAtY

Always

return false.

Accept

Rules The behavior of the letters is defined by a set of rules. Each rule is in a rule editor window. At the top is the name of the rule, followed by the rule itself. The rule has a list of clauses. Each clause has a guard after the When. If the guard is true, then execute the Do part. "return" means evaluate the expression and hand it back to the place where the rule was called. We exit the rule at the return and do not perform the later clauses. Extremely Simple Layout Methods Random Layout As a simple first experiment, we will put each letter in a random place in the text field. Set the x,y position of each letter to a random value within the field's width and height. Press Accept in the rules for layout and place. Press the layout button below. What happens when you press it a second time? Press reset to put all letters at the upper left.

The behavior of the letters is defined by a set of rules. Each rule is in a rule editor window. At the top is the name of the rule, followed by the rule itself. The rule has a list of clauses. Each clause has a guard after the

The behavior of the letters is defined by a set of rules. Each rule is in a rule editor window. At the top is the name of the rule, followed by the rule itself. The rule has a list of clauses. Each clause has a guard after the

hen. If the guard is true, then execute the Do part. "return" means evaluate the expression and hand it back to the place where the rule was called. We exit the rule at the return and do not perform the later clauses.

. If the guard is true, then execute the

part. "return" means evaluate the expression and hand it back to the place where the rule was called. We exit the rule at the return and do not perform the later clauses.

As a simple first experiment, we will put each letter in a random place in the text field. Set the x,y position of each letter to a random value within the field's width and height. Press Accept in the rules for

As a simple first experiment, we will put each letter in a random place in the text field. Set the x,y position of each letter to a random value within the field's width and height. Press Accept in the rules for

ayout and place. Press the layout button below. What happens when you press it a second time? Press reset to put all letters at the upper left.

and

. Press the layout button below. What happens when you press it a second time? Press reset to put all letters at the upper left.

isClipped When my shape isWhiteSpace Do return false. When Always Do return my right + inset x > (whole shape rightAtY my pivotPosition y)

my shape isWhiteSpace

return false.

Always

return my right + inset x > (whole shape rightAtY my pivotPosition y)

rightAtY

place When I amNil Do return me. When Always Do pred := my predecessor. my pivotPosition pred right + pred pivotOffset x , pred pivotPosition y. When rule placeIfAfterReturn me Do return rule tell my successor to 'place'. When rule isClipped me Do rule tell me to 'backToWordStart'. When (rule isClipped me) not Do rule tell my successor to 'place'.

I amNil

return me.

Always

pred := my predecessor. my pivotPosition pred right + pred pivotOffset x , pred pivotPosition y.

pivotPosition

rule placeIfAfterReturn me

placeIfAfterReturn

return rule tell my successor to 'place'.

tell

to

rule isClipped me

isClipped

rule tell me to 'backToWordStart'.

tell

to

(rule isClipped me) not

isClipped

rule tell my successor to 'place'.

tell

to

Noticing a Carriage Return The rule placeIfAfterReturn actually ignores the return character itself. It only takes action when the previous letter is a carriage return. If so, it moves the current letter to the beginning of the next line. placeIfAfterReturn always returns true or false. This allows it to be used in a guard clause. You can see this in the place rule. When placeIfAfterReturn has moved a letter, it returns true, which signals to go on to

The rule

The rule

laceIfAfterReturn actually ignores the return character itself. It only takes action when the previous letter is a carriage return. If so, it moves the current letter to the beginning of the next line. placeIfAfterReturn always returns true or false. This allows it to be used in a guard clause. You can see this in the place rule. When placeIfAfterReturn has moved a letter, it returns true, which signals to go on to

actually ignores the return character itself. It only takes action when the previous letter is a carriage return. If so, it moves the current letter to the beginning of the next line.

always returns true or false. This allows it to be used in a guard clause. You can see this in the

rule. When placeIfAfterReturn has moved a letter, it returns true, which signals to go on to

Text Field Specification

the next letter. For all other letters, it returns false, which signals the place rule to go further and test whether the current letter is over the right margin. maxHeight and missingHeight are used to move the line down when a tall letter is in the middle of the line. We will hook this up later in the essay.

Accept

How to Break the Line of Text

reset

The main problem is to do "word wrap" so that each word is entirely on one line. We don't want half the word at the end of one line and the other half on the next line.

Accept

Text Field Specification

How to Break the Line of Text

To layout the text in the field, place the next letter just to the right of the previous one. The red arrow points to the letter that was just placed, in this case an "r". That letter extends beyond the right margin, so we need to move its entire word to the next line.

Walk back with the blue arrow until we reach the first letter of the word.

Move that letter to the next line. Resume placing letters to the right of the "o", as indicated by the red arrow. Notice that all letters in the word "over" are placed more than once during the layout.

If the walk back (blue arrow) gets all the way to the left margin, a single word covers the entire line. Which letter should be moved to the next line? The original clipped letter (red arrow) is the proper letter to move. A single word that covers the entire line is a special case, and we must test for it.

Wrapping the Text to a New Line When a line of text is longer than the width of the text field, we want to wrap it to the next line. The goal of text wrapping is to determine where to break the text to start a new line. Each letter follows its prececessor on the current horizontal line. When a letter hangs over the right margin, its entire word needs to be moved to the next line. A carriage return causes the next letter to start a new line. A single word can be wider than entire line. Break it where it touches the right margin. We also need to handle the cases when a letter has no prececessor (it is the first), and has no successor (it is the last). We start with a general layout rule. It moves the first letter to the upper left. Then, it the tells the next letter to place itself in the field. (Ignore the part about maxHeight and missingHeight for the moment.) When each letter is finished being placed, it must tell its successor to place.

When a line of text is longer than the width of the text field, we want to wrap it to the next line. The goal of text wrapping is to determine where to break the text to start a new line. Each letter follows its prececessor on the current horizontal line. When a letter hangs over the right margin, its entire word needs to be moved to the next line. A carriage return causes the next letter to start a new line. A single word can be wider than entire line. Break it where it touches the right margin. We also need to handle the cases when a letter has no prececessor (it is the first), and has no successor (it is the last). We start with a general

When a line of text is longer than the width of the text field, we want to wrap it to the next line. The goal of text wrapping is to determine where to break the text to start a new line. Each letter follows its prececessor on the current horizontal line. When a letter hangs over the right margin, its entire word needs to be moved to the next line. A carriage return causes the next letter to start a new line. A single word can be wider than entire line. Break it where it touches the right margin. We also need to handle the cases when a letter has no prececessor (it is the first), and has no successor (it is the last). We start with a general

ayout rule. It moves the first letter to the upper left. Then, it the tells the next letter to place itself in the field. (Ignore the part about maxHeight and missingHeight for the moment.) When each letter is finished being placed, it must tell its successor to place.

rule. It moves the first letter to the upper left. Then, it the tells the next letter to

itself in the field. (Ignore the part about maxHeight and missingHeight for the moment.) When each letter is finished being placed, it must tell its successor to

.

Accept

layout When whole contents isEmpty not Do rule tell whole contents first to 'place'. rule processActions.

whole contents isEmpty not

rule tell whole contents first to 'place'. rule processActions.

tell

to

Text Field Specification

Place each letter just to the right of the previous letter on the current line. Then, look for special cases. If the letter follows a carriage return, move it to the next line. (This is done inside placeIfAfterReturn). The letter has the goal of not being clipped by the right margin. When a letter is not white space and finds that it is being clipped, run the backToWordStart rule. It looks backwards to find the start of the current word, and moves that letter to the next line.

Place

placeIfAfterReturn

backToWordStart

Noticing a Carriage Return The rule placeIfAfterReturn actually ignores the return character itself. It only takes action when the previous letter is a carriage return. If so, it moves the current letter to the beginning of the next line. placeIfAfterReturn always returns true or false. This allows it to be used in a guard clause. You can see this in the place rule. When placeIfAfterReturn has moved a letter, it returns true, which signals to go on to

The rule

The rule

laceIfAfterReturn actually ignores the return character itself. It only takes action when the previous letter is a carriage return. If so, it moves the current letter to the beginning of the next line. placeIfAfterReturn always returns true or false. This allows it to be used in a guard clause. You can see this in the place rule. When placeIfAfterReturn has moved a letter, it returns true, which signals to go on to

actually ignores the return character itself. It only takes action when the previous letter is a carriage return. If so, it moves the current letter to the beginning of the next line.

always returns true or false. This allows it to be used in a guard clause. You can see this in the

rule. When placeIfAfterReturn has moved a letter, it returns true, which signals to go on to

the next letter. For all other letters, it returns false, which signals the place rule to go further and test whether the current letter is over the right margin. maxHeight and missingHeight are used to move the line down when a tall letter is in the middle of the line. We will hook this up later in the essay.

Noticing going beyond the right margin isClipped is the most important rule for specifying word wrap. It returns true if current letter overlaps the right margin. It does this by comparing the letter's right x-value with the margin's x. The margin can be curved, so we ask the text field box for the margin's actual x value at this y. Containers can have irregular shapes, and line lengths can be different. White space such as a space or a tab are allowed to extend beyond the margin. Return false for white space letters.

sClipped is the most important rule for specifying word wrap. It returns true if current letter overlaps the right margin. It does this by comparing the letter's right x-value with the margin's x. The margin can be curved, so we ask the text field box for the margin's actual x value at this y. Containers can have irregular shapes, and line lengths can be different. White space such as a space or a tab are allowed to extend beyond the margin. Return false for white space letters.

is the most important rule for specifying word wrap. It returns true if current letter overlaps the right margin. It does this by comparing the letter's right x-value with the margin's x. The margin can be curved, so we ask the text field box for the margin's actual x value at this y. Containers can have irregular shapes, and line lengths can be different. White space such as a space or a tab are allowed to extend beyond the margin. Return false for white space letters.

All in One Line Now let's redefine place to arrange all letters in one long line. Position each letter just to the right of its predecessor. The one line example inherits the rules of the random layout and overrides the place rule. The line is clipped by the edge of the field.

Now let's redefine

Now let's redefine

lace to arrange all letters in one long line. Position each letter just to the right of its predecessor. The one line example inherits the rules of the random layout and overrides the place rule. The line is clipped by the edge of the field.

to arrange all letters in one long line. Position each letter just to the right of its predecessor. The one line example inherits the rules of the random layout and overrides the

rule. The line is clipped by the edge of the field.

place When I amNil Do return me When my index = 1 Do my position (whole shape leftAtY 0)+4 , 4. return rule tell my successor to 'place'. When Always Do pred := my predecessor. my pivotPosition pred left + pred pivotOffset x + pred width , pred pivotPosition y. rule tell my successor to 'place'.

I amNil

return me

my index = 1

my position (whole shape leftAtY 0)+4 , 4. return rule tell my successor to 'place'.

position

leftAtY

tell

to

Always

pred := my predecessor. my pivotPosition pred left + pred pivotOffset x + pred width , pred pivotPosition y. rule tell my successor to 'place'.

pivotPosition

tell

to

reset

Text Field Specification

Rules The behavior of the letters is defined by a set of rules. Each rule is in a rule editor window. At the top is the name of the rule, followed by the rule itself. The rule has a list of clauses. Each clause has a guard after the When. If the guard is true, then execute the Do part. "return" means evaluate the expression and hand it back to the place where the rule was called. We exit the rule at the return and do not perform the later clauses. Extremely Simple Layout Methods Random Layout As a simple first experiment, we will put each letter in a random place in the text field. Set the x,y position of each letter to a random value within the field's width and height. Press Accept in the rules for layout and place. Press the layout button below. What happens when you press it a second time? Press reset to put all letters at the upper left.

The behavior of the letters is defined by a set of rules. Each rule is in a rule editor window. At the top is the name of the rule, followed by the rule itself. The rule has a list of clauses. Each clause has a guard after the

The behavior of the letters is defined by a set of rules. Each rule is in a rule editor window. At the top is the name of the rule, followed by the rule itself. The rule has a list of clauses. Each clause has a guard after the

hen. If the guard is true, then execute the Do part. "return" means evaluate the expression and hand it back to the place where the rule was called. We exit the rule at the return and do not perform the later clauses.

. If the guard is true, then execute the

part. "return" means evaluate the expression and hand it back to the place where the rule was called. We exit the rule at the return and do not perform the later clauses.

As a simple first experiment, we will put each letter in a random place in the text field. Set the x,y position of each letter to a random value within the field's width and height. Press Accept in the rules for

As a simple first experiment, we will put each letter in a random place in the text field. Set the x,y position of each letter to a random value within the field's width and height. Press Accept in the rules for

ayout and place. Press the layout button below. What happens when you press it a second time? Press reset to put all letters at the upper left.

and

. Press the layout button below. What happens when you press it a second time? Press reset to put all letters at the upper left.

All in One Line Now let's redefine place to arrange all letters in one long line. Position each letter just to the right of its predecessor. The one line example inherits the rules of the random layout and overrides the place rule. The line is clipped by the edge of the field.

Now let's redefine

Now let's redefine

lace to arrange all letters in one long line. Position each letter just to the right of its predecessor. The one line example inherits the rules of the random layout and overrides the place rule. The line is clipped by the edge of the field.

to arrange all letters in one long line. Position each letter just to the right of its predecessor. The one line example inherits the rules of the random layout and overrides the

rule. The line is clipped by the edge of the field.

The main problem is to do "word wrap" so that each word is entirely on one line. We don't want half the word at the end of one line and the other half on the next line.

lay out text

reset

lay out text

reset

The main problem is to do "word wrap" so that each word is entirely on one line. We don't want half the word at the end of one line and the other half on the next line.

startOfWord When my predecessor isNil Do return me. When my predecessor shape isWhiteSpace Do return me. When Always Do return rule startOfWord my predecessor.

my predecessor isNil

return me.

my predecessor shape isWhiteSpace

return me.

Always

return rule startOfWord my predecessor.

startOfWord

lay out text