Refactor text boxes.
[naja.git] / naja / widgets / text.py
1 import pygame
2
3 from naja.constants import FONT, FONT_SIZE
4 from naja.widgets.base import Widget
5 from naja.resources import resources
6 from naja.utils import convert_colour
7
8
9 class TextWidget(Widget):
10     def __init__(self, pos, text, size=None, fontname=None, fontsize=None,
11                  colour=None):
12         super(TextWidget, self).__init__(pos, size)
13
14         self.text = text
15         self.fontname = fontname or FONT
16         self.fontsize = (fontsize or FONT_SIZE) // 4
17         self.colour = convert_colour(colour or (0, 0, 0))
18
19     def prepare(self):
20         self.font = resources.get_font(self.fontname, self.fontsize)
21         text = self.font.render(self.text, True, self.colour)
22         text_rect = text.get_rect()
23         self.surface = pygame.transform.scale(text, (text_rect.width * 4,
24                                                      text_rect.height * 4))
25         self.size = self.surface.get_rect().size
26
27     def draw(self, surface):
28         surface.blit(self.surface, self.pos)
29
30
31 class TextBoxWidget(TextWidget):
32     def __init__(self, *args, **kwargs):
33         self.padding = kwargs.pop('padding', 5)
34         self.border = kwargs.pop('border', 2)
35         self.bg_colour = convert_colour(kwargs.pop('bg_colour',
36                                                    (255, 255, 255, 192)))
37         self.border_colour = convert_colour(kwargs.pop('border_colour',
38                                                        (0, 0, 0)))
39         self.box_width = kwargs.pop('box_width', 0)
40
41         super(TextBoxWidget, self).__init__(*args, **kwargs)
42
43     def lines(self):
44         if self.box_width != 0:
45             return self._wrapped_lines()
46         else:
47             return self.text.splitlines()
48
49     def _wrapped_lines(self):
50         def words_fit(words):
51             words_line = ' '.join(words)
52             width = self.font.size(words_line)[0]
53             if width < self.box_width:
54                 return True
55             elif len(words) == 1:
56                 Exception("Word %r too long for box." % (words[0],))
57             return False
58
59         for line in self.text.splitlines():
60             current_words = []
61             for word in line.split():
62                 current_words.append(word)
63                 if words_fit(current_words):
64                     continue
65                 else:
66                     yield ' '.join(current_words[:-1])
67                     current_words = current_words[-1:]
68             if current_words and words_fit(current_words):
69                 yield ' '.join(current_words)
70
71     def prepare(self):
72         self.font = resources.get_font(self.fontname, self.fontsize)
73         rendered_lines = []
74         width, height = self.padding, self.padding
75         for line in self.lines():
76             line_surface = self.font.render(line, True, self.colour)
77             line_rect = line_surface.get_rect()
78             line_surface = pygame.transform.scale(
79                 line_surface, (line_rect.width * 2, line_rect.height * 2))
80             line_rect = line_surface.get_rect()
81             rendered_lines.append(line_surface)
82             width = max(width, line_rect.width)
83             height += line_rect.height
84
85         self.surface = pygame.surface.Surface((width, height),
86                                               pygame.locals.SRCALPHA)
87         self.surface.fill(self.bg_colour)
88         self.size = self.surface.get_rect().size
89
90         x, y = self.padding, self.padding
91         for line_surface in rendered_lines:
92             self.surface.blit(line_surface, (x, y))
93             y += line_surface.get_rect().height
94
95     def draw(self, surface):
96         surface.blit(self.surface, self.rect)