reduced redundant code
This commit is contained in:
parent
23d3278b50
commit
2a543d0319
@ -6,7 +6,7 @@ import urllib.request
|
|||||||
import urllib.parse
|
import urllib.parse
|
||||||
from PIL import Image as PILImage
|
from PIL import Image as PILImage
|
||||||
from .inline import Word, FormattedSpan
|
from .inline import Word, FormattedSpan
|
||||||
from ..core import Hierarchical, Styleable, FontRegistry
|
from ..core import Hierarchical, Styleable, FontRegistry, ContainerAware, BlockContainer
|
||||||
|
|
||||||
|
|
||||||
class BlockType(Enum):
|
class BlockType(Enum):
|
||||||
@ -50,7 +50,7 @@ class Block(Hierarchical):
|
|||||||
return self._block_type
|
return self._block_type
|
||||||
|
|
||||||
|
|
||||||
class Paragraph(Styleable, FontRegistry, Block):
|
class Paragraph(Styleable, FontRegistry, ContainerAware, Block):
|
||||||
"""
|
"""
|
||||||
A paragraph is a block-level element that contains a sequence of words.
|
A paragraph is a block-level element that contains a sequence of words.
|
||||||
|
|
||||||
@ -85,22 +85,15 @@ class Paragraph(Styleable, FontRegistry, Block):
|
|||||||
Raises:
|
Raises:
|
||||||
AttributeError: If the container doesn't have the required add_block method
|
AttributeError: If the container doesn't have the required add_block method
|
||||||
"""
|
"""
|
||||||
# Inherit style from container if not provided
|
# Validate container and inherit style using ContainerAware utilities
|
||||||
if style is None and hasattr(container, 'style'):
|
cls._validate_container(container)
|
||||||
style = container.style
|
style = cls._inherit_style(container, style)
|
||||||
elif style is None and hasattr(container, 'default_style'):
|
|
||||||
style = container.default_style
|
|
||||||
|
|
||||||
# Create the new paragraph
|
# Create the new paragraph
|
||||||
paragraph = cls(style)
|
paragraph = cls(style)
|
||||||
|
|
||||||
# Add the paragraph to the container
|
# Add the paragraph to the container
|
||||||
if hasattr(container, 'add_block'):
|
container.add_block(paragraph)
|
||||||
container.add_block(paragraph)
|
|
||||||
else:
|
|
||||||
raise AttributeError(
|
|
||||||
f"Container {type(container).__name__} must have an 'add_block' method"
|
|
||||||
)
|
|
||||||
|
|
||||||
return paragraph
|
return paragraph
|
||||||
|
|
||||||
@ -237,22 +230,15 @@ class Heading(Paragraph):
|
|||||||
Raises:
|
Raises:
|
||||||
AttributeError: If the container doesn't have the required add_block method
|
AttributeError: If the container doesn't have the required add_block method
|
||||||
"""
|
"""
|
||||||
# Inherit style from container if not provided
|
# Validate container and inherit style using ContainerAware utilities
|
||||||
if style is None and hasattr(container, 'style'):
|
cls._validate_container(container)
|
||||||
style = container.style
|
style = cls._inherit_style(container, style)
|
||||||
elif style is None and hasattr(container, 'default_style'):
|
|
||||||
style = container.default_style
|
|
||||||
|
|
||||||
# Create the new heading
|
# Create the new heading
|
||||||
heading = cls(level, style)
|
heading = cls(level, style)
|
||||||
|
|
||||||
# Add the heading to the container
|
# Add the heading to the container
|
||||||
if hasattr(container, 'add_block'):
|
container.add_block(heading)
|
||||||
container.add_block(heading)
|
|
||||||
else:
|
|
||||||
raise AttributeError(
|
|
||||||
f"Container {type(container).__name__} must have an 'add_block' method"
|
|
||||||
)
|
|
||||||
|
|
||||||
return heading
|
return heading
|
||||||
|
|
||||||
@ -267,7 +253,7 @@ class Heading(Paragraph):
|
|||||||
self._level = level
|
self._level = level
|
||||||
|
|
||||||
|
|
||||||
class Quote(Block):
|
class Quote(BlockContainer, ContainerAware, Block):
|
||||||
"""
|
"""
|
||||||
A blockquote element that can contain other block elements.
|
A blockquote element that can contain other block elements.
|
||||||
"""
|
"""
|
||||||
@ -280,7 +266,6 @@ class Quote(Block):
|
|||||||
style: Optional default style for child blocks
|
style: Optional default style for child blocks
|
||||||
"""
|
"""
|
||||||
super().__init__(BlockType.QUOTE)
|
super().__init__(BlockType.QUOTE)
|
||||||
self._blocks: List[Block] = []
|
|
||||||
self._style = style
|
self._style = style
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -299,22 +284,15 @@ class Quote(Block):
|
|||||||
Raises:
|
Raises:
|
||||||
AttributeError: If the container doesn't have the required add_block method
|
AttributeError: If the container doesn't have the required add_block method
|
||||||
"""
|
"""
|
||||||
# Inherit style from container if not provided
|
# Validate container and inherit style using ContainerAware utilities
|
||||||
if style is None and hasattr(container, 'style'):
|
cls._validate_container(container)
|
||||||
style = container.style
|
style = cls._inherit_style(container, style)
|
||||||
elif style is None and hasattr(container, 'default_style'):
|
|
||||||
style = container.default_style
|
|
||||||
|
|
||||||
# Create the new quote
|
# Create the new quote
|
||||||
quote = cls(style)
|
quote = cls(style)
|
||||||
|
|
||||||
# Add the quote to the container
|
# Add the quote to the container
|
||||||
if hasattr(container, 'add_block'):
|
container.add_block(quote)
|
||||||
container.add_block(quote)
|
|
||||||
else:
|
|
||||||
raise AttributeError(
|
|
||||||
f"Container {type(container).__name__} must have an 'add_block' method"
|
|
||||||
)
|
|
||||||
|
|
||||||
return quote
|
return quote
|
||||||
|
|
||||||
@ -328,54 +306,6 @@ class Quote(Block):
|
|||||||
"""Set the default style for this quote"""
|
"""Set the default style for this quote"""
|
||||||
self._style = style
|
self._style = style
|
||||||
|
|
||||||
def add_block(self, block: Block):
|
|
||||||
"""
|
|
||||||
Add a block element to this quote.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
block: The Block object to add
|
|
||||||
"""
|
|
||||||
self._blocks.append(block)
|
|
||||||
block.parent = self
|
|
||||||
|
|
||||||
def create_paragraph(self, style=None) -> Paragraph:
|
|
||||||
"""
|
|
||||||
Create a new paragraph and add it to this quote.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
style: Optional style override. If None, inherits from quote
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The newly created Paragraph object
|
|
||||||
"""
|
|
||||||
return Paragraph.create_and_add_to(self, style)
|
|
||||||
|
|
||||||
def create_heading(
|
|
||||||
self,
|
|
||||||
level: HeadingLevel = HeadingLevel.H1,
|
|
||||||
style=None) -> Heading:
|
|
||||||
"""
|
|
||||||
Create a new heading and add it to this quote.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
level: The heading level
|
|
||||||
style: Optional style override. If None, inherits from quote
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The newly created Heading object
|
|
||||||
"""
|
|
||||||
return Heading.create_and_add_to(self, level, style)
|
|
||||||
|
|
||||||
def blocks(self) -> Iterator[Block]:
|
|
||||||
"""
|
|
||||||
Iterate over the blocks in this quote.
|
|
||||||
|
|
||||||
Yields:
|
|
||||||
Each Block in the quote
|
|
||||||
"""
|
|
||||||
for block in self._blocks:
|
|
||||||
yield block
|
|
||||||
|
|
||||||
|
|
||||||
class CodeBlock(Block):
|
class CodeBlock(Block):
|
||||||
"""
|
"""
|
||||||
@ -463,7 +393,7 @@ class ListStyle(Enum):
|
|||||||
DEFINITION = 3 # <dl>
|
DEFINITION = 3 # <dl>
|
||||||
|
|
||||||
|
|
||||||
class HList(Block):
|
class HList(ContainerAware, Block):
|
||||||
"""
|
"""
|
||||||
An HTML list element (ul, ol, dl).
|
An HTML list element (ul, ol, dl).
|
||||||
"""
|
"""
|
||||||
@ -502,22 +432,15 @@ class HList(Block):
|
|||||||
Raises:
|
Raises:
|
||||||
AttributeError: If the container doesn't have the required add_block method
|
AttributeError: If the container doesn't have the required add_block method
|
||||||
"""
|
"""
|
||||||
# Inherit style from container if not provided
|
# Validate container and inherit style using ContainerAware utilities
|
||||||
if default_style is None and hasattr(container, 'style'):
|
cls._validate_container(container)
|
||||||
default_style = container.style
|
default_style = cls._inherit_style(container, default_style)
|
||||||
elif default_style is None and hasattr(container, 'default_style'):
|
|
||||||
default_style = container.default_style
|
|
||||||
|
|
||||||
# Create the new list
|
# Create the new list
|
||||||
hlist = cls(style, default_style)
|
hlist = cls(style, default_style)
|
||||||
|
|
||||||
# Add the list to the container
|
# Add the list to the container
|
||||||
if hasattr(container, 'add_block'):
|
container.add_block(hlist)
|
||||||
container.add_block(hlist)
|
|
||||||
else:
|
|
||||||
raise AttributeError(
|
|
||||||
f"Container {type(container).__name__} must have an 'add_block' method"
|
|
||||||
)
|
|
||||||
|
|
||||||
return hlist
|
return hlist
|
||||||
|
|
||||||
@ -580,7 +503,7 @@ class HList(Block):
|
|||||||
return len(self._items)
|
return len(self._items)
|
||||||
|
|
||||||
|
|
||||||
class ListItem(Block):
|
class ListItem(BlockContainer, ContainerAware, Block):
|
||||||
"""
|
"""
|
||||||
A list item element that can contain other block elements.
|
A list item element that can contain other block elements.
|
||||||
"""
|
"""
|
||||||
@ -594,7 +517,6 @@ class ListItem(Block):
|
|||||||
style: Optional default style for child blocks
|
style: Optional default style for child blocks
|
||||||
"""
|
"""
|
||||||
super().__init__(BlockType.LIST_ITEM)
|
super().__init__(BlockType.LIST_ITEM)
|
||||||
self._blocks: List[Block] = []
|
|
||||||
self._term = term
|
self._term = term
|
||||||
self._style = style
|
self._style = style
|
||||||
|
|
||||||
@ -619,22 +541,15 @@ class ListItem(Block):
|
|||||||
Raises:
|
Raises:
|
||||||
AttributeError: If the container doesn't have the required add_item method
|
AttributeError: If the container doesn't have the required add_item method
|
||||||
"""
|
"""
|
||||||
# Inherit style from container if not provided
|
# Validate container and inherit style using ContainerAware utilities
|
||||||
if style is None and hasattr(container, 'default_style'):
|
cls._validate_container(container, required_method='add_item')
|
||||||
style = container.default_style
|
style = cls._inherit_style(container, style)
|
||||||
elif style is None and hasattr(container, 'style'):
|
|
||||||
style = container.style
|
|
||||||
|
|
||||||
# Create the new list item
|
# Create the new list item
|
||||||
item = cls(term, style)
|
item = cls(term, style)
|
||||||
|
|
||||||
# Add the list item to the container
|
# Add the list item to the container
|
||||||
if hasattr(container, 'add_item'):
|
container.add_item(item)
|
||||||
container.add_item(item)
|
|
||||||
else:
|
|
||||||
raise AttributeError(
|
|
||||||
f"Container {type(container).__name__} must have an 'add_item' method"
|
|
||||||
)
|
|
||||||
|
|
||||||
return item
|
return item
|
||||||
|
|
||||||
@ -658,56 +573,8 @@ class ListItem(Block):
|
|||||||
"""Set the default style for this list item"""
|
"""Set the default style for this list item"""
|
||||||
self._style = style
|
self._style = style
|
||||||
|
|
||||||
def add_block(self, block: Block):
|
|
||||||
"""
|
|
||||||
Add a block element to this list item.
|
|
||||||
|
|
||||||
Args:
|
class TableCell(BlockContainer, ContainerAware, Block):
|
||||||
block: The Block object to add
|
|
||||||
"""
|
|
||||||
self._blocks.append(block)
|
|
||||||
block.parent = self
|
|
||||||
|
|
||||||
def create_paragraph(self, style=None) -> Paragraph:
|
|
||||||
"""
|
|
||||||
Create a new paragraph and add it to this list item.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
style: Optional style override. If None, inherits from list item
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The newly created Paragraph object
|
|
||||||
"""
|
|
||||||
return Paragraph.create_and_add_to(self, style)
|
|
||||||
|
|
||||||
def create_heading(
|
|
||||||
self,
|
|
||||||
level: HeadingLevel = HeadingLevel.H1,
|
|
||||||
style=None) -> Heading:
|
|
||||||
"""
|
|
||||||
Create a new heading and add it to this list item.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
level: The heading level
|
|
||||||
style: Optional style override. If None, inherits from list item
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The newly created Heading object
|
|
||||||
"""
|
|
||||||
return Heading.create_and_add_to(self, level, style)
|
|
||||||
|
|
||||||
def blocks(self) -> Iterator[Block]:
|
|
||||||
"""
|
|
||||||
Iterate over the blocks in this list item.
|
|
||||||
|
|
||||||
Yields:
|
|
||||||
Each Block in the list item
|
|
||||||
"""
|
|
||||||
for block in self._blocks:
|
|
||||||
yield block
|
|
||||||
|
|
||||||
|
|
||||||
class TableCell(Block):
|
|
||||||
"""
|
"""
|
||||||
A table cell element that can contain other block elements.
|
A table cell element that can contain other block elements.
|
||||||
"""
|
"""
|
||||||
@ -731,7 +598,6 @@ class TableCell(Block):
|
|||||||
self._is_header = is_header
|
self._is_header = is_header
|
||||||
self._colspan = colspan
|
self._colspan = colspan
|
||||||
self._rowspan = rowspan
|
self._rowspan = rowspan
|
||||||
self._blocks: List[Block] = []
|
|
||||||
self._style = style
|
self._style = style
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -754,20 +620,15 @@ class TableCell(Block):
|
|||||||
Raises:
|
Raises:
|
||||||
AttributeError: If the container doesn't have the required add_cell method
|
AttributeError: If the container doesn't have the required add_cell method
|
||||||
"""
|
"""
|
||||||
# Inherit style from container if not provided
|
# Validate container and inherit style using ContainerAware utilities
|
||||||
if style is None and hasattr(container, 'style'):
|
cls._validate_container(container, required_method='add_cell')
|
||||||
style = container.style
|
style = cls._inherit_style(container, style)
|
||||||
|
|
||||||
# Create the new table cell
|
# Create the new table cell
|
||||||
cell = cls(is_header, colspan, rowspan, style)
|
cell = cls(is_header, colspan, rowspan, style)
|
||||||
|
|
||||||
# Add the cell to the container
|
# Add the cell to the container
|
||||||
if hasattr(container, 'add_cell'):
|
container.add_cell(cell)
|
||||||
container.add_cell(cell)
|
|
||||||
else:
|
|
||||||
raise AttributeError(
|
|
||||||
f"Container {type(container).__name__} must have an 'add_cell' method"
|
|
||||||
)
|
|
||||||
|
|
||||||
return cell
|
return cell
|
||||||
|
|
||||||
@ -811,56 +672,8 @@ class TableCell(Block):
|
|||||||
"""Set the default style for this table cell"""
|
"""Set the default style for this table cell"""
|
||||||
self._style = style
|
self._style = style
|
||||||
|
|
||||||
def add_block(self, block: Block):
|
|
||||||
"""
|
|
||||||
Add a block element to this cell.
|
|
||||||
|
|
||||||
Args:
|
class TableRow(ContainerAware, Block):
|
||||||
block: The Block object to add
|
|
||||||
"""
|
|
||||||
self._blocks.append(block)
|
|
||||||
block.parent = self
|
|
||||||
|
|
||||||
def create_paragraph(self, style=None) -> Paragraph:
|
|
||||||
"""
|
|
||||||
Create a new paragraph and add it to this table cell.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
style: Optional style override. If None, inherits from cell
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The newly created Paragraph object
|
|
||||||
"""
|
|
||||||
return Paragraph.create_and_add_to(self, style)
|
|
||||||
|
|
||||||
def create_heading(
|
|
||||||
self,
|
|
||||||
level: HeadingLevel = HeadingLevel.H1,
|
|
||||||
style=None) -> Heading:
|
|
||||||
"""
|
|
||||||
Create a new heading and add it to this table cell.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
level: The heading level
|
|
||||||
style: Optional style override. If None, inherits from cell
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The newly created Heading object
|
|
||||||
"""
|
|
||||||
return Heading.create_and_add_to(self, level, style)
|
|
||||||
|
|
||||||
def blocks(self) -> Iterator[Block]:
|
|
||||||
"""
|
|
||||||
Iterate over the blocks in this cell.
|
|
||||||
|
|
||||||
Yields:
|
|
||||||
Each Block in the cell
|
|
||||||
"""
|
|
||||||
for block in self._blocks:
|
|
||||||
yield block
|
|
||||||
|
|
||||||
|
|
||||||
class TableRow(Block):
|
|
||||||
"""
|
"""
|
||||||
A table row element containing table cells.
|
A table row element containing table cells.
|
||||||
"""
|
"""
|
||||||
@ -897,20 +710,15 @@ class TableRow(Block):
|
|||||||
Raises:
|
Raises:
|
||||||
AttributeError: If the container doesn't have the required add_row method
|
AttributeError: If the container doesn't have the required add_row method
|
||||||
"""
|
"""
|
||||||
# Inherit style from container if not provided
|
# Validate container and inherit style using ContainerAware utilities
|
||||||
if style is None and hasattr(container, 'style'):
|
cls._validate_container(container, required_method='add_row')
|
||||||
style = container.style
|
style = cls._inherit_style(container, style)
|
||||||
|
|
||||||
# Create the new table row
|
# Create the new table row
|
||||||
row = cls(style)
|
row = cls(style)
|
||||||
|
|
||||||
# Add the row to the container
|
# Add the row to the container
|
||||||
if hasattr(container, 'add_row'):
|
container.add_row(row, section)
|
||||||
container.add_row(row, section)
|
|
||||||
else:
|
|
||||||
raise AttributeError(
|
|
||||||
f"Container {type(container).__name__} must have an 'add_row' method"
|
|
||||||
)
|
|
||||||
|
|
||||||
return row
|
return row
|
||||||
|
|
||||||
@ -970,7 +778,7 @@ class TableRow(Block):
|
|||||||
return len(self._cells)
|
return len(self._cells)
|
||||||
|
|
||||||
|
|
||||||
class Table(Block):
|
class Table(ContainerAware, Block):
|
||||||
"""
|
"""
|
||||||
A table element containing rows and cells.
|
A table element containing rows and cells.
|
||||||
"""
|
"""
|
||||||
@ -1011,22 +819,15 @@ class Table(Block):
|
|||||||
Raises:
|
Raises:
|
||||||
AttributeError: If the container doesn't have the required add_block method
|
AttributeError: If the container doesn't have the required add_block method
|
||||||
"""
|
"""
|
||||||
# Inherit style from container if not provided
|
# Validate container and inherit style using ContainerAware utilities
|
||||||
if style is None and hasattr(container, 'style'):
|
cls._validate_container(container)
|
||||||
style = container.style
|
style = cls._inherit_style(container, style)
|
||||||
elif style is None and hasattr(container, 'default_style'):
|
|
||||||
style = container.default_style
|
|
||||||
|
|
||||||
# Create the new table
|
# Create the new table
|
||||||
table = cls(caption, style)
|
table = cls(caption, style)
|
||||||
|
|
||||||
# Add the table to the container
|
# Add the table to the container
|
||||||
if hasattr(container, 'add_block'):
|
container.add_block(table)
|
||||||
container.add_block(table)
|
|
||||||
else:
|
|
||||||
raise AttributeError(
|
|
||||||
f"Container {type(container).__name__} must have an 'add_block' method"
|
|
||||||
)
|
|
||||||
|
|
||||||
return table
|
return table
|
||||||
|
|
||||||
|
|||||||
@ -190,6 +190,46 @@ class Page(Renderable, Queriable):
|
|||||||
"""Get a copy of the children list"""
|
"""Get a copy of the children list"""
|
||||||
return self._children.copy()
|
return self._children.copy()
|
||||||
|
|
||||||
|
def _get_child_property(self, child: Renderable, private_attr: str,
|
||||||
|
public_attr: str, index: Optional[int] = None,
|
||||||
|
default: Optional[int] = None) -> Optional[int]:
|
||||||
|
"""
|
||||||
|
Generic helper to extract properties from child objects with multiple fallback strategies.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
child: The child object
|
||||||
|
private_attr: Name of the private attribute (e.g., '_size')
|
||||||
|
public_attr: Name of the public property (e.g., 'size')
|
||||||
|
index: Optional index for array-like properties (0 for width, 1 for height)
|
||||||
|
default: Default value if property cannot be determined
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Property value or default
|
||||||
|
"""
|
||||||
|
# Try private attribute first
|
||||||
|
if hasattr(child, private_attr):
|
||||||
|
value = getattr(child, private_attr)
|
||||||
|
if value is not None:
|
||||||
|
if isinstance(value, (list, tuple, np.ndarray)):
|
||||||
|
if index is not None and len(value) > index:
|
||||||
|
return int(value[index])
|
||||||
|
elif index is None:
|
||||||
|
return value
|
||||||
|
|
||||||
|
# Try public property
|
||||||
|
if hasattr(child, public_attr):
|
||||||
|
value = getattr(child, public_attr)
|
||||||
|
if value is not None:
|
||||||
|
if isinstance(value, (list, tuple, np.ndarray)):
|
||||||
|
if index is not None and len(value) > index:
|
||||||
|
return int(value[index])
|
||||||
|
elif index is None:
|
||||||
|
return value
|
||||||
|
else:
|
||||||
|
return int(value)
|
||||||
|
|
||||||
|
return default
|
||||||
|
|
||||||
def _get_child_height(self, child: Renderable) -> int:
|
def _get_child_height(self, child: Renderable) -> int:
|
||||||
"""
|
"""
|
||||||
Get the height of a child object.
|
Get the height of a child object.
|
||||||
@ -200,20 +240,15 @@ class Page(Renderable, Queriable):
|
|||||||
Returns:
|
Returns:
|
||||||
Height in pixels
|
Height in pixels
|
||||||
"""
|
"""
|
||||||
if hasattr(child, '_size') and child._size is not None:
|
# Try to get height from size property (index 1)
|
||||||
if isinstance(
|
height = self._get_child_property(child, '_size', 'size', index=1)
|
||||||
child._size, (list, tuple, np.ndarray)) and len(
|
if height is not None:
|
||||||
child._size) >= 2:
|
return height
|
||||||
return int(child._size[1])
|
|
||||||
|
|
||||||
if hasattr(child, 'size') and child.size is not None:
|
# Try direct height attribute
|
||||||
if isinstance(
|
height = self._get_child_property(child, '_height', 'height')
|
||||||
child.size, (list, tuple, np.ndarray)) and len(
|
if height is not None:
|
||||||
child.size) >= 2:
|
return height
|
||||||
return int(child.size[1])
|
|
||||||
|
|
||||||
if hasattr(child, 'height'):
|
|
||||||
return int(child.height)
|
|
||||||
|
|
||||||
# Default fallback height
|
# Default fallback height
|
||||||
return 20
|
return 20
|
||||||
@ -286,19 +321,12 @@ class Page(Renderable, Queriable):
|
|||||||
Returns:
|
Returns:
|
||||||
Tuple of (x, y) coordinates
|
Tuple of (x, y) coordinates
|
||||||
"""
|
"""
|
||||||
if hasattr(child, '_origin') and child._origin is not None:
|
# Try to get x coordinate
|
||||||
if isinstance(child._origin, np.ndarray):
|
x = self._get_child_property(child, '_origin', 'position', index=0, default=0)
|
||||||
return (int(child._origin[0]), int(child._origin[1]))
|
# Try to get y coordinate
|
||||||
elif isinstance(child._origin, (list, tuple)) and len(child._origin) >= 2:
|
y = self._get_child_property(child, '_origin', 'position', index=1, default=0)
|
||||||
return (int(child._origin[0]), int(child._origin[1]))
|
|
||||||
|
|
||||||
if hasattr(child, 'position'):
|
return (x, y)
|
||||||
pos = child.position
|
|
||||||
if isinstance(pos, (list, tuple)) and len(pos) >= 2:
|
|
||||||
return (int(pos[0]), int(pos[1]))
|
|
||||||
|
|
||||||
# Default to origin
|
|
||||||
return (0, 0)
|
|
||||||
|
|
||||||
def query_point(self, point: Tuple[int, int]) -> Optional[QueryResult]:
|
def query_point(self, point: Tuple[int, int]) -> Optional[QueryResult]:
|
||||||
"""
|
"""
|
||||||
@ -377,20 +405,20 @@ class Page(Renderable, Queriable):
|
|||||||
Returns:
|
Returns:
|
||||||
Tuple of (width, height) or None if size cannot be determined
|
Tuple of (width, height) or None if size cannot be determined
|
||||||
"""
|
"""
|
||||||
if hasattr(child, '_size') and child._size is not None:
|
# Try to get width and height from size property
|
||||||
if isinstance(
|
width = self._get_child_property(child, '_size', 'size', index=0)
|
||||||
child._size, (list, tuple, np.ndarray)) and len(
|
height = self._get_child_property(child, '_size', 'size', index=1)
|
||||||
child._size) >= 2:
|
|
||||||
return (int(child._size[0]), int(child._size[1]))
|
|
||||||
|
|
||||||
if hasattr(child, 'size') and child.size is not None:
|
# If size property worked, return it
|
||||||
if isinstance(
|
if width is not None and height is not None:
|
||||||
child.size, (list, tuple, np.ndarray)) and len(
|
return (width, height)
|
||||||
child.size) >= 2:
|
|
||||||
return (int(child.size[0]), int(child.size[1]))
|
|
||||||
|
|
||||||
if hasattr(child, 'width') and hasattr(child, 'height'):
|
# Try direct width/height attributes
|
||||||
return (int(child.width), int(child.height))
|
width = self._get_child_property(child, '_width', 'width')
|
||||||
|
height = self._get_child_property(child, '_height', 'height')
|
||||||
|
|
||||||
|
if width is not None and height is not None:
|
||||||
|
return (width, height)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@ -331,10 +331,16 @@ class BlockContainer:
|
|||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self._blocks = []
|
self._blocks = []
|
||||||
|
|
||||||
@property
|
|
||||||
def blocks(self):
|
def blocks(self):
|
||||||
"""Get the list of blocks in this container"""
|
"""
|
||||||
return self._blocks
|
Get an iterator over the blocks in this container.
|
||||||
|
|
||||||
|
Can be used as blocks() for iteration or accessing the _blocks list directly.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Iterator over blocks
|
||||||
|
"""
|
||||||
|
return iter(self._blocks)
|
||||||
|
|
||||||
def add_block(self, block):
|
def add_block(self, block):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -359,62 +359,48 @@ class Font:
|
|||||||
"""Get the minimum width required for hyphenation to be considered"""
|
"""Get the minimum width required for hyphenation to be considered"""
|
||||||
return self._min_hyphenation_width
|
return self._min_hyphenation_width
|
||||||
|
|
||||||
|
def _with_modified(self, **kwargs):
|
||||||
|
"""
|
||||||
|
Internal helper to create a new Font with modified parameters.
|
||||||
|
|
||||||
|
This consolidates the duplication across all with_* methods.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
**kwargs: Parameters to override (e.g., font_size=20, colour=(255,0,0))
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
New Font object with modified parameters
|
||||||
|
"""
|
||||||
|
params = {
|
||||||
|
'font_path': self._font_path,
|
||||||
|
'font_size': self._font_size,
|
||||||
|
'colour': self._colour,
|
||||||
|
'weight': self._weight,
|
||||||
|
'style': self._style,
|
||||||
|
'decoration': self._decoration,
|
||||||
|
'background': self._background,
|
||||||
|
'language': self.language,
|
||||||
|
'min_hyphenation_width': self._min_hyphenation_width
|
||||||
|
}
|
||||||
|
params.update(kwargs)
|
||||||
|
return Font(**params)
|
||||||
|
|
||||||
def with_size(self, size: int):
|
def with_size(self, size: int):
|
||||||
"""Create a new Font object with modified size"""
|
"""Create a new Font object with modified size"""
|
||||||
return Font(
|
return self._with_modified(font_size=size)
|
||||||
self._font_path,
|
|
||||||
size,
|
|
||||||
self._colour,
|
|
||||||
self._weight,
|
|
||||||
self._style,
|
|
||||||
self._decoration,
|
|
||||||
self._background
|
|
||||||
)
|
|
||||||
|
|
||||||
def with_colour(self, colour: Tuple[int, int, int]):
|
def with_colour(self, colour: Tuple[int, int, int]):
|
||||||
"""Create a new Font object with modified colour"""
|
"""Create a new Font object with modified colour"""
|
||||||
return Font(
|
return self._with_modified(colour=colour)
|
||||||
self._font_path,
|
|
||||||
self._font_size,
|
|
||||||
colour,
|
|
||||||
self._weight,
|
|
||||||
self._style,
|
|
||||||
self._decoration,
|
|
||||||
self._background
|
|
||||||
)
|
|
||||||
|
|
||||||
def with_weight(self, weight: FontWeight):
|
def with_weight(self, weight: FontWeight):
|
||||||
"""Create a new Font object with modified weight"""
|
"""Create a new Font object with modified weight"""
|
||||||
return Font(
|
return self._with_modified(weight=weight)
|
||||||
self._font_path,
|
|
||||||
self._font_size,
|
|
||||||
self._colour,
|
|
||||||
weight,
|
|
||||||
self._style,
|
|
||||||
self._decoration,
|
|
||||||
self._background
|
|
||||||
)
|
|
||||||
|
|
||||||
def with_style(self, style: FontStyle):
|
def with_style(self, style: FontStyle):
|
||||||
"""Create a new Font object with modified style"""
|
"""Create a new Font object with modified style"""
|
||||||
return Font(
|
return self._with_modified(style=style)
|
||||||
self._font_path,
|
|
||||||
self._font_size,
|
|
||||||
self._colour,
|
|
||||||
self._weight,
|
|
||||||
style,
|
|
||||||
self._decoration,
|
|
||||||
self._background
|
|
||||||
)
|
|
||||||
|
|
||||||
def with_decoration(self, decoration: TextDecoration):
|
def with_decoration(self, decoration: TextDecoration):
|
||||||
"""Create a new Font object with modified decoration"""
|
"""Create a new Font object with modified decoration"""
|
||||||
return Font(
|
return self._with_modified(decoration=decoration)
|
||||||
self._font_path,
|
|
||||||
self._font_size,
|
|
||||||
self._colour,
|
|
||||||
self._weight,
|
|
||||||
self._style,
|
|
||||||
decoration,
|
|
||||||
self._background
|
|
||||||
)
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user