@@ -5,8 +5,9 @@ from typing import List, Tuple, Optional, Union
|
||||
from pyWebLayout.concrete import Page, Line, Text
|
||||
from pyWebLayout.concrete.image import RenderableImage
|
||||
from pyWebLayout.concrete.functional import LinkText
|
||||
from pyWebLayout.concrete.table import TableRenderer, TableStyle
|
||||
from pyWebLayout.abstract import Paragraph, Word, Link
|
||||
from pyWebLayout.abstract.block import Image as AbstractImage, PageBreak
|
||||
from pyWebLayout.abstract.block import Image as AbstractImage, PageBreak, Table
|
||||
from pyWebLayout.abstract.inline import LinkedWord
|
||||
from pyWebLayout.style.concrete_style import ConcreteStyleRegistry, RenderingContext, StyleResolver
|
||||
from pyWebLayout.style import Font, Alignment
|
||||
@@ -288,14 +289,65 @@ def image_layouter(image: AbstractImage, page: Page, max_width: Optional[int] =
|
||||
return True
|
||||
|
||||
|
||||
def table_layouter(table: Table, page: Page, style: Optional[TableStyle] = None) -> bool:
|
||||
"""
|
||||
Layout a table within a given page.
|
||||
|
||||
This function uses the TableRenderer to render the table at the current
|
||||
page position, advancing the page's y-offset after successful rendering.
|
||||
|
||||
Args:
|
||||
table: The abstract Table object to layout
|
||||
page: The page to layout the table on
|
||||
style: Optional table styling configuration
|
||||
|
||||
Returns:
|
||||
bool: True if table was successfully laid out, False if page ran out of space
|
||||
"""
|
||||
# Calculate available space
|
||||
available_width = page.available_width
|
||||
x_offset = page.border_size
|
||||
y_offset = page._current_y_offset
|
||||
|
||||
# Access page.draw to ensure canvas is initialized
|
||||
draw = page.draw
|
||||
canvas = page._canvas
|
||||
|
||||
# Create table renderer
|
||||
origin = (x_offset, y_offset)
|
||||
renderer = TableRenderer(
|
||||
table=table,
|
||||
origin=origin,
|
||||
available_width=available_width,
|
||||
draw=draw,
|
||||
style=style,
|
||||
canvas=canvas
|
||||
)
|
||||
|
||||
# Check if table fits on current page
|
||||
table_height = renderer.size[1]
|
||||
available_height = page.size[1] - y_offset - page.border_size
|
||||
|
||||
if table_height > available_height:
|
||||
return False
|
||||
|
||||
# Render the table
|
||||
renderer.render()
|
||||
|
||||
# Update page y-offset
|
||||
page._current_y_offset = y_offset + table_height
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class DocumentLayouter:
|
||||
"""
|
||||
Document layouter that orchestrates layout of various abstract elements.
|
||||
|
||||
Delegates to specialized layouters for different content types:
|
||||
- paragraph_layouter for text paragraphs
|
||||
- image_layouter for images (future)
|
||||
- table_layouter for tables (future)
|
||||
- image_layouter for images
|
||||
- table_layouter for tables
|
||||
|
||||
This class acts as a coordinator, managing the overall document flow
|
||||
and page context while delegating specific layout tasks to specialized
|
||||
@@ -305,12 +357,20 @@ class DocumentLayouter:
|
||||
def __init__(self, page: Page):
|
||||
"""
|
||||
Initialize the document layouter with a page.
|
||||
|
||||
|
||||
Args:
|
||||
page: The page to layout content on
|
||||
"""
|
||||
self.page = page
|
||||
self.style_registry = ConcreteStyleRegistry(page.style_resolver)
|
||||
# Create a style resolver if page doesn't have one
|
||||
if hasattr(page, 'style_resolver'):
|
||||
style_resolver = page.style_resolver
|
||||
else:
|
||||
# Create a default rendering context and style resolver
|
||||
from pyWebLayout.style.concrete_style import RenderingContext
|
||||
context = RenderingContext()
|
||||
style_resolver = StyleResolver(context)
|
||||
self.style_registry = ConcreteStyleRegistry(style_resolver)
|
||||
|
||||
def layout_paragraph(self, paragraph: Paragraph, start_word: int = 0,
|
||||
pretext: Optional[Text] = None) -> Tuple[bool, Optional[int], Optional[Text]]:
|
||||
@@ -327,33 +387,46 @@ class DocumentLayouter:
|
||||
"""
|
||||
return paragraph_layouter(paragraph, self.page, start_word, pretext)
|
||||
|
||||
def layout_image(self, image: AbstractImage, max_width: Optional[int] = None,
|
||||
def layout_image(self, image: AbstractImage, max_width: Optional[int] = None,
|
||||
max_height: Optional[int] = None) -> bool:
|
||||
"""
|
||||
Layout an image using the image_layouter.
|
||||
|
||||
|
||||
Args:
|
||||
image: The abstract Image object to layout
|
||||
max_width: Maximum width constraint (defaults to page available width)
|
||||
max_height: Maximum height constraint (defaults to remaining page height)
|
||||
|
||||
|
||||
Returns:
|
||||
bool: True if image was successfully laid out, False if page ran out of space
|
||||
"""
|
||||
return image_layouter(image, self.page, max_width, max_height)
|
||||
|
||||
def layout_document(self, elements: List[Union[Paragraph, AbstractImage]]) -> bool:
|
||||
|
||||
def layout_table(self, table: Table, style: Optional[TableStyle] = None) -> bool:
|
||||
"""
|
||||
Layout a list of abstract elements (paragraphs and images).
|
||||
|
||||
Layout a table using the table_layouter.
|
||||
|
||||
Args:
|
||||
table: The abstract Table object to layout
|
||||
style: Optional table styling configuration
|
||||
|
||||
Returns:
|
||||
bool: True if table was successfully laid out, False if page ran out of space
|
||||
"""
|
||||
return table_layouter(table, self.page, style)
|
||||
|
||||
def layout_document(self, elements: List[Union[Paragraph, AbstractImage, Table]]) -> bool:
|
||||
"""
|
||||
Layout a list of abstract elements (paragraphs, images, and tables).
|
||||
|
||||
This method delegates to specialized layouters based on element type:
|
||||
- Paragraphs are handled by layout_paragraph
|
||||
- Images are handled by layout_image
|
||||
- Tables and other elements can be added in the future
|
||||
|
||||
- Tables are handled by layout_table
|
||||
|
||||
Args:
|
||||
elements: List of abstract elements to layout
|
||||
|
||||
|
||||
Returns:
|
||||
True if all elements were successfully laid out, False otherwise
|
||||
"""
|
||||
@@ -366,6 +439,9 @@ class DocumentLayouter:
|
||||
success = self.layout_image(element)
|
||||
if not success:
|
||||
return False
|
||||
# Future: elif isinstance(element, Table): use table_layouter
|
||||
elif isinstance(element, Table):
|
||||
success = self.layout_table(element)
|
||||
if not success:
|
||||
return False
|
||||
# Future: elif isinstance(element, CodeBlock): use code_layouter
|
||||
return True
|
||||
|
||||
Reference in New Issue
Block a user