Re: [pygame] Rendering Text By Line

2007-07-11 Thread space coyote

Or you can do word wrapping according to a specified maximum pixel width. I
made a few functions for this in a project.

Here's the code, its pretty self-explanatory.

def truncline(text, font, maxwidth):
   Truncates a single line of text to given pixel size.
   real=len(text)
   stext=text
   l=font.size(text)[0]
   a=0
   done=1
   while l  maxwidth:
   a=a+1
   stext=text.rsplit(None, a)[0]
   l=font.size(stext)[0]
   real=len(stext)
   done=0
   return real, done, stext

def wrapline(text, font, maxwidth):
   Wraps text line by word by word into multiple lines to fit given
pixel size.
   done=0
   wrapped=[]

   while not done:
   nl, done, stext=truncline(text, font, maxwidth)
   wrapped.append(stext.strip())
   text=text[nl:]
   return wrapped

#This one deals with a list of strings
def wraplines(lines, font, maxwidth):
   Wraps text lines to fit given pixel size.
   wrapped=[]

   if type(lines)==str:
   return wrapline(lines, font, maxwidth)

   for line in lines:
   nline=wrapline(line, font, maxwidth)
   for line in nline:
   wrapped.append(line)

   return wrapped

On 7/10/07, [EMAIL PROTECTED] [EMAIL PROTECTED] wrote:


 It's pretty simple to split your string on carriage returns (and/or line
 feeds), create surfaces for each line of text, and blit those surfaces
to
 the destination surface.

I'm doing something like that. I haven't yet gotten word-wrapping to work,
but the following out-of-context code does wrapping by line. It keeps
track of text sent to a class, and a list of drawing surfaces each
containing one character. When it redraws, it figures out where to place
each letter so that they're in order without overflowing the allowed
drawing area.


def AddText(self,text,newline_at_end=True):
In progress -- adding smooth word breaks.

Adds to a list of drawing surfaces each containing one rendered
letter.

self.dirty = True
text = str(text) ## Ensure format is correct.
if newline_at_end:
text += \n

self.text += text

## Add the text as rendered surfaces, one character at a time.
for letter in text:
if letter == \n:
self.text_letter_surfaces.append(None)
else:
rendered_letter = self.pen.Write(letter)
self.text_letter_surfaces.append(rendered_letter)

def RedrawText(self):
Draws all current letter surfaces, automatically wrapping text
so that text doesn't go outside the allowed area.
self.dirty = False
self.text_surface.fill((0,0,0,0))
letter_locations = []
LEFT_EDGE = 0
RIGHT_EDGE = self.cursor_rightmost_x
NEAR_RIGHT_EDGE = RIGHT_EDGE - 100
cursor = [0,0]

for letter in self.text_letter_surfaces:
newline = False
letter_locations.append((cursor[0],cursor[1]))
if letter: ## Ie. if it's not None (a newline):
## Move the cursor for the next letter.
cursor[0] += letter.get_width()
if cursor[0]  RIGHT_EDGE:
cursor[0] = LEFT_EDGE
newline = True
else: ## This is a newline marker.
cursor[0] = LEFT_EDGE
newline = True

if newline:
cursor[1] += self.spacing_between_lines
if cursor[1] + self.spacing_between_lines 
self.text_surface.get_height():
## Move everything up.
letter_locations =
[[l[0],l[1]-self.spacing_between_lines] for l in
letter_locations]
## Move the cursor back up, too.
cursor[1] -= self.spacing_between_lines

## Now, actually put the letter surfaces onto my drawing surface.
for n in range(len(self.text_letter_surfaces)):
if self.text_letter_surfaces[n]:
self.text_surface.blit(self.text_letter_surfaces
[n],letter_locations[n])

## Clean up: Delete characters that aren't visible, for next time.
top = 0 - self.spacing_between_lines
if letter_locations and letter_locations[0][1] = top:
n = 0
last = len(letter_locations)-1
while letter_locations[n][1] = top and n  last:
n += 1
self.text_letter_surfaces = self.text_letter_surfaces[n:]
self.text = self.text[n:]




[pygame] Rendering Text By Line

2007-07-10 Thread kschnee
 It's pretty simple to split your string on carriage returns (and/or line
 feeds), create surfaces for each line of text, and blit those surfaces to
 the destination surface.

I'm doing something like that. I haven't yet gotten word-wrapping to work,
but the following out-of-context code does wrapping by line. It keeps
track of text sent to a class, and a list of drawing surfaces each
containing one character. When it redraws, it figures out where to place
each letter so that they're in order without overflowing the allowed
drawing area.


def AddText(self,text,newline_at_end=True):
In progress -- adding smooth word breaks.

Adds to a list of drawing surfaces each containing one rendered letter.

self.dirty = True
text = str(text) ## Ensure format is correct.
if newline_at_end:
text += \n

self.text += text

## Add the text as rendered surfaces, one character at a time.
for letter in text:
if letter == \n:
self.text_letter_surfaces.append(None)
else:
rendered_letter = self.pen.Write(letter)
self.text_letter_surfaces.append(rendered_letter)

def RedrawText(self):
Draws all current letter surfaces, automatically wrapping text
so that text doesn't go outside the allowed area.
self.dirty = False
self.text_surface.fill((0,0,0,0))
letter_locations = []
LEFT_EDGE = 0
RIGHT_EDGE = self.cursor_rightmost_x
NEAR_RIGHT_EDGE = RIGHT_EDGE - 100
cursor = [0,0]

for letter in self.text_letter_surfaces:
newline = False
letter_locations.append((cursor[0],cursor[1]))
if letter: ## Ie. if it's not None (a newline):
## Move the cursor for the next letter.
cursor[0] += letter.get_width()
if cursor[0]  RIGHT_EDGE:
cursor[0] = LEFT_EDGE
newline = True
else: ## This is a newline marker.
cursor[0] = LEFT_EDGE
newline = True

if newline:
cursor[1] += self.spacing_between_lines
if cursor[1] + self.spacing_between_lines 
self.text_surface.get_height():
## Move everything up.
letter_locations =
[[l[0],l[1]-self.spacing_between_lines] for l in
letter_locations]
## Move the cursor back up, too.
cursor[1] -= self.spacing_between_lines

## Now, actually put the letter surfaces onto my drawing surface.
for n in range(len(self.text_letter_surfaces)):
if self.text_letter_surfaces[n]:

self.text_surface.blit(self.text_letter_surfaces[n],letter_locations[n])

## Clean up: Delete characters that aren't visible, for next time.
top = 0 - self.spacing_between_lines
if letter_locations and letter_locations[0][1] = top:
n = 0
last = len(letter_locations)-1
while letter_locations[n][1] = top and n  last:
n += 1
self.text_letter_surfaces = self.text_letter_surfaces[n:]
self.text = self.text[n:]