mirror of
https://git.lynn.is/Gwen/python-layout.git
synced 2024-01-13 01:31:55 +01:00
107 lines
4 KiB
Python
107 lines
4 KiB
Python
from PIL import ImageDraw, ImageFont
|
|
from . import Layout
|
|
from .internal.textlayouter import TextLayouter
|
|
from .internal.helpers import min_with_none, max_with_none, get_line_height
|
|
from .enums import TextAlign, TextVerticalAlign, TextWrap
|
|
|
|
|
|
class Text(Layout):
|
|
def __init__(
|
|
self,
|
|
|
|
text=None,
|
|
text_align=TextAlign.LEFT,
|
|
vertical_text_align=TextVerticalAlign.TOP,
|
|
text_wrap=TextWrap.NO_WRAP,
|
|
line_spacing=0,
|
|
|
|
**kwargs
|
|
):
|
|
super().__init__(**kwargs)
|
|
self._text_layouter = None
|
|
self._text = text
|
|
self._text_align = text_align
|
|
self._vertical_text_align = vertical_text_align
|
|
self._text_wrap = text_wrap
|
|
self._line_spacing = line_spacing
|
|
|
|
def complete_init(self, container):
|
|
super().complete_init(container)
|
|
if self._is_empty():
|
|
lines = []
|
|
elif isinstance(self._text, list):
|
|
lines = self._text
|
|
else:
|
|
lines = self._text.splitlines()
|
|
self._text_layouter = TextLayouter(lines=lines,
|
|
align=self._text_align,
|
|
vertical_align=self._vertical_text_align,
|
|
wrap=self._text_wrap,
|
|
font=self.get_font(),
|
|
line_height=self._get_line_height_with_spacing())
|
|
|
|
def _is_empty(self):
|
|
return self._text is None or self._text == '' or (isinstance(self._text, list)
|
|
and len(self._text) == 0)
|
|
|
|
def get_min_inner_width(self, max_height=None):
|
|
if self._is_empty():
|
|
width = 0
|
|
else:
|
|
if max_height is not None:
|
|
max_height += self._line_spacing
|
|
width = self._text_layouter.get_dimensions(0, max_height)[0]
|
|
return max_with_none(width, self._min_width)
|
|
|
|
def get_min_inner_height(self, max_width=None):
|
|
if self._is_empty():
|
|
height = 0
|
|
else:
|
|
# no spacing after the last line
|
|
height = self._text_layouter.get_dimensions(max_width, 0)[1] - self._line_spacing
|
|
return max_with_none(height, self._min_height)
|
|
|
|
def get_ideal_inner_dimensions(self, min_width=None, min_height=None, available_width=None, available_height=None):
|
|
available_width = min_with_none(available_width, self._width)
|
|
available_height = min_with_none(available_height, self._height)
|
|
|
|
width, height = self._text_layouter.get_dimensions(available_width, available_height)
|
|
height -= self._line_spacing # no spacing after the last line
|
|
|
|
if self._width is not None:
|
|
width = self._width
|
|
if self._height is not None:
|
|
height = self._height
|
|
|
|
width = max_with_none(width, self._min_width)
|
|
height = max_with_none(height, self._min_height)
|
|
width = min_with_none(width, self._max_width)
|
|
height = min_with_none(height, self._max_height)
|
|
|
|
return width, height
|
|
|
|
def render_content(self, rect):
|
|
image = self.make_canvas()
|
|
d = ImageDraw.Draw(image)
|
|
|
|
x1, y1, x2, y2 = rect
|
|
width, height = x2 - x1 + 1, y2 - y1 + 1
|
|
if self._max_width is not None:
|
|
width = min(width, self._max_width)
|
|
if self._min_width is not None:
|
|
width = max(width, self._min_width)
|
|
if self._max_height is not None:
|
|
height = min(height, self._max_height)
|
|
if self._min_height is not None:
|
|
height = max(height, self._min_height)
|
|
|
|
lines = self._text_layouter.get_lines(width, height)
|
|
color = self.get_fg_color()
|
|
font = self.get_font()
|
|
for posx, posy, text in lines:
|
|
d.text((x1 + posx, y1 + posy), text, font=font, fill=color)
|
|
return image
|
|
|
|
def _get_line_height_with_spacing(self):
|
|
return get_line_height(self.get_font()) + self._line_spacing
|