added line wrapping to table
This commit is contained in:
parent
303179865d
commit
5afad2ca07
@ -108,21 +108,34 @@ class TableCellRenderer(Box):
|
||||
return None # Cell rendering is done directly on the page
|
||||
|
||||
def _render_cell_content(self, x: int, y: int, width: int, height: int):
|
||||
"""Render the content inside the cell (text and images)."""
|
||||
from PIL import ImageFont
|
||||
"""Render the content inside the cell (text and images) with line wrapping."""
|
||||
from pyWebLayout.concrete.text import Line, Text
|
||||
from pyWebLayout.style.fonts import Font
|
||||
from pyWebLayout.style import FontWeight, Alignment
|
||||
|
||||
current_y = y + 2
|
||||
available_height = height - 4 # Account for top/bottom padding
|
||||
|
||||
# Get font
|
||||
try:
|
||||
if self._is_header_section and self._style.header_text_bold:
|
||||
font = ImageFont.truetype(
|
||||
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 12)
|
||||
else:
|
||||
font = ImageFont.truetype(
|
||||
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 12)
|
||||
except BaseException:
|
||||
font = ImageFont.load_default()
|
||||
# Create font for the cell
|
||||
font_size = 12
|
||||
font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
|
||||
if self._is_header_section and self._style.header_text_bold:
|
||||
font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"
|
||||
|
||||
font = Font(
|
||||
font_path=font_path,
|
||||
font_size=font_size,
|
||||
weight=FontWeight.BOLD if self._is_header_section and self._style.header_text_bold else FontWeight.NORMAL
|
||||
)
|
||||
|
||||
# Word spacing constraints (min, max)
|
||||
min_spacing = int(font_size * 0.25)
|
||||
max_spacing = int(font_size * 0.5)
|
||||
word_spacing = (min_spacing, max_spacing)
|
||||
|
||||
# Line height (baseline spacing)
|
||||
line_height = font_size + 4
|
||||
ascent, descent = font.font.getmetrics()
|
||||
|
||||
# Render each block in the cell
|
||||
for block in self._cell.blocks():
|
||||
@ -131,38 +144,83 @@ class TableCellRenderer(Box):
|
||||
current_y = self._render_image_in_cell(
|
||||
block, x, current_y, width, height - (current_y - y))
|
||||
elif isinstance(block, (Paragraph, Heading)):
|
||||
# Extract and render text
|
||||
words = []
|
||||
# Get words from the block
|
||||
word_items = block.words() if callable(block.words) else block.words
|
||||
for word in word_items:
|
||||
if hasattr(word, 'text'):
|
||||
words.append(word.text)
|
||||
elif isinstance(word, tuple) and len(word) >= 2:
|
||||
word_obj = word[1]
|
||||
if hasattr(word_obj, 'text'):
|
||||
words.append(word_obj.text)
|
||||
words = list(word_items)
|
||||
|
||||
if words:
|
||||
text = " ".join(words)
|
||||
if current_y <= y + height - 15:
|
||||
self._draw.text((x + 2, current_y), text,
|
||||
fill=(0, 0, 0), font=font)
|
||||
current_y += 16
|
||||
if not words:
|
||||
continue
|
||||
|
||||
# Layout words using Line objects with wrapping
|
||||
word_index = 0
|
||||
pretext = None
|
||||
|
||||
while word_index < len(words):
|
||||
# Check if we have space for another line
|
||||
if current_y + ascent + descent > y + available_height:
|
||||
break # No more space in cell
|
||||
|
||||
# Create a new line
|
||||
line = Line(
|
||||
spacing=word_spacing,
|
||||
origin=(x + 2, current_y),
|
||||
size=(width - 4, line_height),
|
||||
draw=self._draw,
|
||||
font=font,
|
||||
halign=Alignment.LEFT
|
||||
)
|
||||
|
||||
# Add words to this line until it's full
|
||||
line_has_content = False
|
||||
while word_index < len(words):
|
||||
word = words[word_index]
|
||||
|
||||
# Handle word tuples (index, word_obj)
|
||||
if isinstance(word, tuple) and len(word) >= 2:
|
||||
word_obj = word[1]
|
||||
else:
|
||||
word_obj = word
|
||||
|
||||
# Try to add word to line
|
||||
success, overflow = line.add_word(word_obj, pretext)
|
||||
pretext = None # Clear pretext after use
|
||||
|
||||
if success:
|
||||
line_has_content = True
|
||||
if overflow:
|
||||
# Word was hyphenated, carry over to next line
|
||||
pretext = overflow
|
||||
word_index += 1
|
||||
else:
|
||||
# Word doesn't fit on this line
|
||||
if not line_has_content:
|
||||
# Even first word doesn't fit, force it anyway to avoid infinite loop
|
||||
word_index += 1
|
||||
break
|
||||
|
||||
# Render the line if it has content
|
||||
if line_has_content or len(line.text_objects) > 0:
|
||||
line.render()
|
||||
current_y += line_height
|
||||
|
||||
if current_y > y + height - 10: # Don't overflow cell
|
||||
break
|
||||
|
||||
# If no structured content, try to get any text representation
|
||||
if current_y == y + 2 and hasattr(self._cell, '_text_content'):
|
||||
# Use simple text rendering for fallback case
|
||||
from PIL import ImageFont
|
||||
try:
|
||||
pil_font = ImageFont.truetype(font_path, font_size)
|
||||
except BaseException:
|
||||
pil_font = ImageFont.load_default()
|
||||
|
||||
self._draw.text(
|
||||
(x + 2,
|
||||
current_y),
|
||||
(x + 2, current_y),
|
||||
self._cell._text_content,
|
||||
fill=(
|
||||
0,
|
||||
0,
|
||||
0),
|
||||
font=font)
|
||||
fill=(0, 0, 0),
|
||||
font=pil_font
|
||||
)
|
||||
|
||||
def _render_image_in_cell(self, image_block: AbstractImage, x: int, y: int,
|
||||
max_width: int, max_height: int) -> int:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user