[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[pygame] Rendering Text By Line



> 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:]