Word Wrap - Simple Version #1

BlitzMax Forums/BlitzMax Programming/Word Wrap - Simple Version #1

Shortwind(Posted 2009) [#1]
Since I haven't seen any code on the forums for this type of routine that actually works, here is a good word wrap routine that works, and works well.

Version #1 can easily be adapted to most any type of application.

This code is released into Public Domain.

If anyone finds any bugs or gotch-ya's! please let me know either here, or by email.

Have fun,
Shortwind

SuperStrict

Local a:String="This string is very long and we (x+y=34*sqr(z)/cos(r)*pi+(x*y)/87) will test various length texts."+..
	"  To test these functions for proper goodness is the stuff of dreams.  And "+..
	"the dreams are (x+y=34*sqr(z)/cos(r)*pi+(x*y)/87) here and not there.  But what if the dreams and here"+..
	" and not there?  Well, if the first and second part are not in the third part then the third part is "+..
	"not the circle of the square.  But sometimes things are not as they seem.  Even though the seem is there,"+..
	"it may not be there when we look into the seemingly endlessness of space and time...  Oh, but there is"+..
	"no time like the present even though there is no present in the time of the timeness that is time."

Local boxwidth:Int=20

DoMyWrap(a,boxwidth)
End

'------------------Start of Function ----------------------------
Function DoMyWrap(a:String, width:Int)
	Local s:Int, e:Int
	
	s=1
	e=width
	
	While s<Len(a)
		If Len(a)<e Then
			Print a
			Exit
		ElseIf s+e>=Len(a) Then
			Print Mid(a,s)
			Exit
		End If
		
		While Mid(a,s+e,1)<>" " And e>0
			e=e-1
		Wend
		
		If e=0 Then
			Print Mid(a,s,width)
			s=s+width
			e=width
		Else
			Print Mid(a,s,e)
			s=s+e+1
			e=width
		End If
	Wend

End Function



markcw(Posted 2009) [#2]
They have a place for folks like you... it's called the Code Archives. Muhahaha!

Here is the Algorithm section, just click on the "Add to..." link at the top.
http://www.blitzbasic.com/codearcs/codearcs.php?cat=6


CS_TBL(Posted 2009) [#3]
It'd be more practical to return a word wrapped string. Then everyone can decide whether to print to the console (which I only use for debugging) or to do something else with it (draw into a canvas?)..


_Skully(Posted 2009) [#4]
This one peels the lines out of the original text and passes the lines back as wrapped strings.


Local a:String="This string is very long and we (x+y=34*sqr(z)/cos(r)*pi+(x*y)/87) will test various length texts."+..
	"  To test these functions for proper goodness is the stuff of dreams.  And "+..
	"the dreams are (x+y=34*sqr(z)/cos(r)*pi+(x*y)/87) here and not there.  But what if the dreams and here"+..
	" and not there?  Well, if the first and second part are not in the third part then the third part is "+..
	"not the circle of the square.  But sometimes things are not as they seem.  Even though the seem is there,"+..
	"it may not be there when we look into the seemingly endlessness of space and time...  Oh, but there is"+..
	"no time like the present even though there is no present in the time of the timeness that is time."

Local display:String=a
Repeat
	Local txt:String=Wrapper(display,30)
	Print txt
Until txt=""

Function Wrapper:String(text:String Var,width:Int)
	Local result:String
	If Len(text)>width
		Local spotcheck:Int=width
		Local char:String
		Repeat
			spotcheck:-1
			char=Mid(text,spotcheck,1)
		Until char=" " Or spotcheck=0
		If spotcheck=0
			' no breaks
			result=Left(text,width)
			text=Right(text,Len(text)-width)
		Else
			result=Left(text,spotcheck-1)
			text=Right(text,Len(text)-spotcheck)
		End If
	Else
		result=text
		text=""
	End If
	Return result
End Function



Shortwind(Posted 2009) [#5]
@CS_TBL, I did say:

Version #1 can easily be adapted... (LOL)

@_Skully, Impressive, but I actually found a design flaw in your code, and my own. (Plus, in the current configuration of your code, mine and yours don't print the same. Yours seems to be breaking on a space early or something.... Run them side by side and you'll see what I mean.)

Anyway...

It's a matter of astectics I suppose, but in the very beginning of the example string, when it reaches the long word that will not fit on the line, it should not make a new line, but print what it can on the current line, and then continue. Currently both our code doesn't do this.

An example: (Here is how it works now....)
This string is very long and
we
(x+y=34*sqr(z)/cos(r)*pi+(x*y)
/87) will test various length
...

But it probably should be like this...

This string is very long and
we (x+y=34*sqr(z)/cos(r)*pi+(x
*y)/87) will test various length
...

This isn't really a big deal, it just looks funny when it is displayed.
I suppose there should be a look-ahead to see if the non-spaced-word is longer then the current window size. Or maybe there is an easier way. :O

:)


Shortwind(Posted 2009) [#6]
LOL. OH! MY! GOD! LOL

Now my brain hurts trying to get this thing fixed. ha hah aha ha...


CS_TBL(Posted 2009) [#7]
Version #1 can easily be adapted... (LOL)


Yes, that's why I launched the string-return suggestion, so that someone could implement it! :P


GfK(Posted 2009) [#8]
Just written text-wrapping code myself. Its heavily integrated into my bitmap font class so I can't really post any of it right now.

Basically I have a function which chops a long line of text up into lines of no more than X pixels wide. It first cuts the text into individual words, and measures the pixel width of each.

Then, it starts to build lines of text by adding words. If it can add the next word without the total width of the current line exceeding X pixels, it does so. If not, it puts the current line into a TList and starts a new one. It continues doing this until no words are left to add.

Finally, I convert the TList to an array (I need it this way for what I'm doing - you wouldn't *have* to), and return the array to the main program.

I can then draw the text any time I want without having to recalculate it all every time. The only time I would need to recalculate it from the original text, is if I wanted to change the font size, or the font itself. But I never need to do this anyway.


_Skully(Posted 2009) [#9]
{edit} oops.. posted messed code lol


-Rick-(Posted 2014) [#10]
I know this thread is a few years out of date, but I ran across it while trying to find a simple word wrap, but I don't use BlitzMax so rewrote this to run in simple .bb format.

It does have one glaring problem, however. If any 1 "word" is larger than the width value then it crashes to error.

Thanks for the original code! It really helped me for what I'm working on.

a$ = "This string is very long and we (x+y=34*sqr(z)/cos(r)*pi+(x*y)/87) will test various length texts."
a = a + "  To test these functions for proper goodness is the stuff of dreams.  And "
a = a +	"the dreams are (x+y=34*sqr(z)/cos(r)*pi+(x*y)/87) here and not there.  But what if the dreams and here"
a = a +	" and not there?  Well, if the first and second part are not in the third part then the third part is "
a = a +	"not the circle of the square.  But sometimes things are not as they seem.  Even though the seem is there,"
a = a +	"it may not be there when we look into the seemingly endlessness of space and time...  Oh, but there is"
a = a +	"no time like the present even though there is no present in the time of the timeness that is time."

;BEGIN
Wrapper(a,40)
WaitKey()           
End
;END PROGRAM

Function Wrapper$(Var$,width)
	While Var <> ""
		result$ = ""
	;if length of string is greater than our width
		If Len(Var) > width
			spotcheck = width
			char$ = ""
		;Look for the last space in our next 'width chunk' of the MasterText
			Repeat
				spotcheck = spotcheck - 1
				char = Mid(Var,spotcheck,1)
			Until char = " " Or spotcheck = 0
		;didn't find a space
			If spotcheck = 0
				result = Left(Var,width)
				Var = Right(Var,Len(Var) - width)
		;found a space
			Else
				result = Left(Var,spotcheck - 1)
				Var = Right(Var,Len(Var) - spotcheck) 
			EndIf
	;length of string is less than return width so send it all back
		Else
			result=Var
			Var=""
		EndIf
		Print result
	Wend
End Function



-Rick-(Posted 2014) [#11]
LoL. Originally found this with a simple "word wrap" search of the site and didn't even bother to look what forum category it fell under :P

Explains why it was in BlitzMax. But just in case some other .bb guy stumbles along my same path to here I'll leave it unless someone objects.