Update coverage badges [skip ci]

This commit is contained in:
Gitea Action 2025-11-12 12:03:27 +00:00
commit e04a6044da
291 changed files with 78353 additions and 0 deletions

31
.coveragerc Normal file
View File

@ -0,0 +1,31 @@
[run]
source = pyWebLayout
branch = True
omit =
*/tests/*
*/test_*
setup.py
*/examples/*
*/__main__.py
[report]
exclude_lines =
pragma: no cover
def __repr__
if self.debug:
if settings.DEBUG
raise AssertionError
raise NotImplementedError
if 0:
if __name__ == .__main__.:
# Exclude docstrings
^\s*"""
^\s*'''
^\s*r"""
^\s*r'''
[xml]
output = coverage.xml
[html]
directory = htmlcov

179
.gitea/workflows/ci.yml Normal file
View File

@ -0,0 +1,179 @@
name: Python CI
on:
push:
branches: [ main, master, develop ]
paths-ignore:
- 'coverage*.svg'
- 'README.md'
pull_request:
branches: [ main, master, develop ]
jobs:
test:
runs-on: self-hosted
strategy:
matrix:
python-version: ['3.10', '3.12', '3.13']
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
# Install package in development mode
pip install -e .
# Install test dependencies if they exist
if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi
if [ -f requirements/test.txt ]; then pip install -r requirements/test.txt; fi
# Install common test packages
pip install pytest pytest-cov flake8 coverage-badge interrogate
- name: Download initial failed badges
run: |
echo "Downloading initial failed badges..."
# Create cov_info directory first
mkdir -p cov_info
# Download failed badges as defaults
curl -o cov_info/coverage.svg "https://img.shields.io/badge/coverage-failed-red.svg"
curl -o cov_info/coverage-docs.svg "https://img.shields.io/badge/docs-failed-red.svg"
echo "Initial failed badges created:"
ls -la cov_info/coverage*.svg
- name: Run tests with pytest
id: pytest
continue-on-error: true
run: |
# Run tests with coverage
python -m pytest tests/ -v --cov=pyWebLayout --cov-report=term-missing --cov-report=json --cov-report=html --cov-report=xml
- name: Check documentation coverage
id: docs
continue-on-error: true
run: |
# Generate documentation coverage report
interrogate -v --ignore-init-method --ignore-init-module --ignore-magic --ignore-private --ignore-property-decorators --ignore-semiprivate --fail-under=80 pyWebLayout/
- name: Lint with flake8
run: |
# Stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# Exit-zero treats all errors as warnings
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Create coverage info directory
if: always()
run: |
mkdir -p cov_info
echo "Created cov_info directory for coverage data"
- name: Update test coverage badge on success
if: steps.pytest.outcome == 'success' && always()
run: |
echo "Tests passed! Generating successful coverage badge..."
if [ -f coverage.json ]; then
coverage-badge -o cov_info/coverage.svg -f
echo "✅ Test coverage badge updated with actual results"
else
echo "⚠️ No coverage.json found, keeping failed badge"
fi
- name: Update docs coverage badge on success
if: steps.docs.outcome == 'success' && always()
run: |
echo "Docs check passed! Generating successful docs badge..."
# Remove existing badge first to avoid overwrite error
rm -f cov_info/coverage-docs.svg
interrogate --generate-badge cov_info/coverage-docs.svg pyWebLayout/
echo "✅ Docs coverage badge updated with actual results"
- name: Generate coverage reports
if: steps.pytest.outcome == 'success'
run: |
# Generate coverage summary for README
python -c "
import json
import os
# Read coverage data
if os.path.exists('coverage.json'):
with open('coverage.json', 'r') as f:
coverage_data = json.load(f)
total_coverage = round(coverage_data['totals']['percent_covered'], 1)
# Create coverage summary file in cov_info directory
with open('cov_info/coverage-summary.txt', 'w') as f:
f.write(f'{total_coverage}%')
print(f'Test Coverage: {total_coverage}%')
covered_lines = coverage_data['totals']['covered_lines']
total_lines = coverage_data['totals']['num_statements']
print(f'Lines Covered: {covered_lines}/{total_lines}')
else:
print('No coverage data found')
"
# Copy other coverage files to cov_info
if [ -f coverage.json ]; then cp coverage.json cov_info/; fi
if [ -f coverage.xml ]; then cp coverage.xml cov_info/; fi
if [ -d htmlcov ]; then cp -r htmlcov cov_info/; fi
- name: Final badge status
if: always()
run: |
echo "=== FINAL BADGE STATUS ==="
echo "Test outcome: ${{ steps.pytest.outcome }}"
echo "Docs outcome: ${{ steps.docs.outcome }}"
if [ -f cov_info/coverage.svg ]; then
echo "✅ Test coverage badge: $(ls -lh cov_info/coverage.svg)"
else
echo "❌ Test coverage badge: MISSING"
fi
if [ -f cov_info/coverage-docs.svg ]; then
echo "✅ Docs coverage badge: $(ls -lh cov_info/coverage-docs.svg)"
else
echo "❌ Docs coverage badge: MISSING"
fi
echo "Coverage info directory contents:"
ls -la cov_info/ 2>/dev/null || echo "No cov_info directory found"
- name: Upload coverage artifacts
uses: actions/upload-artifact@v3
with:
name: coverage-reports
path: |
cov_info/
- name: Commit badges to badges branch
if: github.ref == 'refs/heads/master'
run: |
git config --local user.email "action@gitea.local"
git config --local user.name "Gitea Action"
# Set the remote URL to use the token
git remote set-url origin https://${{ secrets.PUSH_TOKEN }}@gitea.tourolle.paris/dtourolle/pyWebLayout.git
# Create a new orphan branch for badges (this discards any existing badges branch)
git checkout --orphan badges
# Remove all files except cov_info
find . -maxdepth 1 -not -name '.git' -not -name 'cov_info' -exec rm -rf {} + 2>/dev/null || true
# Add only the coverage info directory
git add -f cov_info/
# Always commit (force overwrite)
echo "Force updating badges branch with new coverage data..."
git commit -m "Update coverage badges [skip ci]"
git push -f origin badges

56
.gitignore vendored Normal file
View File

@ -0,0 +1,56 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
*/__pycache__
# Distribution / packaging
dist/
build/
*.egg-info/
# Environment
venv/
env/
.env/
.venv/
# Tests
.pytest_cache/
.coverage
htmlcov/
# IDE files
.idea/
.vscode/
*.swp
*.swo
# Project specific
*.png
*.jpg
*.jpeg
*.gif
*.svg
# But allow documentation images
!docs/images/*.gif
!docs/images/*.png
!docs/images/*.jpg
# Output directories
output/
my_output/
test_output/
*_output/
examples/output/
# Generated data
bookmarks/
positions/
# Profiling scripts
profile_*.py
# Debug scripts output
debug_*.png
.fish*

233
ARCHITECTURE.md Normal file
View File

@ -0,0 +1,233 @@
# pyWebLayout Architecture: Abstract vs Concrete
This document explains the fundamental architectural separation between **Abstract** and **Concrete** layers in the pyWebLayout library.
## Overview
The pyWebLayout library follows a clear separation between two distinct layers:
- **Abstract Layer**: Represents the logical structure and content of documents (HTML/EPUB text)
- **Concrete Layer**: Handles the spatial rendering and visual representation of content
This separation provides flexibility, testability, and clean separation of concerns.
## Abstract Layer (`pyWebLayout/abstract/`)
The Abstract layer deals with the **logical structure** of documents without concerning itself with how content will be visually rendered.
### Key Components
#### `abstract/block.py`
- `Block`: Base class for all block-level content
- `Paragraph`: Represents a logical paragraph containing words
- `Heading`: Represents headings with semantic levels (H1-H6)
- `HList`: Represents ordered/unordered lists
- `Image`: Represents image references
#### `abstract/inline.py`
- `Word`: Represents individual words with text content and styling information
- Contains methods for hyphenation and text manipulation
- Does **not** handle rendering or spatial layout
#### `abstract/document.py`
- `Document`: Container for the overall document structure
- `Chapter`: Logical grouping of blocks (for books/long documents)
### Characteristics of Abstract Classes
1. **Content-focused**: Store text, structure, and semantic meaning
2. **Layout-agnostic**: No knowledge of fonts, pixels, or rendering
3. **Reusable**: Same content can be rendered in different formats/sizes
4. **Serializable**: Can be saved/loaded without rendering context
### Example: Abstract Word
```python
# An Abstract Word knows its text content and semantic properties
word = Word("supercalifragilisticexpialidocious", font_style)
word.hyphenate() # Logical operation - finds break points
parts = word.get_hyphenated_parts() # Returns ["super-", "cali-", "fragi-", ...]
```
## Concrete Layer (`pyWebLayout/concrete/`)
The Concrete layer handles the **spatial representation** and actual rendering of content.
### Key Components
#### `concrete/text.py`
- `Text`: Renders a specific text fragment with precise positioning
- `Line`: Manages a line of `Text` objects with spacing and alignment
- Handles actual pixel measurements, font rendering, and positioning
#### `concrete/page.py`
- `Page`: Top-level container for rendered content
- `Container`: Layout manager for organizing renderable objects
- Handles spatial layout, pagination, and visual composition
#### `concrete/box.py`
- `Box`: Base class for all spatially-aware renderable objects
- Provides positioning, sizing, and rendering capabilities
### Characteristics of Concrete Classes
1. **Rendering-focused**: Handle pixels, fonts, images, and visual output
2. **Spatially-aware**: Know exact positions, sizes, and layout constraints
3. **Implementation-specific**: Tied to specific rendering technologies (PIL, etc.)
4. **Non-portable**: Rendering results are tied to specific display contexts
### Example: Concrete Text
```python
# A Concrete Text object handles actual rendering
text = Text("super-", font) # Specific text fragment
text._calculate_dimensions() # Computes exact pixel size
image = text.render() # Produces actual visual output
```
## The Transformation Process
The architecture involves a clear transformation from Abstract to Concrete:
```
Abstract Document
[Parser Layer]
Abstract Blocks (Paragraph, Heading, etc.)
[Layout Engine]
Concrete Objects (Text, Line, Page)
[Rendering Engine]
Visual Output (Images, PDF, etc.)
```
### Example Transformation
```python
# 1. Abstract content
paragraph = Paragraph()
paragraph.add_word(Word("This", font))
paragraph.add_word(Word("is", font))
paragraph.add_word(Word("a", font))
paragraph.add_word(Word("test", font))
# 2. Layout transformation
layout = ParagraphLayout(line_width=200, line_height=20)
lines = layout.layout_paragraph(paragraph) # Returns List[Line]
# 3. Each Line contains concrete Text objects
for line in lines:
for text_obj in line.text_objects: # List[Text]
print(f"Text: '{text_obj.text}' at position {text_obj._origin}")
```
## Key Architectural Principles
### 1. **Single Responsibility**
- Abstract classes: Handle content and structure
- Concrete classes: Handle rendering and layout
### 2. **Separation of Concerns**
- Text parsing/processing ≠ Text rendering
- Document structure ≠ Page layout
- Content semantics ≠ Visual presentation
### 3. **Immutable Abstract Content**
- Abstract content remains unchanged during rendering
- Multiple concrete representations can be generated from same abstract content
- Enables pagination, different formats, responsive layouts
### 4. **One-to-Many Relationships**
- One Abstract Word → Multiple Concrete Text objects (hyphenation)
- One Abstract Paragraph → Multiple Concrete Lines
- One Abstract Document → Multiple Concrete Pages
## Common Anti-Patterns to Avoid
### ❌ **Mixing Concerns**
```python
# WRONG: Abstract class knowing about pixels
class Word:
def __init__(self, text):
self.text = text
self.rendered_width = None # ❌ Concrete concern in abstract class
```
### ❌ **renderable_words Concept**
```python
# WRONG: Confusing abstract and concrete
line.renderable_words # ❌ This suggests Words are renderable
# Words are abstract - only Text objects render
```
### ✅ **Correct Separation**
```python
# CORRECT: Clear separation
abstract_word = Word("test") # Abstract content
concrete_text = Text("test", font) # Concrete rendering
line.text_objects.append(concrete_text) # Concrete objects in concrete container
```
## Benefits of This Architecture
### 1. **Flexibility**
- Same content can be rendered at different sizes
- Multiple output formats from single source
- Easy to implement responsive design
### 2. **Testability**
- Abstract logic can be tested without rendering
- Layout algorithms can be tested independently
- Visual rendering can be mocked
### 3. **Performance**
- Abstract content can be cached and reused
- Layout can be computed once for multiple renderings
- Incremental updates possible
### 4. **Maintainability**
- Clear boundaries between text processing and rendering
- Changes to rendering don't affect content parsing
- Easy to swap rendering backends
## File Organization
```
pyWebLayout/
├── abstract/ # Content and structure
│ ├── block.py # Document blocks (Paragraph, Heading, etc.)
│ ├── inline.py # Inline content (Word, etc.)
│ ├── document.py # Document structure
│ └── functional.py # Links, buttons, etc.
├── concrete/ # Rendering and layout
│ ├── text.py # Text and Line rendering
│ ├── page.py # Page layout and containers
│ ├── box.py # Base rendering classes
│ ├── image.py # Image rendering
│ └── functional.py # Interactive elements
├── typesetting/ # Layout algorithms
│ ├── paragraph_layout.py # Abstract → Concrete transformation
│ ├── flow.py # Text flow management
│ └── pagination.py # Page breaking logic
└── style/ # Styling and formatting
├── fonts.py # Font management
├── layout.py # Layout constants
└── alignment.py # Alignment enums
```
## Conclusion
The Abstract/Concrete separation is fundamental to pyWebLayout's design. It ensures clean separation between content processing and visual rendering, enabling flexible, maintainable, and testable document processing pipelines.
**Remember**:
- **Abstract** = What to display (content, structure, semantics)
- **Concrete** = How to display it (pixels, fonts, positioning, rendering)
This architecture enables the library to handle complex document layouts while maintaining clear, understandable code organization.

139
FONT_SWITCHING_FEATURE.md Normal file
View File

@ -0,0 +1,139 @@
# Dynamic Font Family Switching
The pyWebLayout ereader now supports dynamic font family switching, allowing readers to change fonts on-the-fly without losing their reading position.
## Visual Demo
![Font Family Switching](docs/images/font_family_switching_vertical.png)
*The same content rendered in Sans-Serif, Serif, and Monospace fonts*
## Features
- **Three Bundled Font Families**: Sans-Serif (DejaVu Sans), Serif (DejaVu Serif), and Monospace (DejaVu Sans Mono)
- **Dynamic Switching**: Change fonts instantly during reading
- **Position Preservation**: Your reading position is maintained across font changes
- **Attribute Preservation**: Bold, italic, size, and color are preserved when switching families
- **Automatic Cache Management**: Intelligent cache invalidation ensures optimal performance
## Usage
```python
from pyWebLayout.style.fonts import BundledFont
from pyWebLayout.layout.ereader_manager import create_ereader_manager
# Create an ereader instance
manager = create_ereader_manager(blocks, page_size=(600, 800))
# Switch to serif font
manager.set_font_family(BundledFont.SERIF)
page = manager.get_current_page()
# Switch to monospace font
manager.set_font_family(BundledFont.MONOSPACE)
page = manager.get_current_page()
# Restore original fonts
manager.set_font_family(None)
page = manager.get_current_page()
# Query current font family
current_family = manager.get_font_family() # Returns BundledFont or None
```
## API Reference
### EreaderLayoutManager Methods
#### `set_font_family(family: Optional[BundledFont]) -> Page`
Change the font family and re-render the current page.
**Parameters:**
- `family`: Font family to use (`BundledFont.SANS`, `BundledFont.SERIF`, `BundledFont.MONOSPACE`, or `None` for original fonts)
**Returns:**
- Re-rendered page with the new font family
**Example:**
```python
# Switch to serif
page = manager.set_font_family(BundledFont.SERIF)
# Restore original fonts
page = manager.set_font_family(None)
```
#### `get_font_family() -> Optional[BundledFont]`
Get the current font family override.
**Returns:**
- Current font family (`BundledFont.SANS`, `BundledFont.SERIF`, `BundledFont.MONOSPACE`) or `None` if using original fonts
**Example:**
```python
family = manager.get_font_family()
if family:
print(f"Currently using: {family.value}")
else:
print("Using original fonts")
```
## Font Families
### Sans-Serif (BundledFont.SANS)
- **Font**: DejaVu Sans
- **Best for**: Screen reading, modern interfaces
- **Characteristics**: Clean, legible, no decorative strokes
### Serif (BundledFont.SERIF)
- **Font**: DejaVu Serif
- **Best for**: Long-form reading, formal documents
- **Characteristics**: Traditional, classic appearance with decorative strokes
### Monospace (BundledFont.MONOSPACE)
- **Font**: DejaVu Sans Mono
- **Best for**: Code, technical documentation
- **Characteristics**: Fixed-width characters, uniform spacing
## Examples
### Complete Demo
See [examples/11_font_family_switching_demo.py](examples/11_font_family_switching_demo.py) for a full demonstration including:
- Creating ereader content
- Switching between font families
- Navigating with different fonts
- Position tracking across font changes
### Generate README Images
Run [examples/generate_readme_font_demo.py](examples/generate_readme_font_demo.py) to create comparison images:
```bash
python examples/generate_readme_font_demo.py
```
## Implementation Details
The font family switching is implemented using a **hybrid approach** that combines:
1. **FontFamilyOverride class**: Manages font preferences at render time
2. **Font transformation pipeline**: Intercepts and transforms Font objects during rendering
3. **Intelligent caching**: Automatic cache invalidation when font family changes
4. **Backward compatibility**: Works with existing Font-based content without migration
This approach provides:
- ✅ No breaking changes to existing code
- ✅ Instant font switching without document recreation
- ✅ Preservation of font attributes (weight, style, size, color)
- ✅ Optimal performance with intelligent buffering
## Technical Notes
- Font family changes invalidate the page buffer cache
- Reading position is preserved using the abstract document structure
- Background rendering adapts to the new font family automatically
- All three bundled fonts are included in the package (license: Bitstream Vera / Public Domain)
## License
The bundled DejaVu fonts are free and open source under the [Bitstream Vera License](pyWebLayout/assets/fonts/DEJAVU_README.md).

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Duncan Tourolle
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

11
MANIFEST.in Normal file
View File

@ -0,0 +1,11 @@
include README.md
include LICENSE
include pyWebLayout/*.py
recursive-include pyWebLayout/abstract *.py
recursive-include pyWebLayout/concrete *.py
recursive-include pyWebLayout/style *.py
recursive-include pyWebLayout/core *.py
recursive-include pyWebLayout/typesetting *.py
recursive-include pyWebLayout/io *.py
recursive-include pyWebLayout/examples *.py
recursive-include pyWebLayout/assets *.ttf *.otf *.woff *.woff2

240
README.md Normal file
View File

@ -0,0 +1,240 @@
# PyWebLayout
## Project Status
| Badge | Description |
|-------|-------------|
| ![Test Coverage](https://gitea.tourolle.paris/dtourolle/pyWebLayout/raw/branch/badges/cov_info/coverage.svg) | **Test Coverage** - Percentage of code covered by unit tests |
| ![Documentation Coverage](https://gitea.tourolle.paris/dtourolle/pyWebLayout/raw/branch/badges/cov_info/coverage-docs.svg) | **Documentation Coverage** - Percentage of code with docstrings |
| ![License](https://img.shields.io/badge/license-MIT-blue.svg) | **License** - Project licensing information |
A Python library for HTML-like layout and rendering.
> 📋 **Note**: Badges show results from the commit referenced in the URLs. Red "error" badges indicate build failures for that specific step.
## Description
PyWebLayout is a Python library for HTML-like layout and rendering to paginated images. It provides a flexible page rendering system with support for borders, padding, text layout, and HTML parsing.
## Key Features
### Page Rendering System
- 📄 **Flexible Page Layouts** - Create pages with customizable sizes, borders, and padding
- 🎨 **Styling System** - Control backgrounds, border colors, and spacing
- 📐 **Multiple Layouts** - Support for portrait, landscape, and square pages
- 🖼️ **Image Output** - Render pages to PIL Images (PNG, JPEG, etc.)
### Text and HTML Support
- 📝 **HTML Parsing** - Parse HTML content into structured document blocks
- 🔤 **Font Support** - Multiple font sizes, weights, and styles
- 🎨 **Dynamic Font Families** - Switch between Sans, Serif, and Monospace fonts on-the-fly
- ↔️ **Text Alignment** - Left, center, right, and justified text
- 📖 **Rich Content** - Headings, paragraphs, bold, italic, and more
- 📊 **Table Rendering** - Full HTML table support with headers, borders, and styling
- 🔘 **Interactive Elements** - Buttons, forms, and links with callback support
### Architecture
- **Abstract/Concrete Separation** - Clean separation between content structure and rendering
- **Extensible Design** - Easy to extend with custom renderables
- **Type-safe** - Comprehensive type hints throughout the codebase
## Installation
```bash
pip install pyWebLayout
```
## Quick Start
### Basic Page Rendering
```python
from pyWebLayout.concrete.page import Page
from pyWebLayout.style.page_style import PageStyle
# Create a styled page
page_style = PageStyle(
border_width=2,
border_color=(200, 200, 200),
padding=(30, 30, 30, 30), # top, right, bottom, left
background_color=(255, 255, 255)
)
page = Page(size=(600, 800), style=page_style)
# Render to image
image = page.render()
image.save("my_page.png")
```
### HTML Content Parsing
```python
from pyWebLayout.io.readers.html_extraction import parse_html_string
from pyWebLayout.style import Font
# Parse HTML to structured blocks
html = """
<h1>Document Title</h1>
<p>First paragraph with <b>bold</b> text.</p>
<p>Second paragraph with more content.</p>
"""
base_font = Font(font_size=14)
blocks = parse_html_string(html, base_font=base_font)
# blocks is a list of structured content (Paragraph, Heading, etc.)
```
## Visual Examples
The library supports various page layouts and configurations:
<table>
<tr>
<td align="center" width="50%">
<b>Page Styles</b><br>
<img src="docs/images/example_01_page_rendering.png" width="300" alt="Page Rendering"><br>
<em>Different borders, padding, and backgrounds</em>
</td>
<td align="center" width="50%">
<b>HTML Content</b><br>
<img src="docs/images/example_02_text_and_layout.png" width="300" alt="Text Layout"><br>
<em>Parsed HTML with various text styles</em>
</td>
</tr>
<tr>
<td align="center" width="50%">
<b>Page Layouts</b><br>
<img src="docs/images/example_03_page_layouts.png" width="300" alt="Page Layouts"><br>
<em>Portrait, landscape, and square formats</em>
</td>
<td align="center" width="50%">
<b>Table Rendering</b><br>
<img src="docs/images/example_04_table_rendering.png" width="300" alt="Table Rendering"><br>
<em>HTML tables with headers and styling</em>
</td>
</tr>
<tr>
<td align="center" colspan="2">
<b>Interactive Elements</b><br>
<img src="docs/images/example_06_functional_elements.png" width="300" alt="Interactive Elements"><br>
<em>Buttons, forms, and callback binding</em>
</td>
</tr>
<tr>
<td align="center" width="50%">
<b>🆕 Pagination & PageBreak</b><br>
<img src="docs/images/example_08_pagination_explicit.png" width="300" alt="Pagination"><br>
<em>Multi-page documents with explicit and automatic breaks</em>
</td>
<td align="center" width="50%">
<b>🆕 Link Navigation</b><br>
<img src="docs/images/example_09_link_navigation.png" width="300" alt="Links"><br>
<em>All 4 link types: Internal, External, API, Function</em>
</td>
</tr>
<tr>
<td align="center" colspan="2">
<b>🆕 Comprehensive Forms</b><br>
<img src="docs/images/example_10_forms.png" width="300" alt="Forms"><br>
<em>All 14 form field types with validation</em>
</td>
</tr>
<tr>
<td align="center" colspan="2">
<b>🆕 Dynamic Font Family Switching</b><br>
<img src="docs/images/font_family_switching_vertical.png" width="600" alt="Font Switching"><br>
<em>Switch between Sans, Serif, and Monospace fonts instantly</em>
</td>
</tr>
</table>
## Examples
The `examples/` directory contains working demonstrations:
### Getting Started
- **[01_simple_page_rendering.py](examples/01_simple_page_rendering.py)** - Introduction to the Page system
- **[02_text_and_layout.py](examples/02_text_and_layout.py)** - HTML parsing and text rendering
- **[03_page_layouts.py](examples/03_page_layouts.py)** - Different page configurations
- **[04_table_rendering.py](examples/04_table_rendering.py)** - HTML table rendering with styling
- **[05_html_table_with_images.py](examples/05_html_table_with_images.py)** - Tables with embedded images
- **[06_functional_elements_demo.py](examples/06_functional_elements_demo.py)** - Interactive buttons and forms with callbacks
- **[08_bundled_fonts_demo.py](examples/08_bundled_fonts_demo.py)** - Using the bundled DejaVu font families
### 🆕 Advanced Features (NEW)
- **[08_pagination_demo.py](examples/08_pagination_demo.py)** - Multi-page documents with PageBreak ([11 tests](tests/examples/test_08_pagination_demo.py))
- **[09_link_navigation_demo.py](examples/09_link_navigation_demo.py)** - All link types and navigation ([10 tests](tests/examples/test_09_link_navigation_demo.py))
- **[10_forms_demo.py](examples/10_forms_demo.py)** - All 14 form field types ([9 tests](tests/examples/test_10_forms_demo.py))
- **[11_font_family_switching_demo.py](examples/11_font_family_switching_demo.py)** - 🆕 Dynamic font switching in ereader
Run any example:
```bash
cd examples
python 01_simple_page_rendering.py
python 08_pagination_demo.py # NEW: Multi-page documents
```
**All new examples include comprehensive test coverage!** Run tests with:
```bash
python -m pytest tests/examples/ -v # 30 tests, all passing ✅
```
**Coverage Impact:** The new examples fill critical documentation gaps:
- **PageBreak:** 0% → 100% (had NO examples before)
- **LinkText:** 14% → 100% (all 4 link types demonstrated)
- **FormFields:** 14% → 100% (all 14 field types demonstrated)
See **[examples/README.md](examples/README.md)** for detailed documentation.
## Font Family Switching (NEW ✨)
PyWebLayout now supports dynamic font family switching in the ereader, allowing readers to change fonts on-the-fly without losing their reading position!
### Quick Example
```python
from pyWebLayout.style.fonts import BundledFont
from pyWebLayout.layout.ereader_manager import create_ereader_manager
# Create an ereader
manager = create_ereader_manager(blocks, page_size=(600, 800))
# Switch to serif font
manager.set_font_family(BundledFont.SERIF)
# Switch to monospace font
manager.set_font_family(BundledFont.MONOSPACE)
# Restore original fonts
manager.set_font_family(None)
# Query current font
current = manager.get_font_family()
```
### Features
- **3 Bundled Fonts**: Sans, Serif, and Monospace (DejaVu font family)
- **Instant Switching**: Change fonts without recreating the document
- **Position Preservation**: Reading position maintained across font changes
- **Attribute Preservation**: Bold, italic, size, and color are preserved
- **Smart Caching**: Automatic cache invalidation for optimal performance
**Learn more**: See [FONT_SWITCHING_FEATURE.md](FONT_SWITCHING_FEATURE.md) for complete documentation.
## Documentation
- **[ARCHITECTURE.md](ARCHITECTURE.md)** - Abstract/Concrete architecture guide
- **[FONT_SWITCHING_FEATURE.md](FONT_SWITCHING_FEATURE.md)** - 🆕 Font family switching guide
- **[examples/README.md](examples/README.md)** - Complete examples guide with tests
- **[docs/images/README.md](docs/images/README.md)** - Visual documentation index
- **[pyWebLayout/layout/README_EREADER_API.md](pyWebLayout/layout/README_EREADER_API.md)** - EbookReader API reference
- **API Reference** - See docstrings in source code
## License
MIT License
## Author
Duncan Tourolle - duncan@tourolle.paris

View File

@ -0,0 +1,58 @@
<svg width="140" height="20" viewBox="0 0 140 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<title>interrogate: 94.8%</title>
<g transform="matrix(1,0,0,1,22,0)">
<g id="backgrounds" transform="matrix(1.32789,0,0,1,-22.3892,0)">
<rect x="0" y="0" width="71" height="20" style="fill:rgb(85,85,85);"/>
</g>
<rect x="71" y="0" width="47" height="20" data-interrogate="color" style="fill:#97CA00"/>
<g transform="matrix(1.19746,0,0,1,-22.3744,-4.85723e-16)">
<rect x="0" y="0" width="118" height="20" style="fill:url(#_Linear1);"/>
</g>
</g>
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110">
<text x="590" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="610">interrogate</text>
<text x="590" y="140" transform="scale(.1)" textLength="610">interrogate</text>
<text x="1160" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="370" data-interrogate="result">94.8%</text>
<text x="1160" y="140" transform="scale(.1)" textLength="370" data-interrogate="result">94.8%</text>
</g>
<g id="logo-shadow" serif:id="logo shadow" transform="matrix(0.854876,0,0,0.854876,-6.73514,1.732)">
<g transform="matrix(0.299012,0,0,0.299012,9.70229,-6.68582)">
<path d="M50,64.25C52.76,64.25 55,61.13 55,59.75C55,58.37 52.76,57.25 50,57.25C47.24,57.25 45,58.37 45,59.75C45,61.13 47.24,64.25 50,64.25Z" style="fill:rgb(1,1,1);fill-opacity:0.3;fill-rule:nonzero;"/>
</g>
<g transform="matrix(0.299012,0,0,0.299012,9.70229,-6.68582)">
<path d="M88,49.05C86.506,43.475 83.018,38.638 78.2,35.46C72.969,32.002 66.539,30.844 60.43,32.26C56.576,33.145 52.995,34.958 50,37.54C46.998,34.958 43.411,33.149 39.55,32.27C33.441,30.853 27.011,32.011 21.78,35.47C16.97,38.652 13.489,43.489 12,49.06L12,49.13C11.82,49.79 11.66,50.46 11.53,51.13C11.146,53.207 11.021,55.323 11.16,57.43C11.16,58.03 11.26,58.63 11.34,59.23C11.34,59.51 11.43,59.79 11.48,60.07C11.53,60.35 11.58,60.68 11.64,60.98C11.7,61.28 11.8,61.69 11.89,62.05C11.98,62.41 11.99,62.47 12.05,62.68C12.16,63.07 12.28,63.46 12.41,63.84L12.58,64.34C12.72,64.74 12.88,65.14 13.04,65.53L13.23,65.98C13.403,66.373 13.583,66.767 13.77,67.16L13.99,67.59C14.19,67.97 14.39,68.35 14.61,68.73L14.87,69.15C15.1,69.52 15.33,69.89 15.58,70.26L15.58,70.32L15.99,70.93C16.14,71.14 16.29,71.36 16.45,71.57C20.206,75.83 25.086,78.95 30.53,80.57C36.839,82.48 43.41,83.385 50,83.25C56.599,83.374 63.177,82.456 69.49,80.53C74.644,78.978 79.303,76.102 83,72.19C83.34,71.78 83.65,71.35 84,70.92L84.18,70.66L84.33,70.44L84.41,70.32C84.55,70.12 84.67,69.9 84.81,69.7C85.07,69.3 85.32,68.89 85.55,68.48C85.78,68.07 86.02,67.65 86.23,67.22C86.31,67.05 86.39,66.88 86.47,66.7C86.67,66.28 86.85,65.87 87.03,65.44L87.23,64.92C87.397,64.487 87.55,64.05 87.69,63.61L87.85,63.09C87.98,62.64 88.1,62.19 88.21,61.74C88.21,61.57 88.3,61.39 88.33,61.22C88.43,60.75 88.52,60.22 88.6,59.79C88.6,59.64 88.66,59.49 88.68,59.33C88.77,58.71 88.84,58.08 88.88,57.45L88.88,54.17C88.817,53.164 88.693,52.162 88.51,51.17C88.38,50.5 88.23,49.84 88.05,49.17L88,49.05ZM85.89,56.44L85.89,57.23C85.89,57.78 85.79,58.32 85.72,58.86C85.72,59.01 85.72,59.15 85.65,59.3C85.59,59.7 85.51,60.11 85.43,60.51L85.32,60.99C85.23,61.38 85.12,61.77 85.01,62.16C85.01,62.31 84.93,62.46 84.88,62.6C84.74,63.04 84.59,63.47 84.42,63.9L84.27,64.28C84.1,64.71 83.91,65.14 83.71,65.56C83.51,65.98 83.43,66.12 83.28,66.4L83.01,66.91C82.83,67.223 82.643,67.537 82.45,67.85L82.35,68.01C79.121,68.047 75.918,67.434 72.93,66.21C64.27,62.74 59,55.52 61.18,50.11C62.18,47.6 64.7,45.82 68.26,45.11C72.489,44.395 76.835,44.908 80.78,46.59C82.141,47.144 83.453,47.813 84.7,48.59C84.76,48.76 84.82,48.93 84.88,49.1C84.94,49.27 85.05,49.63 85.12,49.9C85.28,50.5 85.44,51.1 85.55,51.73C85.691,52.507 85.792,53.292 85.85,54.08L85.85,55.89C85.85,56.12 85.91,56.25 85.91,56.45L85.89,56.44ZM17.66,68C16.668,66.435 15.869,64.756 15.28,63L15.17,62.68C15.06,62.35 14.96,62.01 14.87,61.68C14.823,61.493 14.777,61.31 14.73,61.13C14.66,60.84 14.59,60.55 14.53,60.27C14.47,59.99 14.43,59.72 14.38,59.44C14.33,59.16 14.3,59 14.27,58.78C14.2,58.27 14.15,57.78 14.11,57.23L14.11,57.03C14.008,55.236 14.122,53.437 14.45,51.67C14.56,51.06 14.71,50.46 14.88,49.87C14.96,49.59 15.04,49.32 15.13,49.05C15.22,48.78 15.24,48.72 15.3,48.55C16.548,47.774 17.859,47.105 19.22,46.55C27.86,43.09 36.65,44.67 38.82,50.08C40.99,55.49 35.73,62.74 27.09,66.2C24.101,67.431 20.893,68.043 17.66,68ZM68.57,77.68C62.554,79.508 56.287,80.376 50,80.25C43.737,80.37 37.495,79.506 31.5,77.69C27.185,76.38 23.243,74.062 20,70.93C22.815,70.706 25.58,70.055 28.2,69C38.37,64.92 44.39,56 41.6,49C38.81,42 28.27,39.72 18.1,43.8L17.43,44.09C18.973,41.648 21.019,39.561 23.43,37.97C26.671,35.824 30.473,34.68 34.36,34.68C35.884,34.681 37.404,34.852 38.89,35.19C42.694,36.049 46.191,37.935 49,40.64L50,41.64L51,40.64C53.797,37.937 57.279,36.049 61.07,35.18C66.402,33.947 72.014,34.968 76.57,38C78.98,39.588 81.026,41.671 82.57,44.11L81.9,43.82C77.409,41.921 72.464,41.355 67.66,42.19C63.08,43.12 59.79,45.54 58.39,49.02C55.6,55.97 61.62,64.94 71.79,69.02C74.414,70.07 77.182,70.714 80,70.93C76.776,74.05 72.859,76.363 68.57,77.68Z" style="fill:rgb(1,1,1);fill-opacity:0.3;fill-rule:nonzero;"/>
</g>
<g transform="matrix(0.299012,0,0,0.299012,9.70229,-6.68582)">
<circle cx="71.33" cy="56" r="5.16" style="fill:rgb(1,1,1);fill-opacity:0.3;"/>
</g>
<g transform="matrix(0.299012,0,0,0.299012,9.70229,-6.68582)">
<circle cx="28.67" cy="56" r="5.16" style="fill:rgb(1,1,1);fill-opacity:0.3;"/>
</g>
<g transform="matrix(0.299012,0,0,0.299012,9.70229,-6.68582)">
<path d="M58,66C55.912,68.161 53.003,69.339 50,69.24C46.997,69.339 44.088,68.161 42,66C41.714,65.677 41.302,65.491 40.87,65.491C40.042,65.491 39.361,66.172 39.361,67C39.361,67.368 39.496,67.724 39.74,68C42.403,70.804 46.134,72.35 50,72.25C53.862,72.347 57.59,70.802 60.25,68C60.495,67.725 60.63,67.369 60.63,67C60.63,66.174 59.951,65.495 59.125,65.495C58.695,65.495 58.285,65.679 58,66Z" style="fill:rgb(1,1,1);fill-opacity:0.3;fill-rule:nonzero;"/>
</g>
</g>
<g id="logo-pink" serif:id="logo pink" transform="matrix(0.854876,0,0,0.854876,-6.73514,0.877124)">
<g transform="matrix(0.299012,0,0,0.299012,9.70229,-6.68582)">
<path d="M50,64.25C52.76,64.25 55,61.13 55,59.75C55,58.37 52.76,57.25 50,57.25C47.24,57.25 45,58.37 45,59.75C45,61.13 47.24,64.25 50,64.25Z" style="fill:rgb(222,120,160);fill-rule:nonzero;"/>
</g>
<g transform="matrix(0.299012,0,0,0.299012,9.70229,-6.68582)">
<path d="M88,49.05C86.506,43.475 83.018,38.638 78.2,35.46C72.969,32.002 66.539,30.844 60.43,32.26C56.576,33.145 52.995,34.958 50,37.54C46.998,34.958 43.411,33.149 39.55,32.27C33.441,30.853 27.011,32.011 21.78,35.47C16.97,38.652 13.489,43.489 12,49.06L12,49.13C11.82,49.79 11.66,50.46 11.53,51.13C11.146,53.207 11.021,55.323 11.16,57.43C11.16,58.03 11.26,58.63 11.34,59.23C11.34,59.51 11.43,59.79 11.48,60.07C11.53,60.35 11.58,60.68 11.64,60.98C11.7,61.28 11.8,61.69 11.89,62.05C11.98,62.41 11.99,62.47 12.05,62.68C12.16,63.07 12.28,63.46 12.41,63.84L12.58,64.34C12.72,64.74 12.88,65.14 13.04,65.53L13.23,65.98C13.403,66.373 13.583,66.767 13.77,67.16L13.99,67.59C14.19,67.97 14.39,68.35 14.61,68.73L14.87,69.15C15.1,69.52 15.33,69.89 15.58,70.26L15.58,70.32L15.99,70.93C16.14,71.14 16.29,71.36 16.45,71.57C20.206,75.83 25.086,78.95 30.53,80.57C36.839,82.48 43.41,83.385 50,83.25C56.599,83.374 63.177,82.456 69.49,80.53C74.644,78.978 79.303,76.102 83,72.19C83.34,71.78 83.65,71.35 84,70.92L84.18,70.66L84.33,70.44L84.41,70.32C84.55,70.12 84.67,69.9 84.81,69.7C85.07,69.3 85.32,68.89 85.55,68.48C85.78,68.07 86.02,67.65 86.23,67.22C86.31,67.05 86.39,66.88 86.47,66.7C86.67,66.28 86.85,65.87 87.03,65.44L87.23,64.92C87.397,64.487 87.55,64.05 87.69,63.61L87.85,63.09C87.98,62.64 88.1,62.19 88.21,61.74C88.21,61.57 88.3,61.39 88.33,61.22C88.43,60.75 88.52,60.22 88.6,59.79C88.6,59.64 88.66,59.49 88.68,59.33C88.77,58.71 88.84,58.08 88.88,57.45L88.88,54.17C88.817,53.164 88.693,52.162 88.51,51.17C88.38,50.5 88.23,49.84 88.05,49.17L88,49.05ZM85.89,56.44L85.89,57.23C85.89,57.78 85.79,58.32 85.72,58.86C85.72,59.01 85.72,59.15 85.65,59.3C85.59,59.7 85.51,60.11 85.43,60.51L85.32,60.99C85.23,61.38 85.12,61.77 85.01,62.16C85.01,62.31 84.93,62.46 84.88,62.6C84.74,63.04 84.59,63.47 84.42,63.9L84.27,64.28C84.1,64.71 83.91,65.14 83.71,65.56C83.51,65.98 83.43,66.12 83.28,66.4L83.01,66.91C82.83,67.223 82.643,67.537 82.45,67.85L82.35,68.01C79.121,68.047 75.918,67.434 72.93,66.21C64.27,62.74 59,55.52 61.18,50.11C62.18,47.6 64.7,45.82 68.26,45.11C72.489,44.395 76.835,44.908 80.78,46.59C82.141,47.144 83.453,47.813 84.7,48.59C84.76,48.76 84.82,48.93 84.88,49.1C84.94,49.27 85.05,49.63 85.12,49.9C85.28,50.5 85.44,51.1 85.55,51.73C85.691,52.507 85.792,53.292 85.85,54.08L85.85,55.89C85.85,56.12 85.91,56.25 85.91,56.45L85.89,56.44ZM17.66,68C16.668,66.435 15.869,64.756 15.28,63L15.17,62.68C15.06,62.35 14.96,62.01 14.87,61.68C14.823,61.493 14.777,61.31 14.73,61.13C14.66,60.84 14.59,60.55 14.53,60.27C14.47,59.99 14.43,59.72 14.38,59.44C14.33,59.16 14.3,59 14.27,58.78C14.2,58.27 14.15,57.78 14.11,57.23L14.11,57.03C14.008,55.236 14.122,53.437 14.45,51.67C14.56,51.06 14.71,50.46 14.88,49.87C14.96,49.59 15.04,49.32 15.13,49.05C15.22,48.78 15.24,48.72 15.3,48.55C16.548,47.774 17.859,47.105 19.22,46.55C27.86,43.09 36.65,44.67 38.82,50.08C40.99,55.49 35.73,62.74 27.09,66.2C24.101,67.431 20.893,68.043 17.66,68ZM68.57,77.68C62.554,79.508 56.287,80.376 50,80.25C43.737,80.37 37.495,79.506 31.5,77.69C27.185,76.38 23.243,74.062 20,70.93C22.815,70.706 25.58,70.055 28.2,69C38.37,64.92 44.39,56 41.6,49C38.81,42 28.27,39.72 18.1,43.8L17.43,44.09C18.973,41.648 21.019,39.561 23.43,37.97C26.671,35.824 30.473,34.68 34.36,34.68C35.884,34.681 37.404,34.852 38.89,35.19C42.694,36.049 46.191,37.935 49,40.64L50,41.64L51,40.64C53.797,37.937 57.279,36.049 61.07,35.18C66.402,33.947 72.014,34.968 76.57,38C78.98,39.588 81.026,41.671 82.57,44.11L81.9,43.82C77.409,41.921 72.464,41.355 67.66,42.19C63.08,43.12 59.79,45.54 58.39,49.02C55.6,55.97 61.62,64.94 71.79,69.02C74.414,70.07 77.182,70.714 80,70.93C76.776,74.05 72.859,76.363 68.57,77.68Z" style="fill:rgb(222,120,160);fill-rule:nonzero;"/>
</g>
<g transform="matrix(0.299012,0,0,0.299012,9.70229,-6.68582)">
<circle cx="71.33" cy="56" r="5.16" style="fill:rgb(222,120,160);"/>
</g>
<g transform="matrix(0.299012,0,0,0.299012,9.70229,-6.68582)">
<circle cx="28.67" cy="56" r="5.16" style="fill:rgb(222,120,160);"/>
</g>
<g transform="matrix(0.299012,0,0,0.299012,9.70229,-6.68582)">
<path d="M58,66C55.912,68.161 53.003,69.339 50,69.24C46.997,69.339 44.088,68.161 42,66C41.714,65.677 41.302,65.491 40.87,65.491C40.042,65.491 39.361,66.172 39.361,67C39.361,67.368 39.496,67.724 39.74,68C42.403,70.804 46.134,72.35 50,72.25C53.862,72.347 57.59,70.802 60.25,68C60.495,67.725 60.63,67.369 60.63,67C60.63,66.174 59.951,65.495 59.125,65.495C58.695,65.495 58.285,65.679 58,66Z" style="fill:rgb(222,120,160);fill-rule:nonzero;"/>
</g>
</g>
<defs>
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.22465e-15,20,-20,1.22465e-15,0,0)">
<stop offset="0" style="stop-color:rgb(187,187,187);stop-opacity:0.1"/>
<stop offset="1" style="stop-color:black;stop-opacity:0.1"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1 @@
78.9%

1
cov_info/coverage.json Normal file

File diff suppressed because one or more lines are too long

21
cov_info/coverage.svg Normal file
View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="99" height="20">
<linearGradient id="b" x2="0" y2="100%">
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<mask id="a">
<rect width="99" height="20" rx="3" fill="#fff"/>
</mask>
<g mask="url(#a)">
<path fill="#555" d="M0 0h63v20H0z"/>
<path fill="#a4a61d" d="M63 0h36v20H63z"/>
<path fill="url(#b)" d="M0 0h99v20H0z"/>
</g>
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
<text x="31.5" y="15" fill="#010101" fill-opacity=".3">coverage</text>
<text x="31.5" y="14">coverage</text>
<text x="80" y="15" fill="#010101" fill-opacity=".3">79%</text>
<text x="80" y="14">79%</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 904 B

5373
cov_info/coverage.xml Normal file

File diff suppressed because it is too large Load Diff

2
cov_info/htmlcov/.gitignore generated vendored Normal file
View File

@ -0,0 +1,2 @@
# Created by coverage.py
*

1453
cov_info/htmlcov/class_index.html generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,733 @@
// Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
// For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
// Coverage.py HTML report browser code.
/*jslint browser: true, sloppy: true, vars: true, plusplus: true, maxerr: 50, indent: 4 */
/*global coverage: true, document, window, $ */
coverage = {};
// General helpers
function debounce(callback, wait) {
let timeoutId = null;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
callback.apply(this, args);
}, wait);
};
};
function checkVisible(element) {
const rect = element.getBoundingClientRect();
const viewBottom = Math.max(document.documentElement.clientHeight, window.innerHeight);
const viewTop = 30;
return !(rect.bottom < viewTop || rect.top >= viewBottom);
}
function on_click(sel, fn) {
const elt = document.querySelector(sel);
if (elt) {
elt.addEventListener("click", fn);
}
}
// Helpers for table sorting
function getCellValue(row, column = 0) {
const cell = row.cells[column] // nosemgrep: eslint.detect-object-injection
if (cell.childElementCount == 1) {
var child = cell.firstElementChild;
if (child.tagName === "A") {
child = child.firstElementChild;
}
if (child instanceof HTMLDataElement && child.value) {
return child.value;
}
}
return cell.innerText || cell.textContent;
}
function rowComparator(rowA, rowB, column = 0) {
let valueA = getCellValue(rowA, column);
let valueB = getCellValue(rowB, column);
if (!isNaN(valueA) && !isNaN(valueB)) {
return valueA - valueB;
}
return valueA.localeCompare(valueB, undefined, {numeric: true});
}
function sortColumn(th) {
// Get the current sorting direction of the selected header,
// clear state on other headers and then set the new sorting direction.
const currentSortOrder = th.getAttribute("aria-sort");
[...th.parentElement.cells].forEach(header => header.setAttribute("aria-sort", "none"));
var direction;
if (currentSortOrder === "none") {
direction = th.dataset.defaultSortOrder || "ascending";
}
else if (currentSortOrder === "ascending") {
direction = "descending";
}
else {
direction = "ascending";
}
th.setAttribute("aria-sort", direction);
const column = [...th.parentElement.cells].indexOf(th)
// Sort all rows and afterwards append them in order to move them in the DOM.
Array.from(th.closest("table").querySelectorAll("tbody tr"))
.sort((rowA, rowB) => rowComparator(rowA, rowB, column) * (direction === "ascending" ? 1 : -1))
.forEach(tr => tr.parentElement.appendChild(tr));
// Save the sort order for next time.
if (th.id !== "region") {
let th_id = "file"; // Sort by file if we don't have a column id
let current_direction = direction;
const stored_list = localStorage.getItem(coverage.INDEX_SORT_STORAGE);
if (stored_list) {
({th_id, direction} = JSON.parse(stored_list))
}
localStorage.setItem(coverage.INDEX_SORT_STORAGE, JSON.stringify({
"th_id": th.id,
"direction": current_direction
}));
if (th.id !== th_id || document.getElementById("region")) {
// Sort column has changed, unset sorting by function or class.
localStorage.setItem(coverage.SORTED_BY_REGION, JSON.stringify({
"by_region": false,
"region_direction": current_direction
}));
}
}
else {
// Sort column has changed to by function or class, remember that.
localStorage.setItem(coverage.SORTED_BY_REGION, JSON.stringify({
"by_region": true,
"region_direction": direction
}));
}
}
// Find all the elements with data-shortcut attribute, and use them to assign a shortcut key.
coverage.assign_shortkeys = function () {
document.querySelectorAll("[data-shortcut]").forEach(element => {
document.addEventListener("keypress", event => {
if (event.target.tagName.toLowerCase() === "input") {
return; // ignore keypress from search filter
}
if (event.key === element.dataset.shortcut) {
element.click();
}
});
});
};
// Create the events for the filter box.
coverage.wire_up_filter = function () {
// Populate the filter and hide100 inputs if there are saved values for them.
const saved_filter_value = localStorage.getItem(coverage.FILTER_STORAGE);
if (saved_filter_value) {
document.getElementById("filter").value = saved_filter_value;
}
const saved_hide100_value = localStorage.getItem(coverage.HIDE100_STORAGE);
if (saved_hide100_value) {
document.getElementById("hide100").checked = JSON.parse(saved_hide100_value);
}
// Cache elements.
const table = document.querySelector("table.index");
const table_body_rows = table.querySelectorAll("tbody tr");
const no_rows = document.getElementById("no_rows");
// Observe filter keyevents.
const filter_handler = (event => {
// Keep running total of each metric, first index contains number of shown rows
const totals = new Array(table.rows[0].cells.length).fill(0);
// Accumulate the percentage as fraction
totals[totals.length - 1] = { "numer": 0, "denom": 0 }; // nosemgrep: eslint.detect-object-injection
var text = document.getElementById("filter").value;
// Store filter value
localStorage.setItem(coverage.FILTER_STORAGE, text);
const casefold = (text === text.toLowerCase());
const hide100 = document.getElementById("hide100").checked;
// Store hide value.
localStorage.setItem(coverage.HIDE100_STORAGE, JSON.stringify(hide100));
// Hide / show elements.
table_body_rows.forEach(row => {
var show = false;
// Check the text filter.
for (let column = 0; column < totals.length; column++) {
cell = row.cells[column];
if (cell.classList.contains("name")) {
var celltext = cell.textContent;
if (casefold) {
celltext = celltext.toLowerCase();
}
if (celltext.includes(text)) {
show = true;
}
}
}
// Check the "hide covered" filter.
if (show && hide100) {
const [numer, denom] = row.cells[row.cells.length - 1].dataset.ratio.split(" ");
show = (numer !== denom);
}
if (!show) {
// hide
row.classList.add("hidden");
return;
}
// show
row.classList.remove("hidden");
totals[0]++;
for (let column = 0; column < totals.length; column++) {
// Accumulate dynamic totals
cell = row.cells[column] // nosemgrep: eslint.detect-object-injection
if (cell.classList.contains("name")) {
continue;
}
if (column === totals.length - 1) {
// Last column contains percentage
const [numer, denom] = cell.dataset.ratio.split(" ");
totals[column]["numer"] += parseInt(numer, 10); // nosemgrep: eslint.detect-object-injection
totals[column]["denom"] += parseInt(denom, 10); // nosemgrep: eslint.detect-object-injection
}
else {
totals[column] += parseInt(cell.textContent, 10); // nosemgrep: eslint.detect-object-injection
}
}
});
// Show placeholder if no rows will be displayed.
if (!totals[0]) {
// Show placeholder, hide table.
no_rows.style.display = "block";
table.style.display = "none";
return;
}
// Hide placeholder, show table.
no_rows.style.display = null;
table.style.display = null;
const footer = table.tFoot.rows[0];
// Calculate new dynamic sum values based on visible rows.
for (let column = 0; column < totals.length; column++) {
// Get footer cell element.
const cell = footer.cells[column]; // nosemgrep: eslint.detect-object-injection
if (cell.classList.contains("name")) {
continue;
}
// Set value into dynamic footer cell element.
if (column === totals.length - 1) {
// Percentage column uses the numerator and denominator,
// and adapts to the number of decimal places.
const match = /\.([0-9]+)/.exec(cell.textContent);
const places = match ? match[1].length : 0;
const { numer, denom } = totals[column]; // nosemgrep: eslint.detect-object-injection
cell.dataset.ratio = `${numer} ${denom}`;
// Check denom to prevent NaN if filtered files contain no statements
cell.textContent = denom
? `${(numer * 100 / denom).toFixed(places)}%`
: `${(100).toFixed(places)}%`;
}
else {
cell.textContent = totals[column]; // nosemgrep: eslint.detect-object-injection
}
}
});
document.getElementById("filter").addEventListener("input", debounce(filter_handler));
document.getElementById("hide100").addEventListener("input", debounce(filter_handler));
// Trigger change event on setup, to force filter on page refresh
// (filter value may still be present).
document.getElementById("filter").dispatchEvent(new Event("input"));
document.getElementById("hide100").dispatchEvent(new Event("input"));
};
coverage.FILTER_STORAGE = "COVERAGE_FILTER_VALUE";
coverage.HIDE100_STORAGE = "COVERAGE_HIDE100_VALUE";
// Set up the click-to-sort columns.
coverage.wire_up_sorting = function () {
document.querySelectorAll("[data-sortable] th[aria-sort]").forEach(
th => th.addEventListener("click", e => sortColumn(e.target))
);
// Look for a localStorage item containing previous sort settings:
let th_id = "file", direction = "ascending";
const stored_list = localStorage.getItem(coverage.INDEX_SORT_STORAGE);
if (stored_list) {
({th_id, direction} = JSON.parse(stored_list));
}
let by_region = false, region_direction = "ascending";
const sorted_by_region = localStorage.getItem(coverage.SORTED_BY_REGION);
if (sorted_by_region) {
({
by_region,
region_direction
} = JSON.parse(sorted_by_region));
}
const region_id = "region";
if (by_region && document.getElementById(region_id)) {
direction = region_direction;
}
// If we are in a page that has a column with id of "region", sort on
// it if the last sort was by function or class.
let th;
if (document.getElementById(region_id)) {
th = document.getElementById(by_region ? region_id : th_id);
}
else {
th = document.getElementById(th_id);
}
th.setAttribute("aria-sort", direction === "ascending" ? "descending" : "ascending");
th.click()
};
coverage.INDEX_SORT_STORAGE = "COVERAGE_INDEX_SORT_2";
coverage.SORTED_BY_REGION = "COVERAGE_SORT_REGION";
// Loaded on index.html
coverage.index_ready = function () {
coverage.assign_shortkeys();
coverage.wire_up_filter();
coverage.wire_up_sorting();
on_click(".button_prev_file", coverage.to_prev_file);
on_click(".button_next_file", coverage.to_next_file);
on_click(".button_show_hide_help", coverage.show_hide_help);
};
// -- pyfile stuff --
coverage.LINE_FILTERS_STORAGE = "COVERAGE_LINE_FILTERS";
coverage.pyfile_ready = function () {
// If we're directed to a particular line number, highlight the line.
var frag = location.hash;
if (frag.length > 2 && frag[1] === "t") {
document.querySelector(frag).closest(".n").classList.add("highlight");
coverage.set_sel(parseInt(frag.substr(2), 10));
}
else {
coverage.set_sel(0);
}
on_click(".button_toggle_run", coverage.toggle_lines);
on_click(".button_toggle_mis", coverage.toggle_lines);
on_click(".button_toggle_exc", coverage.toggle_lines);
on_click(".button_toggle_par", coverage.toggle_lines);
on_click(".button_next_chunk", coverage.to_next_chunk_nicely);
on_click(".button_prev_chunk", coverage.to_prev_chunk_nicely);
on_click(".button_top_of_page", coverage.to_top);
on_click(".button_first_chunk", coverage.to_first_chunk);
on_click(".button_prev_file", coverage.to_prev_file);
on_click(".button_next_file", coverage.to_next_file);
on_click(".button_to_index", coverage.to_index);
on_click(".button_show_hide_help", coverage.show_hide_help);
coverage.filters = undefined;
try {
coverage.filters = localStorage.getItem(coverage.LINE_FILTERS_STORAGE);
} catch(err) {}
if (coverage.filters) {
coverage.filters = JSON.parse(coverage.filters);
}
else {
coverage.filters = {run: false, exc: true, mis: true, par: true};
}
for (cls in coverage.filters) {
coverage.set_line_visibilty(cls, coverage.filters[cls]); // nosemgrep: eslint.detect-object-injection
}
coverage.assign_shortkeys();
coverage.init_scroll_markers();
coverage.wire_up_sticky_header();
document.querySelectorAll("[id^=ctxs]").forEach(
cbox => cbox.addEventListener("click", coverage.expand_contexts)
);
// Rebuild scroll markers when the window height changes.
window.addEventListener("resize", coverage.build_scroll_markers);
};
coverage.toggle_lines = function (event) {
const btn = event.target.closest("button");
const category = btn.value
const show = !btn.classList.contains("show_" + category);
coverage.set_line_visibilty(category, show);
coverage.build_scroll_markers();
coverage.filters[category] = show;
try {
localStorage.setItem(coverage.LINE_FILTERS_STORAGE, JSON.stringify(coverage.filters));
} catch(err) {}
};
coverage.set_line_visibilty = function (category, should_show) {
const cls = "show_" + category;
const btn = document.querySelector(".button_toggle_" + category);
if (btn) {
if (should_show) {
document.querySelectorAll("#source ." + category).forEach(e => e.classList.add(cls));
btn.classList.add(cls);
}
else {
document.querySelectorAll("#source ." + category).forEach(e => e.classList.remove(cls));
btn.classList.remove(cls);
}
}
};
// Return the nth line div.
coverage.line_elt = function (n) {
return document.getElementById("t" + n)?.closest("p");
};
// Set the selection. b and e are line numbers.
coverage.set_sel = function (b, e) {
// The first line selected.
coverage.sel_begin = b;
// The next line not selected.
coverage.sel_end = (e === undefined) ? b+1 : e;
};
coverage.to_top = function () {
coverage.set_sel(0, 1);
coverage.scroll_window(0);
};
coverage.to_first_chunk = function () {
coverage.set_sel(0, 1);
coverage.to_next_chunk();
};
coverage.to_prev_file = function () {
window.location = document.getElementById("prevFileLink").href;
}
coverage.to_next_file = function () {
window.location = document.getElementById("nextFileLink").href;
}
coverage.to_index = function () {
location.href = document.getElementById("indexLink").href;
}
coverage.show_hide_help = function () {
const helpCheck = document.getElementById("help_panel_state")
helpCheck.checked = !helpCheck.checked;
}
// Return a string indicating what kind of chunk this line belongs to,
// or null if not a chunk.
coverage.chunk_indicator = function (line_elt) {
const classes = line_elt?.className;
if (!classes) {
return null;
}
const match = classes.match(/\bshow_\w+\b/);
if (!match) {
return null;
}
return match[0];
};
coverage.to_next_chunk = function () {
const c = coverage;
// Find the start of the next colored chunk.
var probe = c.sel_end;
var chunk_indicator, probe_line;
while (true) {
probe_line = c.line_elt(probe);
if (!probe_line) {
return;
}
chunk_indicator = c.chunk_indicator(probe_line);
if (chunk_indicator) {
break;
}
probe++;
}
// There's a next chunk, `probe` points to it.
var begin = probe;
// Find the end of this chunk.
var next_indicator = chunk_indicator;
while (next_indicator === chunk_indicator) {
probe++;
probe_line = c.line_elt(probe);
next_indicator = c.chunk_indicator(probe_line);
}
c.set_sel(begin, probe);
c.show_selection();
};
coverage.to_prev_chunk = function () {
const c = coverage;
// Find the end of the prev colored chunk.
var probe = c.sel_begin-1;
var probe_line = c.line_elt(probe);
if (!probe_line) {
return;
}
var chunk_indicator = c.chunk_indicator(probe_line);
while (probe > 1 && !chunk_indicator) {
probe--;
probe_line = c.line_elt(probe);
if (!probe_line) {
return;
}
chunk_indicator = c.chunk_indicator(probe_line);
}
// There's a prev chunk, `probe` points to its last line.
var end = probe+1;
// Find the beginning of this chunk.
var prev_indicator = chunk_indicator;
while (prev_indicator === chunk_indicator) {
probe--;
if (probe <= 0) {
return;
}
probe_line = c.line_elt(probe);
prev_indicator = c.chunk_indicator(probe_line);
}
c.set_sel(probe+1, end);
c.show_selection();
};
// Returns 0, 1, or 2: how many of the two ends of the selection are on
// the screen right now?
coverage.selection_ends_on_screen = function () {
if (coverage.sel_begin === 0) {
return 0;
}
const begin = coverage.line_elt(coverage.sel_begin);
const end = coverage.line_elt(coverage.sel_end-1);
return (
(checkVisible(begin) ? 1 : 0)
+ (checkVisible(end) ? 1 : 0)
);
};
coverage.to_next_chunk_nicely = function () {
if (coverage.selection_ends_on_screen() === 0) {
// The selection is entirely off the screen:
// Set the top line on the screen as selection.
// This will select the top-left of the viewport
// As this is most likely the span with the line number we take the parent
const line = document.elementFromPoint(0, 0).parentElement;
if (line.parentElement !== document.getElementById("source")) {
// The element is not a source line but the header or similar
coverage.select_line_or_chunk(1);
}
else {
// We extract the line number from the id
coverage.select_line_or_chunk(parseInt(line.id.substring(1), 10));
}
}
coverage.to_next_chunk();
};
coverage.to_prev_chunk_nicely = function () {
if (coverage.selection_ends_on_screen() === 0) {
// The selection is entirely off the screen:
// Set the lowest line on the screen as selection.
// This will select the bottom-left of the viewport
// As this is most likely the span with the line number we take the parent
const line = document.elementFromPoint(document.documentElement.clientHeight-1, 0).parentElement;
if (line.parentElement !== document.getElementById("source")) {
// The element is not a source line but the header or similar
coverage.select_line_or_chunk(coverage.lines_len);
}
else {
// We extract the line number from the id
coverage.select_line_or_chunk(parseInt(line.id.substring(1), 10));
}
}
coverage.to_prev_chunk();
};
// Select line number lineno, or if it is in a colored chunk, select the
// entire chunk
coverage.select_line_or_chunk = function (lineno) {
var c = coverage;
var probe_line = c.line_elt(lineno);
if (!probe_line) {
return;
}
var the_indicator = c.chunk_indicator(probe_line);
if (the_indicator) {
// The line is in a highlighted chunk.
// Search backward for the first line.
var probe = lineno;
var indicator = the_indicator;
while (probe > 0 && indicator === the_indicator) {
probe--;
probe_line = c.line_elt(probe);
if (!probe_line) {
break;
}
indicator = c.chunk_indicator(probe_line);
}
var begin = probe + 1;
// Search forward for the last line.
probe = lineno;
indicator = the_indicator;
while (indicator === the_indicator) {
probe++;
probe_line = c.line_elt(probe);
indicator = c.chunk_indicator(probe_line);
}
coverage.set_sel(begin, probe);
}
else {
coverage.set_sel(lineno);
}
};
coverage.show_selection = function () {
// Highlight the lines in the chunk
document.querySelectorAll("#source .highlight").forEach(e => e.classList.remove("highlight"));
for (let probe = coverage.sel_begin; probe < coverage.sel_end; probe++) {
coverage.line_elt(probe).querySelector(".n").classList.add("highlight");
}
coverage.scroll_to_selection();
};
coverage.scroll_to_selection = function () {
// Scroll the page if the chunk isn't fully visible.
if (coverage.selection_ends_on_screen() < 2) {
const element = coverage.line_elt(coverage.sel_begin);
coverage.scroll_window(element.offsetTop - 60);
}
};
coverage.scroll_window = function (to_pos) {
window.scroll({top: to_pos, behavior: "smooth"});
};
coverage.init_scroll_markers = function () {
// Init some variables
coverage.lines_len = document.querySelectorAll("#source > p").length;
// Build html
coverage.build_scroll_markers();
};
coverage.build_scroll_markers = function () {
const temp_scroll_marker = document.getElementById("scroll_marker")
if (temp_scroll_marker) temp_scroll_marker.remove();
// Don't build markers if the window has no scroll bar.
if (document.body.scrollHeight <= window.innerHeight) {
return;
}
const marker_scale = window.innerHeight / document.body.scrollHeight;
const line_height = Math.min(Math.max(3, window.innerHeight / coverage.lines_len), 10);
let previous_line = -99, last_mark, last_top;
const scroll_marker = document.createElement("div");
scroll_marker.id = "scroll_marker";
document.getElementById("source").querySelectorAll(
"p.show_run, p.show_mis, p.show_exc, p.show_exc, p.show_par"
).forEach(element => {
const line_top = Math.floor(element.offsetTop * marker_scale);
const line_number = parseInt(element.querySelector(".n a").id.substr(1));
if (line_number === previous_line + 1) {
// If this solid missed block just make previous mark higher.
last_mark.style.height = `${line_top + line_height - last_top}px`;
}
else {
// Add colored line in scroll_marker block.
last_mark = document.createElement("div");
last_mark.id = `m${line_number}`;
last_mark.classList.add("marker");
last_mark.style.height = `${line_height}px`;
last_mark.style.top = `${line_top}px`;
scroll_marker.append(last_mark);
last_top = line_top;
}
previous_line = line_number;
});
// Append last to prevent layout calculation
document.body.append(scroll_marker);
};
coverage.wire_up_sticky_header = function () {
const header = document.querySelector("header");
const header_bottom = (
header.querySelector(".content h2").getBoundingClientRect().top -
header.getBoundingClientRect().top
);
function updateHeader() {
if (window.scrollY > header_bottom) {
header.classList.add("sticky");
}
else {
header.classList.remove("sticky");
}
}
window.addEventListener("scroll", updateHeader);
updateHeader();
};
coverage.expand_contexts = function (e) {
var ctxs = e.target.parentNode.querySelector(".ctxs");
if (!ctxs.classList.contains("expanded")) {
var ctxs_text = ctxs.textContent;
var width = Number(ctxs_text[0]);
ctxs.textContent = "";
for (var i = 1; i < ctxs_text.length; i += width) {
key = ctxs_text.substring(i, i + width).trim();
ctxs.appendChild(document.createTextNode(contexts[key]));
ctxs.appendChild(document.createElement("br"));
}
ctxs.classList.add("expanded");
}
};
document.addEventListener("DOMContentLoaded", () => {
if (document.body.classList.contains("indexfile")) {
coverage.index_ready();
}
else {
coverage.pyfile_ready();
}
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

6983
cov_info/htmlcov/function_index.html generated Normal file

File diff suppressed because it is too large Load Diff

443
cov_info/htmlcov/index.html generated Normal file
View File

@ -0,0 +1,443 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage report</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="indexfile">
<header>
<div class="content">
<h1>Coverage report:
<span class="pc_cov">79%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>f</kbd>
<kbd>s</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>b</kbd>
<kbd>p</kbd>
<kbd>c</kbd>
&nbsp; change column sorting
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<form id="filter_container">
<input id="filter" type="text" value="" placeholder="filter...">
<div>
<input id="hide100" type="checkbox" >
<label for="hide100">hide covered</label>
</div>
</form>
<h2>
<a class="button current">Files</a>
<a class="button" href="function_index.html">Functions</a>
<a class="button" href="class_index.html">Classes</a>
</h2>
<p class="text">
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</header>
<main id="index">
<table class="index" data-sortable>
<thead>
<tr class="tablehead" title="Click to sort">
<th id="file" class="name left" aria-sort="none" data-shortcut="f">File<span class="arrows"></span></th>
<th id="statements" aria-sort="none" data-default-sort-order="descending" data-shortcut="s">statements<span class="arrows"></span></th>
<th id="missing" aria-sort="none" data-default-sort-order="descending" data-shortcut="m">missing<span class="arrows"></span></th>
<th id="excluded" aria-sort="none" data-default-sort-order="descending" data-shortcut="x">excluded<span class="arrows"></span></th>
<th id="branches" aria-sort="none" data-default-sort-order="descending" data-shortcut="b">branches<span class="arrows"></span></th>
<th id="partial" aria-sort="none" data-default-sort-order="descending" data-shortcut="p">partial<span class="arrows"></span></th>
<th id="coverage" class="right" aria-sort="none" data-shortcut="c">coverage<span class="arrows"></span></th>
</tr>
</thead>
<tbody>
<tr class="region">
<td class="name left"><a href="z_20e398e67121d457___init___py.html">pyWebLayout/__init__.py</a></td>
<td>1</td>
<td>0</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td class="right" data-ratio="1 1">100%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_af715639580e2d86___init___py.html">pyWebLayout/abstract/__init__.py</a></td>
<td>5</td>
<td>0</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td class="right" data-ratio="5 5">100%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_af715639580e2d86_block_py.html">pyWebLayout/abstract/block.py</a></td>
<td>489</td>
<td>99</td>
<td>119</td>
<td>66</td>
<td>6</td>
<td class="right" data-ratio="440 555">79%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_af715639580e2d86_document_py.html">pyWebLayout/abstract/document.py</a></td>
<td>194</td>
<td>35</td>
<td>47</td>
<td>36</td>
<td>4</td>
<td class="right" data-ratio="179 230">78%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_af715639580e2d86_functional_py.html">pyWebLayout/abstract/functional.py</a></td>
<td>144</td>
<td>3</td>
<td>39</td>
<td>6</td>
<td>0</td>
<td class="right" data-ratio="147 150">98%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_af715639580e2d86_inline_py.html">pyWebLayout/abstract/inline.py</a></td>
<td>157</td>
<td>1</td>
<td>29</td>
<td>44</td>
<td>1</td>
<td class="right" data-ratio="199 201">99%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_af715639580e2d86_interactive_image_py.html">pyWebLayout/abstract/interactive_image.py</a></td>
<td>34</td>
<td>4</td>
<td>7</td>
<td>12</td>
<td>3</td>
<td class="right" data-ratio="37 46">80%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_7d48e1f4c6486fa2___init___py.html">pyWebLayout/concrete/__init__.py</a></td>
<td>7</td>
<td>0</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td class="right" data-ratio="7 7">100%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_7d48e1f4c6486fa2_box_py.html">pyWebLayout/concrete/box.py</a></td>
<td>19</td>
<td>0</td>
<td>1</td>
<td>2</td>
<td>0</td>
<td class="right" data-ratio="21 21">100%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_7d48e1f4c6486fa2_dynamic_page_py.html">pyWebLayout/concrete/dynamic_page.py</a></td>
<td>178</td>
<td>42</td>
<td>17</td>
<td>84</td>
<td>19</td>
<td class="right" data-ratio="179 262">68%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_7d48e1f4c6486fa2_functional_py.html">pyWebLayout/concrete/functional.py</a></td>
<td>165</td>
<td>17</td>
<td>28</td>
<td>32</td>
<td>9</td>
<td class="right" data-ratio="171 197">87%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_7d48e1f4c6486fa2_image_py.html">pyWebLayout/concrete/image.py</a></td>
<td>134</td>
<td>8</td>
<td>11</td>
<td>36</td>
<td>4</td>
<td class="right" data-ratio="158 170">93%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_7d48e1f4c6486fa2_interaction_handler_py.html">pyWebLayout/concrete/interaction_handler.py</a></td>
<td>99</td>
<td>99</td>
<td>14</td>
<td>40</td>
<td>0</td>
<td class="right" data-ratio="0 139">0%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_7d48e1f4c6486fa2_page_py.html">pyWebLayout/concrete/page.py</a></td>
<td>204</td>
<td>54</td>
<td>31</td>
<td>74</td>
<td>8</td>
<td class="right" data-ratio="184 278">66%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_7d48e1f4c6486fa2_table_py.html">pyWebLayout/concrete/table.py</a></td>
<td>303</td>
<td>76</td>
<td>19</td>
<td>102</td>
<td>20</td>
<td class="right" data-ratio="285 405">70%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_7d48e1f4c6486fa2_text_py.html">pyWebLayout/concrete/text.py</a></td>
<td>283</td>
<td>22</td>
<td>31</td>
<td>82</td>
<td>11</td>
<td class="right" data-ratio="330 365">90%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_40407af872b0cf37___init___py.html">pyWebLayout/core/__init__.py</a></td>
<td>2</td>
<td>0</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td class="right" data-ratio="2 2">100%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_40407af872b0cf37_base_py.html">pyWebLayout/core/base.py</a></td>
<td>134</td>
<td>29</td>
<td>33</td>
<td>30</td>
<td>3</td>
<td class="right" data-ratio="118 164">72%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_40407af872b0cf37_callback_registry_py.html">pyWebLayout/core/callback_registry.py</a></td>
<td>75</td>
<td>4</td>
<td>21</td>
<td>18</td>
<td>3</td>
<td class="right" data-ratio="86 93">92%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_40407af872b0cf37_highlight_py.html">pyWebLayout/core/highlight.py</a></td>
<td>95</td>
<td>5</td>
<td>18</td>
<td>14</td>
<td>0</td>
<td class="right" data-ratio="104 109">95%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_40407af872b0cf37_query_py.html">pyWebLayout/core/query.py</a></td>
<td>33</td>
<td>1</td>
<td>7</td>
<td>2</td>
<td>1</td>
<td class="right" data-ratio="33 35">94%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_fc521de9aff00981___init___py.html">pyWebLayout/io/__init__.py</a></td>
<td>0</td>
<td>0</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td class="right" data-ratio="0 0">100%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_263f2e628cef8c50___init___py.html">pyWebLayout/io/readers/__init__.py</a></td>
<td>2</td>
<td>0</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td class="right" data-ratio="2 2">100%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_263f2e628cef8c50_epub_reader_py.html">pyWebLayout/io/readers/epub_reader.py</a></td>
<td>286</td>
<td>76</td>
<td>18</td>
<td>134</td>
<td>27</td>
<td class="right" data-ratio="295 420">70%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_263f2e628cef8c50_html_extraction_py.html">pyWebLayout/io/readers/html_extraction.py</a></td>
<td>424</td>
<td>30</td>
<td>34</td>
<td>254</td>
<td>35</td>
<td class="right" data-ratio="599 678">88%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_427cc3035faf7633___init___py.html">pyWebLayout/layout/__init__.py</a></td>
<td>0</td>
<td>0</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td class="right" data-ratio="0 0">100%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_427cc3035faf7633_document_layouter_py.html">pyWebLayout/layout/document_layouter.py</a></td>
<td>216</td>
<td>42</td>
<td>16</td>
<td>96</td>
<td>15</td>
<td class="right" data-ratio="239 312">77%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_427cc3035faf7633_ereader_layout_py.html">pyWebLayout/layout/ereader_layout.py</a></td>
<td>279</td>
<td>38</td>
<td>36</td>
<td>112</td>
<td>18</td>
<td class="right" data-ratio="325 391">83%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_427cc3035faf7633_ereader_manager_py.html">pyWebLayout/layout/ereader_manager.py</a></td>
<td>292</td>
<td>48</td>
<td>53</td>
<td>62</td>
<td>8</td>
<td class="right" data-ratio="298 354">84%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_427cc3035faf7633_page_buffer_py.html">pyWebLayout/layout/page_buffer.py</a></td>
<td>195</td>
<td>27</td>
<td>25</td>
<td>64</td>
<td>9</td>
<td class="right" data-ratio="215 259">83%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_427cc3035faf7633_table_optimizer_py.html">pyWebLayout/layout/table_optimizer.py</a></td>
<td>151</td>
<td>14</td>
<td>9</td>
<td>68</td>
<td>9</td>
<td class="right" data-ratio="192 219">88%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_ba7f6bdeb0188088___init___py.html">pyWebLayout/style/__init__.py</a></td>
<td>6</td>
<td>0</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td class="right" data-ratio="6 6">100%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_ba7f6bdeb0188088_abstract_style_py.html">pyWebLayout/style/abstract_style.py</a></td>
<td>130</td>
<td>27</td>
<td>22</td>
<td>22</td>
<td>7</td>
<td class="right" data-ratio="114 152">75%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_ba7f6bdeb0188088_alignment_py.html">pyWebLayout/style/alignment.py</a></td>
<td>11</td>
<td>1</td>
<td>3</td>
<td>0</td>
<td>0</td>
<td class="right" data-ratio="10 11">91%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_ba7f6bdeb0188088_concrete_style_py.html">pyWebLayout/style/concrete_style.py</a></td>
<td>207</td>
<td>66</td>
<td>23</td>
<td>72</td>
<td>12</td>
<td class="right" data-ratio="177 279">63%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_ba7f6bdeb0188088_fonts_py.html">pyWebLayout/style/fonts.py</a></td>
<td>161</td>
<td>43</td>
<td>23</td>
<td>32</td>
<td>2</td>
<td class="right" data-ratio="128 193">66%</td>
</tr>
<tr class="region">
<td class="name left"><a href="z_ba7f6bdeb0188088_page_style_py.html">pyWebLayout/style/page_style.py</a></td>
<td>33</td>
<td>0</td>
<td>4</td>
<td>0</td>
<td>0</td>
<td class="right" data-ratio="33 33">100%</td>
</tr>
</tbody>
<tfoot>
<tr class="total">
<td class="name left">Total</td>
<td>5148</td>
<td>911</td>
<td>746</td>
<td>1596</td>
<td>234</td>
<td class="right" data-ratio="5319 6744">79%</td>
</tr>
</tfoot>
</table>
<p id="no_rows">
No items found using the specified filter.
</p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
<aside class="hidden">
<a id="prevFileLink" class="nav" href="z_ba7f6bdeb0188088_page_style_py.html"></a>
<a id="nextFileLink" class="nav" href="z_20e398e67121d457___init___py.html"></a>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</footer>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

1
cov_info/htmlcov/status.json generated Normal file

File diff suppressed because one or more lines are too long

377
cov_info/htmlcov/style_cb_6b508a39.css generated Normal file
View File

@ -0,0 +1,377 @@
@charset "UTF-8";
/* Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 */
/* For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt */
/* Don't edit this .css file. Edit the .scss file instead! */
html, body, h1, h2, h3, p, table, td, th { margin: 0; padding: 0; border: 0; font-weight: inherit; font-style: inherit; font-size: 100%; font-family: inherit; vertical-align: baseline; }
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 1em; background: #fff; color: #000; }
@media (prefers-color-scheme: dark) { body { background: #1e1e1e; } }
@media (prefers-color-scheme: dark) { body { color: #eee; } }
html > body { font-size: 16px; }
a:active, a:focus { outline: 2px dashed #007acc; }
p { font-size: .875em; line-height: 1.4em; }
table { border-collapse: collapse; }
td { vertical-align: top; }
table tr.hidden { display: none !important; }
p#no_rows { display: none; font-size: 1.15em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; }
a.nav { text-decoration: none; color: inherit; }
a.nav:hover { text-decoration: underline; color: inherit; }
.hidden { display: none; }
header { background: #f8f8f8; width: 100%; z-index: 2; border-bottom: 1px solid #ccc; }
@media (prefers-color-scheme: dark) { header { background: black; } }
@media (prefers-color-scheme: dark) { header { border-color: #333; } }
header .content { padding: 1rem 3.5rem; }
header h2 { margin-top: .5em; font-size: 1em; }
header h2 a.button { font-family: inherit; font-size: inherit; border: 1px solid; border-radius: .2em; background: #eee; color: inherit; text-decoration: none; padding: .1em .5em; margin: 1px calc(.1em + 1px); cursor: pointer; border-color: #ccc; }
@media (prefers-color-scheme: dark) { header h2 a.button { background: #333; } }
@media (prefers-color-scheme: dark) { header h2 a.button { border-color: #444; } }
header h2 a.button.current { border: 2px solid; background: #fff; border-color: #999; cursor: default; }
@media (prefers-color-scheme: dark) { header h2 a.button.current { background: #1e1e1e; } }
@media (prefers-color-scheme: dark) { header h2 a.button.current { border-color: #777; } }
header p.text { margin: .5em 0 -.5em; color: #666; font-style: italic; }
@media (prefers-color-scheme: dark) { header p.text { color: #aaa; } }
header.sticky { position: fixed; left: 0; right: 0; height: 2.5em; }
header.sticky .text { display: none; }
header.sticky h1, header.sticky h2 { font-size: 1em; margin-top: 0; display: inline-block; }
header.sticky .content { padding: 0.5rem 3.5rem; }
header.sticky .content p { font-size: 1em; }
header.sticky ~ #source { padding-top: 6.5em; }
main { position: relative; z-index: 1; }
footer { margin: 1rem 3.5rem; }
footer .content { padding: 0; color: #666; font-style: italic; }
@media (prefers-color-scheme: dark) { footer .content { color: #aaa; } }
#index { margin: 1rem 0 0 3.5rem; }
h1 { font-size: 1.25em; display: inline-block; }
#filter_container { float: right; margin: 0 2em 0 0; line-height: 1.66em; }
#filter_container #filter { width: 10em; padding: 0.2em 0.5em; border: 2px solid #ccc; background: #fff; color: #000; }
@media (prefers-color-scheme: dark) { #filter_container #filter { border-color: #444; } }
@media (prefers-color-scheme: dark) { #filter_container #filter { background: #1e1e1e; } }
@media (prefers-color-scheme: dark) { #filter_container #filter { color: #eee; } }
#filter_container #filter:focus { border-color: #007acc; }
#filter_container :disabled ~ label { color: #ccc; }
@media (prefers-color-scheme: dark) { #filter_container :disabled ~ label { color: #444; } }
#filter_container label { font-size: .875em; color: #666; }
@media (prefers-color-scheme: dark) { #filter_container label { color: #aaa; } }
header button { font-family: inherit; font-size: inherit; border: 1px solid; border-radius: .2em; background: #eee; color: inherit; text-decoration: none; padding: .1em .5em; margin: 1px calc(.1em + 1px); cursor: pointer; border-color: #ccc; }
@media (prefers-color-scheme: dark) { header button { background: #333; } }
@media (prefers-color-scheme: dark) { header button { border-color: #444; } }
header button:active, header button:focus { outline: 2px dashed #007acc; }
header button.run { background: #eeffee; }
@media (prefers-color-scheme: dark) { header button.run { background: #373d29; } }
header button.run.show_run { background: #dfd; border: 2px solid #00dd00; margin: 0 .1em; }
@media (prefers-color-scheme: dark) { header button.run.show_run { background: #373d29; } }
header button.mis { background: #ffeeee; }
@media (prefers-color-scheme: dark) { header button.mis { background: #4b1818; } }
header button.mis.show_mis { background: #fdd; border: 2px solid #ff0000; margin: 0 .1em; }
@media (prefers-color-scheme: dark) { header button.mis.show_mis { background: #4b1818; } }
header button.exc { background: #f7f7f7; }
@media (prefers-color-scheme: dark) { header button.exc { background: #333; } }
header button.exc.show_exc { background: #eee; border: 2px solid #808080; margin: 0 .1em; }
@media (prefers-color-scheme: dark) { header button.exc.show_exc { background: #333; } }
header button.par { background: #ffffd5; }
@media (prefers-color-scheme: dark) { header button.par { background: #650; } }
header button.par.show_par { background: #ffa; border: 2px solid #bbbb00; margin: 0 .1em; }
@media (prefers-color-scheme: dark) { header button.par.show_par { background: #650; } }
#help_panel, #source p .annotate.long { display: none; position: absolute; z-index: 999; background: #ffffcc; border: 1px solid #888; border-radius: .2em; color: #333; padding: .25em .5em; }
#source p .annotate.long { white-space: normal; float: right; top: 1.75em; right: 1em; height: auto; }
#help_panel_wrapper { float: right; position: relative; }
#keyboard_icon { margin: 5px; }
#help_panel_state { display: none; }
#help_panel { top: 25px; right: 0; padding: .75em; border: 1px solid #883; color: #333; }
#help_panel .keyhelp p { margin-top: .75em; }
#help_panel .legend { font-style: italic; margin-bottom: 1em; }
.indexfile #help_panel { width: 25em; }
.pyfile #help_panel { width: 18em; }
#help_panel_state:checked ~ #help_panel { display: block; }
kbd { border: 1px solid black; border-color: #888 #333 #333 #888; padding: .1em .35em; font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-weight: bold; background: #eee; border-radius: 3px; }
#source { padding: 1em 0 1em 3.5rem; font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; }
#source p { position: relative; white-space: pre; }
#source p * { box-sizing: border-box; }
#source p .n { float: left; text-align: right; width: 3.5rem; box-sizing: border-box; margin-left: -3.5rem; padding-right: 1em; color: #999; user-select: none; }
@media (prefers-color-scheme: dark) { #source p .n { color: #777; } }
#source p .n.highlight { background: #ffdd00; }
#source p .n a { scroll-margin-top: 6em; text-decoration: none; color: #999; }
@media (prefers-color-scheme: dark) { #source p .n a { color: #777; } }
#source p .n a:hover { text-decoration: underline; color: #999; }
@media (prefers-color-scheme: dark) { #source p .n a:hover { color: #777; } }
#source p .t { display: inline-block; width: 100%; box-sizing: border-box; margin-left: -.5em; padding-left: 0.3em; border-left: 0.2em solid #fff; }
@media (prefers-color-scheme: dark) { #source p .t { border-color: #1e1e1e; } }
#source p .t:hover { background: #f2f2f2; }
@media (prefers-color-scheme: dark) { #source p .t:hover { background: #282828; } }
#source p .t:hover ~ .r .annotate.long { display: block; }
#source p .t .com { color: #008000; font-style: italic; line-height: 1px; }
@media (prefers-color-scheme: dark) { #source p .t .com { color: #6a9955; } }
#source p .t .key { font-weight: bold; line-height: 1px; }
#source p .t .str, #source p .t .fst { color: #0451a5; }
@media (prefers-color-scheme: dark) { #source p .t .str, #source p .t .fst { color: #9cdcfe; } }
#source p.mis .t { border-left: 0.2em solid #ff0000; }
#source p.mis.show_mis .t { background: #fdd; }
@media (prefers-color-scheme: dark) { #source p.mis.show_mis .t { background: #4b1818; } }
#source p.mis.show_mis .t:hover { background: #f2d2d2; }
@media (prefers-color-scheme: dark) { #source p.mis.show_mis .t:hover { background: #532323; } }
#source p.mis.mis2 .t { border-left: 0.2em dotted #ff0000; }
#source p.mis.mis2.show_mis .t { background: #ffeeee; }
@media (prefers-color-scheme: dark) { #source p.mis.mis2.show_mis .t { background: #351b1b; } }
#source p.mis.mis2.show_mis .t:hover { background: #f2d2d2; }
@media (prefers-color-scheme: dark) { #source p.mis.mis2.show_mis .t:hover { background: #532323; } }
#source p.run .t { border-left: 0.2em solid #00dd00; }
#source p.run.show_run .t { background: #dfd; }
@media (prefers-color-scheme: dark) { #source p.run.show_run .t { background: #373d29; } }
#source p.run.show_run .t:hover { background: #d2f2d2; }
@media (prefers-color-scheme: dark) { #source p.run.show_run .t:hover { background: #404633; } }
#source p.run.run2 .t { border-left: 0.2em dotted #00dd00; }
#source p.run.run2.show_run .t { background: #eeffee; }
@media (prefers-color-scheme: dark) { #source p.run.run2.show_run .t { background: #2b2e24; } }
#source p.run.run2.show_run .t:hover { background: #d2f2d2; }
@media (prefers-color-scheme: dark) { #source p.run.run2.show_run .t:hover { background: #404633; } }
#source p.exc .t { border-left: 0.2em solid #808080; }
#source p.exc.show_exc .t { background: #eee; }
@media (prefers-color-scheme: dark) { #source p.exc.show_exc .t { background: #333; } }
#source p.exc.show_exc .t:hover { background: #e2e2e2; }
@media (prefers-color-scheme: dark) { #source p.exc.show_exc .t:hover { background: #3c3c3c; } }
#source p.exc.exc2 .t { border-left: 0.2em dotted #808080; }
#source p.exc.exc2.show_exc .t { background: #f7f7f7; }
@media (prefers-color-scheme: dark) { #source p.exc.exc2.show_exc .t { background: #292929; } }
#source p.exc.exc2.show_exc .t:hover { background: #e2e2e2; }
@media (prefers-color-scheme: dark) { #source p.exc.exc2.show_exc .t:hover { background: #3c3c3c; } }
#source p.par .t { border-left: 0.2em solid #bbbb00; }
#source p.par.show_par .t { background: #ffa; }
@media (prefers-color-scheme: dark) { #source p.par.show_par .t { background: #650; } }
#source p.par.show_par .t:hover { background: #f2f2a2; }
@media (prefers-color-scheme: dark) { #source p.par.show_par .t:hover { background: #6d5d0c; } }
#source p.par.par2 .t { border-left: 0.2em dotted #bbbb00; }
#source p.par.par2.show_par .t { background: #ffffd5; }
@media (prefers-color-scheme: dark) { #source p.par.par2.show_par .t { background: #423a0f; } }
#source p.par.par2.show_par .t:hover { background: #f2f2a2; }
@media (prefers-color-scheme: dark) { #source p.par.par2.show_par .t:hover { background: #6d5d0c; } }
#source p .r { position: absolute; top: 0; right: 2.5em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; }
#source p .annotate { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; color: #666; padding-right: .5em; }
@media (prefers-color-scheme: dark) { #source p .annotate { color: #ddd; } }
#source p .annotate.short:hover ~ .long { display: block; }
#source p .annotate.long { width: 30em; right: 2.5em; }
#source p input { display: none; }
#source p input ~ .r label.ctx { cursor: pointer; border-radius: .25em; }
#source p input ~ .r label.ctx::before { content: "▶ "; }
#source p input ~ .r label.ctx:hover { background: #e8f4ff; color: #666; }
@media (prefers-color-scheme: dark) { #source p input ~ .r label.ctx:hover { background: #0f3a42; } }
@media (prefers-color-scheme: dark) { #source p input ~ .r label.ctx:hover { color: #aaa; } }
#source p input:checked ~ .r label.ctx { background: #d0e8ff; color: #666; border-radius: .75em .75em 0 0; padding: 0 .5em; margin: -.25em 0; }
@media (prefers-color-scheme: dark) { #source p input:checked ~ .r label.ctx { background: #056; } }
@media (prefers-color-scheme: dark) { #source p input:checked ~ .r label.ctx { color: #aaa; } }
#source p input:checked ~ .r label.ctx::before { content: "▼ "; }
#source p input:checked ~ .ctxs { padding: .25em .5em; overflow-y: scroll; max-height: 10.5em; }
#source p label.ctx { color: #999; display: inline-block; padding: 0 .5em; font-size: .8333em; }
@media (prefers-color-scheme: dark) { #source p label.ctx { color: #777; } }
#source p .ctxs { display: block; max-height: 0; overflow-y: hidden; transition: all .2s; padding: 0 .5em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; white-space: nowrap; background: #d0e8ff; border-radius: .25em; margin-right: 1.75em; text-align: right; }
@media (prefers-color-scheme: dark) { #source p .ctxs { background: #056; } }
#index { font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 0.875em; }
#index table.index { margin-left: -.5em; }
#index td, #index th { text-align: right; padding: .25em .5em; border-bottom: 1px solid #eee; }
@media (prefers-color-scheme: dark) { #index td, #index th { border-color: #333; } }
#index td.name, #index th.name { text-align: left; width: auto; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; min-width: 15em; }
#index th { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-style: italic; color: #333; cursor: pointer; }
@media (prefers-color-scheme: dark) { #index th { color: #ddd; } }
#index th:hover { background: #eee; }
@media (prefers-color-scheme: dark) { #index th:hover { background: #333; } }
#index th .arrows { color: #666; font-size: 85%; font-family: sans-serif; font-style: normal; pointer-events: none; }
#index th[aria-sort="ascending"], #index th[aria-sort="descending"] { white-space: nowrap; background: #eee; padding-left: .5em; }
@media (prefers-color-scheme: dark) { #index th[aria-sort="ascending"], #index th[aria-sort="descending"] { background: #333; } }
#index th[aria-sort="ascending"] .arrows::after { content: " ▲"; }
#index th[aria-sort="descending"] .arrows::after { content: " ▼"; }
#index td.name { font-size: 1.15em; }
#index td.name a { text-decoration: none; color: inherit; }
#index td.name .no-noun { font-style: italic; }
#index tr.total td, #index tr.total_dynamic td { font-weight: bold; border-top: 1px solid #ccc; border-bottom: none; }
#index tr.region:hover { background: #eee; }
@media (prefers-color-scheme: dark) { #index tr.region:hover { background: #333; } }
#index tr.region:hover td.name { text-decoration: underline; color: inherit; }
#scroll_marker { position: fixed; z-index: 3; right: 0; top: 0; width: 16px; height: 100%; background: #fff; border-left: 1px solid #eee; will-change: transform; }
@media (prefers-color-scheme: dark) { #scroll_marker { background: #1e1e1e; } }
@media (prefers-color-scheme: dark) { #scroll_marker { border-color: #333; } }
#scroll_marker .marker { background: #ccc; position: absolute; min-height: 3px; width: 100%; }
@media (prefers-color-scheme: dark) { #scroll_marker .marker { background: #444; } }

View File

@ -0,0 +1,121 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/__init__.py: 100%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/__init__.py</b>:
<span class="pc_cov">100%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">1 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">1<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">0<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">1<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">0<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="index.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_af715639580e2d86___init___py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">PyWebLayout - A Python library for HTML-like layout and rendering.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">This library provides classes for rendering HTML-like content to images</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">using a box-based layout system. It includes support for text, tables,</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="str">and containers, as well as parsers for HTML and EPUB content. It also</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="str">supports pagination for ebook-like content with the ability to pause,</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="str">save state, and resume rendering.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="nam">__version__</span> <span class="op">=</span> <span class="str">'0.1.1'</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"><span class="com"># Core abstractions</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"><span class="com"># Style components</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"><span class="com"># Abstract document model</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"><span class="com"># Concrete implementations</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"><span class="com"># Abstract components</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="index.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_af715639580e2d86___init___py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,116 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/io/readers/__init__.py: 100%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/io/readers/__init__.py</b>:
<span class="pc_cov">100%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">2 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">2<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">0<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">1<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">0<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_fc521de9aff00981___init___py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_263f2e628cef8c50_epub_reader_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">Readers module for pyWebLayout.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">This module provides specialized readers for different document formats.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="com"># EPUB readers</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">epub_reader</span> <span class="key">import</span> <span class="nam">read_epub</span> <span class="com"># Legacy</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="nam">__all__</span> <span class="op">=</span> <span class="op">[</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"> <span class="com"># HTML readers</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"> <span class="str">'read_html'</span><span class="op">,</span> <span class="str">'read_html_file'</span><span class="op">,</span> <span class="str">'parse_html_string'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"> <span class="com"># EPUB readers</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"> <span class="str">'read_epub'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_fc521de9aff00981___init___py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_263f2e628cef8c50_epub_reader_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,702 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/io/readers/epub_reader.py: 70%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/io/readers/epub_reader.py</b>:
<span class="pc_cov">70%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">286 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">210<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">76<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">18<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">27<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_263f2e628cef8c50___init___py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_263f2e628cef8c50_html_extraction_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">EPUB reader for pyWebLayout.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">This module provides functionality for reading EPUB documents and converting them</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">to pyWebLayout's abstract document model.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="key">import</span> <span class="nam">os</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="key">import</span> <span class="nam">zipfile</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="key">import</span> <span class="nam">tempfile</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">Dict</span><span class="op">,</span> <span class="nam">List</span><span class="op">,</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">Any</span><span class="op">,</span> <span class="nam">Callable</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="key">import</span> <span class="nam">xml</span><span class="op">.</span><span class="nam">etree</span><span class="op">.</span><span class="nam">ElementTree</span> <span class="key">as</span> <span class="nam">ET</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"><span class="key">import</span> <span class="nam">urllib</span><span class="op">.</span><span class="nam">parse</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t"><span class="key">from</span> <span class="nam">PIL</span> <span class="key">import</span> <span class="nam">Image</span> <span class="key">as</span> <span class="nam">PILImage</span><span class="op">,</span> <span class="nam">ImageOps</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">document</span> <span class="key">import</span> <span class="nam">Book</span><span class="op">,</span> <span class="nam">Chapter</span><span class="op">,</span> <span class="nam">MetadataType</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">block</span> <span class="key">import</span> <span class="nam">PageBreak</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">io</span><span class="op">.</span><span class="nam">readers</span><span class="op">.</span><span class="nam">html_extraction</span> <span class="key">import</span> <span class="nam">parse_html_string</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"><span class="com"># XML namespaces used in EPUB files</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"><span class="nam">NAMESPACES</span> <span class="op">=</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"> <span class="str">'opf'</span><span class="op">:</span> <span class="str">'http://www.idpf.org/2007/opf'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"> <span class="str">'dc'</span><span class="op">:</span> <span class="str">'http://purl.org/dc/elements/1.1/'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"> <span class="str">'dcterms'</span><span class="op">:</span> <span class="str">'http://purl.org/dc/terms/'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"> <span class="str">'xhtml'</span><span class="op">:</span> <span class="str">'http://www.w3.org/1999/xhtml'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"> <span class="str">'ncx'</span><span class="op">:</span> <span class="str">'http://www.daisy.org/z3986/2005/ncx/'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t"><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"><span class="key">def</span> <span class="nam">default_eink_processor</span><span class="op">(</span><span class="nam">img</span><span class="op">:</span> <span class="nam">PILImage</span><span class="op">.</span><span class="nam">Image</span><span class="op">)</span> <span class="op">-></span> <span class="nam">PILImage</span><span class="op">.</span><span class="nam">Image</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"><span class="str"> Process image for 4-bit e-ink display using PIL only.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"><span class="str"> Applies histogram equalization and 4-bit quantization.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"><span class="str"> img: PIL Image to process</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"><span class="str"> Processed PIL Image in L mode (grayscale) with 4-bit quantization</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t"> <span class="com"># Convert to grayscale if needed</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t"> <span class="key">if</span> <span class="nam">img</span><span class="op">.</span><span class="nam">mode</span> <span class="op">!=</span> <span class="str">'L'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"> <span class="nam">img</span> <span class="op">=</span> <span class="nam">img</span><span class="op">.</span><span class="nam">convert</span><span class="op">(</span><span class="str">'L'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"> <span class="com"># Apply histogram equalization for contrast enhancement</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"> <span class="nam">img</span> <span class="op">=</span> <span class="nam">ImageOps</span><span class="op">.</span><span class="nam">equalize</span><span class="op">(</span><span class="nam">img</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t"> <span class="com"># Quantize to 4-bit (16 grayscale levels: 0, 17, 34, ..., 255)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"> <span class="nam">img</span> <span class="op">=</span> <span class="nam">img</span><span class="op">.</span><span class="nam">point</span><span class="op">(</span><span class="key">lambda</span> <span class="nam">x</span><span class="op">:</span> <span class="op">(</span><span class="nam">x</span> <span class="op">//</span> <span class="num">16</span><span class="op">)</span> <span class="op">*</span> <span class="num">17</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t"> <span class="key">return</span> <span class="nam">img</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"><span class="key">class</span> <span class="nam">EPUBReader</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t"><span class="str"> Reader for EPUB documents.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"><span class="str"> This class extracts content from EPUB files and converts it to</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"><span class="str"> pyWebLayout's abstract document model.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">epub_path</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span> <span class="nam">image_processor</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Callable</span><span class="op">[</span><span class="op">[</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"> <span class="nam">PILImage</span><span class="op">.</span><span class="nam">Image</span><span class="op">]</span><span class="op">,</span> <span class="nam">PILImage</span><span class="op">.</span><span class="nam">Image</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="nam">default_eink_processor</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t"><span class="str"> Initialize an EPUB reader.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"><span class="str"> epub_path: Path to the EPUB file</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t"><span class="str"> image_processor: Optional function to process images for display optimization.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t"><span class="str"> Defaults to default_eink_processor for 4-bit e-ink displays.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t"><span class="str"> Set to None to disable image processing.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"><span class="str"> Custom processor should accept and return a PIL Image.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">epub_path</span> <span class="op">=</span> <span class="nam">epub_path</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">image_processor</span> <span class="op">=</span> <span class="nam">image_processor</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">book</span> <span class="op">=</span> <span class="nam">Book</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">temp_dir</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">content_dir</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">toc</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">spine</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">manifest</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">cover_id</span> <span class="op">=</span> <span class="key">None</span> <span class="com"># ID of the cover image in manifest</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t"> <span class="key">def</span> <span class="nam">read</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Book</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t"><span class="str"> Read the EPUB file and convert it to a Book.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t"><span class="str"> Book: The parsed book</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t"> <span class="com"># Extract the EPUB file</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">temp_dir</span> <span class="op">=</span> <span class="nam">tempfile</span><span class="op">.</span><span class="nam">mkdtemp</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_extract_epub</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_parse_package_document</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_parse_toc</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_create_book</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"> <span class="com"># Add chapters to the book</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_add_chapters</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t"> <span class="com"># Process images for e-ink display optimization</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_process_content_images</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">book</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t"> <span class="key">finally</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"> <span class="com"># Clean up temporary files</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">temp_dir</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"> <span class="key">import</span> <span class="nam">shutil</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t"> <span class="nam">shutil</span><span class="op">.</span><span class="nam">rmtree</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">temp_dir</span><span class="op">,</span> <span class="nam">ignore_errors</span><span class="op">=</span><span class="key">True</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t"> <span class="key">def</span> <span class="nam">_extract_epub</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"> <span class="str">"""Extract the EPUB file to a temporary directory."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t"> <span class="key">with</span> <span class="nam">zipfile</span><span class="op">.</span><span class="nam">ZipFile</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">epub_path</span><span class="op">,</span> <span class="str">'r'</span><span class="op">)</span> <span class="key">as</span> <span class="nam">zip_ref</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t"> <span class="nam">zip_ref</span><span class="op">.</span><span class="nam">extractall</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">temp_dir</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t"> <span class="com"># Find the content directory (typically OEBPS or OPS)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t"> <span class="nam">container_path</span> <span class="op">=</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">join</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">temp_dir</span><span class="op">,</span> <span class="str">'META-INF'</span><span class="op">,</span> <span class="str">'container.xml'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t"> <span class="key">if</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">exists</span><span class="op">(</span><span class="nam">container_path</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">122&#x202F;&#x219B;&#x202F;136</span><span class="annotate long">line 122 didn't jump to line 136 because the condition on line 122 was always true</span></span></p>
<p class="run"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"> <span class="nam">tree</span> <span class="op">=</span> <span class="nam">ET</span><span class="op">.</span><span class="nam">parse</span><span class="op">(</span><span class="nam">container_path</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t"> <span class="nam">root</span> <span class="op">=</span> <span class="nam">tree</span><span class="op">.</span><span class="nam">getroot</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t"> <span class="com"># Get the path to the package document (content.opf)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t"> <span class="key">for</span> <span class="nam">rootfile</span> <span class="key">in</span> <span class="nam">root</span><span class="op">.</span><span class="nam">findall</span><span class="op">(</span>&nbsp;</span><span class="r"><span class="annotate short">127&#x202F;&#x219B;&#x202F;136</span><span class="annotate long">line 127 didn't jump to line 136 because the loop on line 127 didn't complete</span></span></p>
<p class="par par2 ru2 show_par"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t"> <span class="str">'.//{urn:oasis:names:tc:opendocument:xmlns:container}rootfile'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t"> <span class="nam">full_path</span> <span class="op">=</span> <span class="nam">rootfile</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="str">'full-path'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t"> <span class="key">if</span> <span class="nam">full_path</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">130&#x202F;&#x219B;&#x202F;127</span><span class="annotate long">line 130 didn't jump to line 127 because the condition on line 130 was always true</span></span></p>
<p class="run"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">content_dir</span> <span class="op">=</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">dirname</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t"> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">join</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">temp_dir</span><span class="op">,</span> <span class="nam">full_path</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t"> <span class="key">return</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t"> <span class="com"># Fallback: look for common content directories</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"> <span class="key">for</span> <span class="nam">content_dir</span> <span class="key">in</span> <span class="op">[</span><span class="str">'OEBPS'</span><span class="op">,</span> <span class="str">'OPS'</span><span class="op">,</span> <span class="str">'Content'</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t"> <span class="key">if</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">exists</span><span class="op">(</span><span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">join</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">temp_dir</span><span class="op">,</span> <span class="nam">content_dir</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">content_dir</span> <span class="op">=</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">join</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">temp_dir</span><span class="op">,</span> <span class="nam">content_dir</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t"> <span class="key">return</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t"> <span class="com"># If no content directory found, use the root</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">content_dir</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">temp_dir</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"> <span class="key">def</span> <span class="nam">_parse_package_document</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t"> <span class="str">"""Parse the package document (content.opf)."""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t"> <span class="com"># Find the package document</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"> <span class="nam">opf_path</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"> <span class="key">for</span> <span class="nam">root</span><span class="op">,</span> <span class="nam">dirs</span><span class="op">,</span> <span class="nam">files</span> <span class="key">in</span> <span class="nam">os</span><span class="op">.</span><span class="nam">walk</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">content_dir</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">148&#x202F;&#x219B;&#x202F;156</span><span class="annotate long">line 148 didn't jump to line 156 because the loop on line 148 didn't complete</span></span></p>
<p class="par run show_par"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t"> <span class="key">for</span> <span class="nam">file</span> <span class="key">in</span> <span class="nam">files</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">149&#x202F;&#x219B;&#x202F;153</span><span class="annotate long">line 149 didn't jump to line 153 because the loop on line 149 didn't complete</span></span></p>
<p class="run"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t"> <span class="key">if</span> <span class="nam">file</span><span class="op">.</span><span class="nam">endswith</span><span class="op">(</span><span class="str">'.opf'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t"> <span class="nam">opf_path</span> <span class="op">=</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">join</span><span class="op">(</span><span class="nam">root</span><span class="op">,</span> <span class="nam">file</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t"> <span class="key">break</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t"> <span class="key">if</span> <span class="nam">opf_path</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">153&#x202F;&#x219B;&#x202F;148</span><span class="annotate long">line 153 didn't jump to line 148 because the condition on line 153 was always true</span></span></p>
<p class="run"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t"> <span class="key">break</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">opf_path</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">156&#x202F;&#x219B;&#x202F;157</span><span class="annotate long">line 156 didn't jump to line 157 because the condition on line 156 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t"> <span class="key">raise</span> <span class="nam">ValueError</span><span class="op">(</span><span class="str">"No package document (.opf) found in EPUB"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t"> <span class="com"># Parse the package document</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"> <span class="nam">tree</span> <span class="op">=</span> <span class="nam">ET</span><span class="op">.</span><span class="nam">parse</span><span class="op">(</span><span class="nam">opf_path</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t"> <span class="nam">root</span> <span class="op">=</span> <span class="nam">tree</span><span class="op">.</span><span class="nam">getroot</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"> <span class="com"># Parse metadata</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_parse_metadata</span><span class="op">(</span><span class="nam">root</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"> <span class="com"># Parse manifest</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_parse_manifest</span><span class="op">(</span><span class="nam">root</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t"> <span class="com"># Parse spine</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_parse_spine</span><span class="op">(</span><span class="nam">root</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t"> <span class="key">def</span> <span class="nam">_parse_metadata</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">root</span><span class="op">:</span> <span class="nam">ET</span><span class="op">.</span><span class="nam">Element</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t"><span class="str"> Parse metadata from the package document.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t"><span class="str"> root: Root element of the package document</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t"> <span class="com"># Find the metadata element</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t"> <span class="nam">metadata_elem</span> <span class="op">=</span> <span class="nam">root</span><span class="op">.</span><span class="nam">find</span><span class="op">(</span><span class="str">'.//{{{0}}}metadata'</span><span class="op">.</span><span class="nam">format</span><span class="op">(</span><span class="nam">NAMESPACES</span><span class="op">[</span><span class="str">'opf'</span><span class="op">]</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t"> <span class="key">if</span> <span class="nam">metadata_elem</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">181&#x202F;&#x219B;&#x202F;182</span><span class="annotate long">line 181 didn't jump to line 182 because the condition on line 181 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t"> <span class="key">return</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t"> <span class="com"># Parse DC metadata</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t"> <span class="key">for</span> <span class="nam">elem</span> <span class="key">in</span> <span class="nam">metadata_elem</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t"> <span class="key">if</span> <span class="nam">elem</span><span class="op">.</span><span class="nam">tag</span><span class="op">.</span><span class="nam">startswith</span><span class="op">(</span><span class="str">'{{{0}}}'</span><span class="op">.</span><span class="nam">format</span><span class="op">(</span><span class="nam">NAMESPACES</span><span class="op">[</span><span class="str">'dc'</span><span class="op">]</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t"> <span class="com"># Get the local name (without namespace)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t"> <span class="nam">name</span> <span class="op">=</span> <span class="nam">elem</span><span class="op">.</span><span class="nam">tag</span><span class="op">.</span><span class="nam">split</span><span class="op">(</span><span class="str">'}'</span><span class="op">,</span> <span class="num">1</span><span class="op">)</span><span class="op">[</span><span class="num">1</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t"> <span class="nam">value</span> <span class="op">=</span> <span class="nam">elem</span><span class="op">.</span><span class="nam">text</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t"> <span class="key">if</span> <span class="nam">name</span> <span class="op">==</span> <span class="str">'title'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">[</span><span class="str">'title'</span><span class="op">]</span> <span class="op">=</span> <span class="nam">value</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t"> <span class="key">elif</span> <span class="nam">name</span> <span class="op">==</span> <span class="str">'creator'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">[</span><span class="str">'creator'</span><span class="op">]</span> <span class="op">=</span> <span class="nam">value</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t"> <span class="key">elif</span> <span class="nam">name</span> <span class="op">==</span> <span class="str">'language'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">[</span><span class="str">'language'</span><span class="op">]</span> <span class="op">=</span> <span class="nam">value</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"> <span class="key">elif</span> <span class="nam">name</span> <span class="op">==</span> <span class="str">'description'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">[</span><span class="str">'description'</span><span class="op">]</span> <span class="op">=</span> <span class="nam">value</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t"> <span class="key">elif</span> <span class="nam">name</span> <span class="op">==</span> <span class="str">'subject'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t"> <span class="key">if</span> <span class="str">'subjects'</span> <span class="key">not</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">[</span><span class="str">'subjects'</span><span class="op">]</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">[</span><span class="str">'subjects'</span><span class="op">]</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">value</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t"> <span class="key">elif</span> <span class="nam">name</span> <span class="op">==</span> <span class="str">'date'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">[</span><span class="str">'date'</span><span class="op">]</span> <span class="op">=</span> <span class="nam">value</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t"> <span class="key">elif</span> <span class="nam">name</span> <span class="op">==</span> <span class="str">'identifier'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">[</span><span class="str">'identifier'</span><span class="op">]</span> <span class="op">=</span> <span class="nam">value</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t"> <span class="key">elif</span> <span class="nam">name</span> <span class="op">==</span> <span class="str">'publisher'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">[</span><span class="str">'publisher'</span><span class="op">]</span> <span class="op">=</span> <span class="nam">value</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t"> <span class="com"># Store other metadata</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">[</span><span class="nam">name</span><span class="op">]</span> <span class="op">=</span> <span class="nam">value</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"> <span class="com"># Parse meta elements for cover reference</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t"> <span class="key">for</span> <span class="nam">meta</span> <span class="key">in</span> <span class="nam">metadata_elem</span><span class="op">.</span><span class="nam">findall</span><span class="op">(</span><span class="str">'.//{{{0}}}meta'</span><span class="op">.</span><span class="nam">format</span><span class="op">(</span><span class="nam">NAMESPACES</span><span class="op">[</span><span class="str">'opf'</span><span class="op">]</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t"> <span class="nam">name</span> <span class="op">=</span> <span class="nam">meta</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="str">'name'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t"> <span class="nam">content</span> <span class="op">=</span> <span class="nam">meta</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="str">'content'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t"> <span class="key">if</span> <span class="nam">name</span> <span class="op">==</span> <span class="str">'cover'</span> <span class="key">and</span> <span class="nam">content</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">218&#x202F;&#x219B;&#x202F;220</span><span class="annotate long">line 218 didn't jump to line 220 because the condition on line 218 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t"> <span class="com"># This is a reference to the cover image in the manifest</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">cover_id</span> <span class="op">=</span> <span class="nam">content</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"> <span class="key">def</span> <span class="nam">_parse_manifest</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">root</span><span class="op">:</span> <span class="nam">ET</span><span class="op">.</span><span class="nam">Element</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t"><span class="str"> Parse manifest from the package document.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t"><span class="str"> root: Root element of the package document</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t"> <span class="com"># Find the manifest element</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t"> <span class="nam">manifest_elem</span> <span class="op">=</span> <span class="nam">root</span><span class="op">.</span><span class="nam">find</span><span class="op">(</span><span class="str">'.//{{{0}}}manifest'</span><span class="op">.</span><span class="nam">format</span><span class="op">(</span><span class="nam">NAMESPACES</span><span class="op">[</span><span class="str">'opf'</span><span class="op">]</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t"> <span class="key">if</span> <span class="nam">manifest_elem</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">231&#x202F;&#x219B;&#x202F;232</span><span class="annotate long">line 231 didn't jump to line 232 because the condition on line 231 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t"> <span class="key">return</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t"> <span class="com"># Parse items</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t"> <span class="key">for</span> <span class="nam">item</span> <span class="key">in</span> <span class="nam">manifest_elem</span><span class="op">.</span><span class="nam">findall</span><span class="op">(</span><span class="str">'.//{{{0}}}item'</span><span class="op">.</span><span class="nam">format</span><span class="op">(</span><span class="nam">NAMESPACES</span><span class="op">[</span><span class="str">'opf'</span><span class="op">]</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t"> <span class="nam">id</span> <span class="op">=</span> <span class="nam">item</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="str">'id'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t"> <span class="nam">href</span> <span class="op">=</span> <span class="nam">item</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="str">'href'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t"> <span class="nam">media_type</span> <span class="op">=</span> <span class="nam">item</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="str">'media-type'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t"> <span class="key">if</span> <span class="nam">id</span> <span class="key">and</span> <span class="nam">href</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">240&#x202F;&#x219B;&#x202F;235</span><span class="annotate long">line 240 didn't jump to line 235 because the condition on line 240 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t"> <span class="com"># Resolve relative path</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t"> <span class="nam">href</span> <span class="op">=</span> <span class="nam">urllib</span><span class="op">.</span><span class="nam">parse</span><span class="op">.</span><span class="nam">unquote</span><span class="op">(</span><span class="nam">href</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t"> <span class="nam">path</span> <span class="op">=</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">normpath</span><span class="op">(</span><span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">join</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">content_dir</span><span class="op">,</span> <span class="nam">href</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">manifest</span><span class="op">[</span><span class="nam">id</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t"> <span class="str">'href'</span><span class="op">:</span> <span class="nam">href</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t"> <span class="str">'path'</span><span class="op">:</span> <span class="nam">path</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t"> <span class="str">'media_type'</span><span class="op">:</span> <span class="nam">media_type</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t"> <span class="key">def</span> <span class="nam">_parse_spine</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">root</span><span class="op">:</span> <span class="nam">ET</span><span class="op">.</span><span class="nam">Element</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t"><span class="str"> Parse spine from the package document.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t"><span class="str"> root: Root element of the package document</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t"> <span class="com"># Find the spine element</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t"> <span class="nam">spine_elem</span> <span class="op">=</span> <span class="nam">root</span><span class="op">.</span><span class="nam">find</span><span class="op">(</span><span class="str">'.//{{{0}}}spine'</span><span class="op">.</span><span class="nam">format</span><span class="op">(</span><span class="nam">NAMESPACES</span><span class="op">[</span><span class="str">'opf'</span><span class="op">]</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t"> <span class="key">if</span> <span class="nam">spine_elem</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">260&#x202F;&#x219B;&#x202F;261</span><span class="annotate long">line 260 didn't jump to line 261 because the condition on line 260 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t"> <span class="key">return</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t"> <span class="com"># Get the toc attribute (NCX file ID)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t"> <span class="nam">toc_id</span> <span class="op">=</span> <span class="nam">spine_elem</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="str">'toc'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t"> <span class="key">if</span> <span class="nam">toc_id</span> <span class="key">and</span> <span class="nam">toc_id</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">manifest</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">265&#x202F;&#x219B;&#x202F;269</span><span class="annotate long">line 265 didn't jump to line 269 because the condition on line 265 was always true</span></span></p>
<p class="run"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">toc_path</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">manifest</span><span class="op">[</span><span class="nam">toc_id</span><span class="op">]</span><span class="op">[</span><span class="str">'path'</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t"> <span class="com"># Parse itemrefs</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t"> <span class="key">for</span> <span class="nam">itemref</span> <span class="key">in</span> <span class="nam">spine_elem</span><span class="op">.</span><span class="nam">findall</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t"> <span class="str">'.//{{{0}}}itemref'</span><span class="op">.</span><span class="nam">format</span><span class="op">(</span><span class="nam">NAMESPACES</span><span class="op">[</span><span class="str">'opf'</span><span class="op">]</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t"> <span class="nam">idref</span> <span class="op">=</span> <span class="nam">itemref</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="str">'idref'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t"> <span class="key">if</span> <span class="nam">idref</span> <span class="key">and</span> <span class="nam">idref</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">manifest</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">272&#x202F;&#x219B;&#x202F;269</span><span class="annotate long">line 272 didn't jump to line 269 because the condition on line 272 was always true</span></span></p>
<p class="run"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">spine</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">idref</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t"> <span class="key">def</span> <span class="nam">_parse_toc</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t"> <span class="str">"""Parse the table of contents."""</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">hasattr</span><span class="op">(</span>&nbsp;</span><span class="r"><span class="annotate short">277&#x202F;&#x219B;&#x202F;282</span><span class="annotate long">line 277 didn't jump to line 282 because the condition on line 277 was never true</span></span></p>
<p class="par par2 ru2 show_par"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="par par2 ru2 show_par"><span class="n"><a id="t279" href="#t279">279</a></span><span class="t"> <span class="str">'toc_path'</span><span class="op">)</span> <span class="key">or</span> <span class="key">not</span> <span class="nam">self</span><span class="op">.</span><span class="nam">toc_path</span> <span class="key">or</span> <span class="key">not</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">exists</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="par par2 ru2 show_par"><span class="n"><a id="t280" href="#t280">280</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">toc_path</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t281" href="#t281">281</a></span><span class="t"> <span class="com"># Try to find the toc.ncx file</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t282" href="#t282">282</a></span><span class="t"> <span class="key">for</span> <span class="nam">root</span><span class="op">,</span> <span class="nam">dirs</span><span class="op">,</span> <span class="nam">files</span> <span class="key">in</span> <span class="nam">os</span><span class="op">.</span><span class="nam">walk</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">content_dir</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t283" href="#t283">283</a></span><span class="t"> <span class="key">for</span> <span class="nam">file</span> <span class="key">in</span> <span class="nam">files</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t284" href="#t284">284</a></span><span class="t"> <span class="key">if</span> <span class="nam">file</span><span class="op">.</span><span class="nam">endswith</span><span class="op">(</span><span class="str">'.ncx'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t285" href="#t285">285</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">toc_path</span> <span class="op">=</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">join</span><span class="op">(</span><span class="nam">root</span><span class="op">,</span> <span class="nam">file</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t286" href="#t286">286</a></span><span class="t"> <span class="key">break</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t287" href="#t287">287</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="str">'toc_path'</span><span class="op">)</span> <span class="key">and</span> <span class="nam">self</span><span class="op">.</span><span class="nam">toc_path</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t288" href="#t288">288</a></span><span class="t"> <span class="key">break</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t289" href="#t289">289</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t290" href="#t290">290</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">hasattr</span><span class="op">(</span>&nbsp;</span><span class="r"><span class="annotate short">290&#x202F;&#x219B;&#x202F;295</span><span class="annotate long">line 290 didn't jump to line 295 because the condition on line 290 was never true</span></span></p>
<p class="par par2 ru2 show_par"><span class="n"><a id="t291" href="#t291">291</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="par par2 ru2 show_par"><span class="n"><a id="t292" href="#t292">292</a></span><span class="t"> <span class="str">'toc_path'</span><span class="op">)</span> <span class="key">or</span> <span class="key">not</span> <span class="nam">self</span><span class="op">.</span><span class="nam">toc_path</span> <span class="key">or</span> <span class="key">not</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">exists</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="par par2 ru2 show_par"><span class="n"><a id="t293" href="#t293">293</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">toc_path</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t294" href="#t294">294</a></span><span class="t"> <span class="com"># No TOC found</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t295" href="#t295">295</a></span><span class="t"> <span class="key">return</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t296" href="#t296">296</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t297" href="#t297">297</a></span><span class="t"> <span class="com"># Parse the NCX file</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t298" href="#t298">298</a></span><span class="t"> <span class="nam">tree</span> <span class="op">=</span> <span class="nam">ET</span><span class="op">.</span><span class="nam">parse</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">toc_path</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t299" href="#t299">299</a></span><span class="t"> <span class="nam">root</span> <span class="op">=</span> <span class="nam">tree</span><span class="op">.</span><span class="nam">getroot</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t300" href="#t300">300</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t301" href="#t301">301</a></span><span class="t"> <span class="com"># Parse navMap</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t302" href="#t302">302</a></span><span class="t"> <span class="nam">nav_map</span> <span class="op">=</span> <span class="nam">root</span><span class="op">.</span><span class="nam">find</span><span class="op">(</span><span class="str">'.//{{{0}}}navMap'</span><span class="op">.</span><span class="nam">format</span><span class="op">(</span><span class="nam">NAMESPACES</span><span class="op">[</span><span class="str">'ncx'</span><span class="op">]</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t303" href="#t303">303</a></span><span class="t"> <span class="key">if</span> <span class="nam">nav_map</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">303&#x202F;&#x219B;&#x202F;304</span><span class="annotate long">line 303 didn't jump to line 304 because the condition on line 303 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t304" href="#t304">304</a></span><span class="t"> <span class="key">return</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t305" href="#t305">305</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t306" href="#t306">306</a></span><span class="t"> <span class="com"># Parse navPoints</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t307" href="#t307">307</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_parse_nav_points</span><span class="op">(</span><span class="nam">nav_map</span><span class="op">,</span> <span class="op">[</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t308" href="#t308">308</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t309" href="#t309">309</a></span><span class="t"> <span class="key">def</span> <span class="nam">_parse_nav_points</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">parent</span><span class="op">:</span> <span class="nam">ET</span><span class="op">.</span><span class="nam">Element</span><span class="op">,</span> <span class="nam">path</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">]</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t310" href="#t310">310</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t311" href="#t311">311</a></span><span class="t"><span class="str"> Recursively parse navPoints from the NCX file.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t312" href="#t312">312</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t313" href="#t313">313</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t314" href="#t314">314</a></span><span class="t"><span class="str"> parent: Parent element containing navPoints</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t315" href="#t315">315</a></span><span class="t"><span class="str"> path: Current path in the TOC hierarchy</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t316" href="#t316">316</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t317" href="#t317">317</a></span><span class="t"> <span class="key">for</span> <span class="nam">nav_point</span> <span class="key">in</span> <span class="nam">parent</span><span class="op">.</span><span class="nam">findall</span><span class="op">(</span><span class="str">'.//{{{0}}}navPoint'</span><span class="op">.</span><span class="nam">format</span><span class="op">(</span><span class="nam">NAMESPACES</span><span class="op">[</span><span class="str">'ncx'</span><span class="op">]</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t318" href="#t318">318</a></span><span class="t"> <span class="com"># Get navPoint attributes</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t319" href="#t319">319</a></span><span class="t"> <span class="nam">id</span> <span class="op">=</span> <span class="nam">nav_point</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="str">'id'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t320" href="#t320">320</a></span><span class="t"> <span class="nam">play_order</span> <span class="op">=</span> <span class="nam">nav_point</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="str">'playOrder'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t321" href="#t321">321</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t322" href="#t322">322</a></span><span class="t"> <span class="com"># Get navLabel</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t323" href="#t323">323</a></span><span class="t"> <span class="nam">nav_label</span> <span class="op">=</span> <span class="nam">nav_point</span><span class="op">.</span><span class="nam">find</span><span class="op">(</span><span class="str">'.//{{{0}}}navLabel'</span><span class="op">.</span><span class="nam">format</span><span class="op">(</span><span class="nam">NAMESPACES</span><span class="op">[</span><span class="str">'ncx'</span><span class="op">]</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t324" href="#t324">324</a></span><span class="t"> <span class="nam">text_elem</span> <span class="op">=</span> <span class="nam">nav_label</span><span class="op">.</span><span class="nam">find</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t325" href="#t325">325</a></span><span class="t"> <span class="str">'.//{{{0}}}text'</span><span class="op">.</span><span class="nam">format</span><span class="op">(</span><span class="nam">NAMESPACES</span><span class="op">[</span><span class="str">'ncx'</span><span class="op">]</span><span class="op">)</span><span class="op">)</span> <span class="key">if</span> <span class="nam">nav_label</span> <span class="key">else</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t326" href="#t326">326</a></span><span class="t"> <span class="nam">label</span> <span class="op">=</span> <span class="nam">text_elem</span><span class="op">.</span><span class="nam">text</span> <span class="key">if</span> <span class="nam">text_elem</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span> <span class="key">else</span> <span class="str">""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t327" href="#t327">327</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t328" href="#t328">328</a></span><span class="t"> <span class="com"># Get content</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t329" href="#t329">329</a></span><span class="t"> <span class="nam">content</span> <span class="op">=</span> <span class="nam">nav_point</span><span class="op">.</span><span class="nam">find</span><span class="op">(</span><span class="str">'.//{{{0}}}content'</span><span class="op">.</span><span class="nam">format</span><span class="op">(</span><span class="nam">NAMESPACES</span><span class="op">[</span><span class="str">'ncx'</span><span class="op">]</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t330" href="#t330">330</a></span><span class="t"> <span class="nam">src</span> <span class="op">=</span> <span class="nam">content</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="str">'src'</span><span class="op">)</span> <span class="key">if</span> <span class="nam">content</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span> <span class="key">else</span> <span class="str">""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t331" href="#t331">331</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t332" href="#t332">332</a></span><span class="t"> <span class="com"># Create a TOC entry</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t333" href="#t333">333</a></span><span class="t"> <span class="nam">entry</span> <span class="op">=</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t334" href="#t334">334</a></span><span class="t"> <span class="str">'id'</span><span class="op">:</span> <span class="nam">id</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t335" href="#t335">335</a></span><span class="t"> <span class="str">'label'</span><span class="op">:</span> <span class="nam">label</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t336" href="#t336">336</a></span><span class="t"> <span class="str">'src'</span><span class="op">:</span> <span class="nam">src</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t337" href="#t337">337</a></span><span class="t"> <span class="str">'play_order'</span><span class="op">:</span> <span class="nam">play_order</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t338" href="#t338">338</a></span><span class="t"> <span class="str">'children'</span><span class="op">:</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t339" href="#t339">339</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t340" href="#t340">340</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t341" href="#t341">341</a></span><span class="t"> <span class="com"># Add to TOC</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t342" href="#t342">342</a></span><span class="t"> <span class="key">if</span> <span class="nam">path</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">342&#x202F;&#x219B;&#x202F;343</span><span class="annotate long">line 342 didn't jump to line 343 because the condition on line 342 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t343" href="#t343">343</a></span><span class="t"> <span class="nam">path</span><span class="op">[</span><span class="op">-</span><span class="num">1</span><span class="op">]</span><span class="op">[</span><span class="str">'children'</span><span class="op">]</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">entry</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t344" href="#t344">344</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t345" href="#t345">345</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">toc</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">entry</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t346" href="#t346">346</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t347" href="#t347">347</a></span><span class="t"> <span class="com"># Parse child navPoints</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t348" href="#t348">348</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_parse_nav_points</span><span class="op">(</span><span class="nam">nav_point</span><span class="op">,</span> <span class="nam">path</span> <span class="op">+</span> <span class="op">[</span><span class="nam">entry</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t349" href="#t349">349</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t350" href="#t350">350</a></span><span class="t"> <span class="key">def</span> <span class="nam">_create_book</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t351" href="#t351">351</a></span><span class="t"> <span class="str">"""Create a Book object from the parsed metadata."""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t352" href="#t352">352</a></span><span class="t"> <span class="com"># Set book metadata</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t353" href="#t353">353</a></span><span class="t"> <span class="key">if</span> <span class="str">'title'</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">353&#x202F;&#x219B;&#x202F;356</span><span class="annotate long">line 353 didn't jump to line 356 because the condition on line 353 was always true</span></span></p>
<p class="run"><span class="n"><a id="t354" href="#t354">354</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">book</span><span class="op">.</span><span class="nam">set_title</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">[</span><span class="str">'title'</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t355" href="#t355">355</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t356" href="#t356">356</a></span><span class="t"> <span class="key">if</span> <span class="str">'creator'</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t357" href="#t357">357</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">book</span><span class="op">.</span><span class="nam">set_metadata</span><span class="op">(</span><span class="nam">MetadataType</span><span class="op">.</span><span class="nam">AUTHOR</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">[</span><span class="str">'creator'</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t358" href="#t358">358</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t359" href="#t359">359</a></span><span class="t"> <span class="key">if</span> <span class="str">'language'</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t360" href="#t360">360</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">book</span><span class="op">.</span><span class="nam">set_metadata</span><span class="op">(</span><span class="nam">MetadataType</span><span class="op">.</span><span class="nam">LANGUAGE</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">[</span><span class="str">'language'</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t361" href="#t361">361</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t362" href="#t362">362</a></span><span class="t"> <span class="key">if</span> <span class="str">'description'</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t363" href="#t363">363</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">book</span><span class="op">.</span><span class="nam">set_metadata</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t364" href="#t364">364</a></span><span class="t"> <span class="nam">MetadataType</span><span class="op">.</span><span class="nam">DESCRIPTION</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t365" href="#t365">365</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">[</span><span class="str">'description'</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t366" href="#t366">366</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t367" href="#t367">367</a></span><span class="t"> <span class="key">if</span> <span class="str">'subjects'</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t368" href="#t368">368</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">book</span><span class="op">.</span><span class="nam">set_metadata</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t369" href="#t369">369</a></span><span class="t"> <span class="nam">MetadataType</span><span class="op">.</span><span class="nam">KEYWORDS</span><span class="op">,</span> <span class="str">', '</span><span class="op">.</span><span class="nam">join</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t370" href="#t370">370</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">[</span><span class="str">'subjects'</span><span class="op">]</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t371" href="#t371">371</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t372" href="#t372">372</a></span><span class="t"> <span class="key">if</span> <span class="str">'date'</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t373" href="#t373">373</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">book</span><span class="op">.</span><span class="nam">set_metadata</span><span class="op">(</span><span class="nam">MetadataType</span><span class="op">.</span><span class="nam">PUBLICATION_DATE</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">[</span><span class="str">'date'</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t374" href="#t374">374</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t375" href="#t375">375</a></span><span class="t"> <span class="key">if</span> <span class="str">'identifier'</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">375&#x202F;&#x219B;&#x202F;378</span><span class="annotate long">line 375 didn't jump to line 378 because the condition on line 375 was always true</span></span></p>
<p class="run"><span class="n"><a id="t376" href="#t376">376</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">book</span><span class="op">.</span><span class="nam">set_metadata</span><span class="op">(</span><span class="nam">MetadataType</span><span class="op">.</span><span class="nam">IDENTIFIER</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">[</span><span class="str">'identifier'</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t377" href="#t377">377</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t378" href="#t378">378</a></span><span class="t"> <span class="key">if</span> <span class="str">'publisher'</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t379" href="#t379">379</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">book</span><span class="op">.</span><span class="nam">set_metadata</span><span class="op">(</span><span class="nam">MetadataType</span><span class="op">.</span><span class="nam">PUBLISHER</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">metadata</span><span class="op">[</span><span class="str">'publisher'</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t380" href="#t380">380</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t381" href="#t381">381</a></span><span class="t"> <span class="key">def</span> <span class="nam">_add_cover_chapter</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t382" href="#t382">382</a></span><span class="t"> <span class="str">"""Add a cover chapter if a cover image is available."""</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t383" href="#t383">383</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">self</span><span class="op">.</span><span class="nam">cover_id</span> <span class="key">or</span> <span class="nam">self</span><span class="op">.</span><span class="nam">cover_id</span> <span class="key">not</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">manifest</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">383&#x202F;&#x219B;&#x202F;387</span><span class="annotate long">line 383 didn't jump to line 387 because the condition on line 383 was always true</span></span></p>
<p class="run"><span class="n"><a id="t384" href="#t384">384</a></span><span class="t"> <span class="key">return</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t385" href="#t385">385</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t386" href="#t386">386</a></span><span class="t"> <span class="com"># Get the cover image path from the manifest</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t387" href="#t387">387</a></span><span class="t"> <span class="nam">cover_item</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">manifest</span><span class="op">[</span><span class="nam">self</span><span class="op">.</span><span class="nam">cover_id</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t388" href="#t388">388</a></span><span class="t"> <span class="nam">cover_path</span> <span class="op">=</span> <span class="nam">cover_item</span><span class="op">[</span><span class="str">'path'</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t389" href="#t389">389</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t390" href="#t390">390</a></span><span class="t"> <span class="com"># Check if the file exists</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t391" href="#t391">391</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">exists</span><span class="op">(</span><span class="nam">cover_path</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t392" href="#t392">392</a></span><span class="t"> <span class="nam">print</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Warning: Cover image file not found: </span><span class="op">{</span><span class="nam">cover_path</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t393" href="#t393">393</a></span><span class="t"> <span class="key">return</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t394" href="#t394">394</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t395" href="#t395">395</a></span><span class="t"> <span class="com"># Create a cover chapter</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t396" href="#t396">396</a></span><span class="t"> <span class="nam">cover_chapter</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">book</span><span class="op">.</span><span class="nam">create_chapter</span><span class="op">(</span><span class="str">"Cover"</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t397" href="#t397">397</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t398" href="#t398">398</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t399" href="#t399">399</a></span><span class="t"> <span class="com"># Create an Image block for the cover</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t400" href="#t400">400</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">block</span> <span class="key">import</span> <span class="nam">Image</span> <span class="key">as</span> <span class="nam">AbstractImage</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t401" href="#t401">401</a></span><span class="t"> <span class="key">from</span> <span class="nam">PIL</span> <span class="key">import</span> <span class="nam">Image</span> <span class="key">as</span> <span class="nam">PILImage</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t402" href="#t402">402</a></span><span class="t"> <span class="key">import</span> <span class="nam">io</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t403" href="#t403">403</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t404" href="#t404">404</a></span><span class="t"> <span class="com"># Load the image into memory before the temp directory is cleaned up</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t405" href="#t405">405</a></span><span class="t"> <span class="com"># We need to fully copy the image data to ensure it persists after temp</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t406" href="#t406">406</a></span><span class="t"> <span class="com"># cleanup</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t407" href="#t407">407</a></span><span class="t"> <span class="key">with</span> <span class="nam">open</span><span class="op">(</span><span class="nam">cover_path</span><span class="op">,</span> <span class="str">'rb'</span><span class="op">)</span> <span class="key">as</span> <span class="nam">f</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t408" href="#t408">408</a></span><span class="t"> <span class="nam">image_bytes</span> <span class="op">=</span> <span class="nam">f</span><span class="op">.</span><span class="nam">read</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t409" href="#t409">409</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t410" href="#t410">410</a></span><span class="t"> <span class="com"># Create PIL image from bytes in memory</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t411" href="#t411">411</a></span><span class="t"> <span class="nam">pil_image</span> <span class="op">=</span> <span class="nam">PILImage</span><span class="op">.</span><span class="nam">open</span><span class="op">(</span><span class="nam">io</span><span class="op">.</span><span class="nam">BytesIO</span><span class="op">(</span><span class="nam">image_bytes</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t412" href="#t412">412</a></span><span class="t"> <span class="nam">pil_image</span><span class="op">.</span><span class="nam">load</span><span class="op">(</span><span class="op">)</span> <span class="com"># Force loading into memory</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t413" href="#t413">413</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t414" href="#t414">414</a></span><span class="t"> <span class="com"># Create a copy to ensure all data is in memory</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t415" href="#t415">415</a></span><span class="t"> <span class="nam">pil_image</span> <span class="op">=</span> <span class="nam">pil_image</span><span class="op">.</span><span class="nam">copy</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t416" href="#t416">416</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t417" href="#t417">417</a></span><span class="t"> <span class="com"># Apply image processing if enabled</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t418" href="#t418">418</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">image_processor</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t419" href="#t419">419</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t420" href="#t420">420</a></span><span class="t"> <span class="nam">pil_image</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">image_processor</span><span class="op">(</span><span class="nam">pil_image</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t421" href="#t421">421</a></span><span class="t"> <span class="key">except</span> <span class="nam">Exception</span> <span class="key">as</span> <span class="nam">e</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t422" href="#t422">422</a></span><span class="t"> <span class="nam">print</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Warning: Image processing failed for cover: </span><span class="op">{</span><span class="nam">str</span><span class="op">(</span><span class="nam">e</span><span class="op">)</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t423" href="#t423">423</a></span><span class="t"> <span class="com"># Continue with unprocessed image</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t424" href="#t424">424</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t425" href="#t425">425</a></span><span class="t"> <span class="com"># Create an AbstractImage block with the cover image path</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t426" href="#t426">426</a></span><span class="t"> <span class="nam">cover_image</span> <span class="op">=</span> <span class="nam">AbstractImage</span><span class="op">(</span><span class="nam">source</span><span class="op">=</span><span class="nam">cover_path</span><span class="op">,</span> <span class="nam">alt_text</span><span class="op">=</span><span class="str">"Cover Image"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t427" href="#t427">427</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t428" href="#t428">428</a></span><span class="t"> <span class="com"># Set dimensions from the loaded image</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t429" href="#t429">429</a></span><span class="t"> <span class="nam">cover_image</span><span class="op">.</span><span class="nam">_width</span> <span class="op">=</span> <span class="nam">pil_image</span><span class="op">.</span><span class="nam">width</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t430" href="#t430">430</a></span><span class="t"> <span class="nam">cover_image</span><span class="op">.</span><span class="nam">_height</span> <span class="op">=</span> <span class="nam">pil_image</span><span class="op">.</span><span class="nam">height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t431" href="#t431">431</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t432" href="#t432">432</a></span><span class="t"> <span class="com"># Store the loaded PIL image in the abstract image so it persists after</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t433" href="#t433">433</a></span><span class="t"> <span class="com"># temp cleanup</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t434" href="#t434">434</a></span><span class="t"> <span class="nam">cover_image</span><span class="op">.</span><span class="nam">_loaded_image</span> <span class="op">=</span> <span class="nam">pil_image</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t435" href="#t435">435</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t436" href="#t436">436</a></span><span class="t"> <span class="com"># Add the image to the cover chapter</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t437" href="#t437">437</a></span><span class="t"> <span class="nam">cover_chapter</span><span class="op">.</span><span class="nam">add_block</span><span class="op">(</span><span class="nam">cover_image</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t438" href="#t438">438</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t439" href="#t439">439</a></span><span class="t"> <span class="key">except</span> <span class="nam">Exception</span> <span class="key">as</span> <span class="nam">e</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t440" href="#t440">440</a></span><span class="t"> <span class="nam">print</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Error creating cover chapter: </span><span class="op">{</span><span class="nam">str</span><span class="op">(</span><span class="nam">e</span><span class="op">)</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t441" href="#t441">441</a></span><span class="t"> <span class="key">import</span> <span class="nam">traceback</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t442" href="#t442">442</a></span><span class="t"> <span class="nam">traceback</span><span class="op">.</span><span class="nam">print_exc</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t443" href="#t443">443</a></span><span class="t"> <span class="com"># If we can't create the cover image, remove the chapter</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t444" href="#t444">444</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">book</span><span class="op">,</span> <span class="str">'chapters'</span><span class="op">)</span> <span class="key">and</span> <span class="nam">cover_chapter</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">book</span><span class="op">.</span><span class="nam">chapters</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t445" href="#t445">445</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">book</span><span class="op">.</span><span class="nam">chapters</span><span class="op">.</span><span class="nam">remove</span><span class="op">(</span><span class="nam">cover_chapter</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t446" href="#t446">446</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t447" href="#t447">447</a></span><span class="t"> <span class="key">def</span> <span class="nam">_process_chapter_images</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">chapter</span><span class="op">:</span> <span class="nam">Chapter</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t448" href="#t448">448</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t449" href="#t449">449</a></span><span class="t"><span class="str"> Load and process images in a single chapter.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t450" href="#t450">450</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t451" href="#t451">451</a></span><span class="t"><span class="str"> This method loads images from disk into memory and applies image processing.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t452" href="#t452">452</a></span><span class="t"><span class="str"> Images must be loaded before the temporary EPUB directory is cleaned up.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t453" href="#t453">453</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t454" href="#t454">454</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t455" href="#t455">455</a></span><span class="t"><span class="str"> chapter: The chapter containing images to process</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t456" href="#t456">456</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t457" href="#t457">457</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">block</span> <span class="key">import</span> <span class="nam">Image</span> <span class="key">as</span> <span class="nam">AbstractImage</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t458" href="#t458">458</a></span><span class="t"> <span class="key">from</span> <span class="nam">PIL</span> <span class="key">import</span> <span class="nam">Image</span> <span class="key">as</span> <span class="nam">PILImage</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t459" href="#t459">459</a></span><span class="t"> <span class="key">import</span> <span class="nam">io</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t460" href="#t460">460</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t461" href="#t461">461</a></span><span class="t"> <span class="key">for</span> <span class="nam">block</span> <span class="key">in</span> <span class="nam">chapter</span><span class="op">.</span><span class="nam">blocks</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t462" href="#t462">462</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="nam">AbstractImage</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t463" href="#t463">463</a></span><span class="t"> <span class="com"># Load image into memory if not already loaded</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t464" href="#t464">464</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="str">'_loaded_image'</span><span class="op">)</span> <span class="key">or</span> <span class="key">not</span> <span class="nam">block</span><span class="op">.</span><span class="nam">_loaded_image</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">464&#x202F;&#x219B;&#x202F;485</span><span class="annotate long">line 464 didn't jump to line 485 because the condition on line 464 was always true</span></span></p>
<p class="run"><span class="n"><a id="t465" href="#t465">465</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t466" href="#t466">466</a></span><span class="t"> <span class="com"># Load the image from the source path</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t467" href="#t467">467</a></span><span class="t"> <span class="key">if</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">isfile</span><span class="op">(</span><span class="nam">block</span><span class="op">.</span><span class="nam">source</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">467&#x202F;&#x219B;&#x202F;485</span><span class="annotate long">line 467 didn't jump to line 485 because the condition on line 467 was always true</span></span></p>
<p class="run"><span class="n"><a id="t468" href="#t468">468</a></span><span class="t"> <span class="key">with</span> <span class="nam">open</span><span class="op">(</span><span class="nam">block</span><span class="op">.</span><span class="nam">source</span><span class="op">,</span> <span class="str">'rb'</span><span class="op">)</span> <span class="key">as</span> <span class="nam">f</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t469" href="#t469">469</a></span><span class="t"> <span class="nam">image_bytes</span> <span class="op">=</span> <span class="nam">f</span><span class="op">.</span><span class="nam">read</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t470" href="#t470">470</a></span><span class="t"> <span class="com"># Create PIL image from bytes in memory</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t471" href="#t471">471</a></span><span class="t"> <span class="nam">pil_image</span> <span class="op">=</span> <span class="nam">PILImage</span><span class="op">.</span><span class="nam">open</span><span class="op">(</span><span class="nam">io</span><span class="op">.</span><span class="nam">BytesIO</span><span class="op">(</span><span class="nam">image_bytes</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t472" href="#t472">472</a></span><span class="t"> <span class="nam">pil_image</span><span class="op">.</span><span class="nam">load</span><span class="op">(</span><span class="op">)</span> <span class="com"># Force loading into memory</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t473" href="#t473">473</a></span><span class="t"> <span class="nam">block</span><span class="op">.</span><span class="nam">_loaded_image</span> <span class="op">=</span> <span class="nam">pil_image</span><span class="op">.</span><span class="nam">copy</span><span class="op">(</span><span class="op">)</span> <span class="com"># Create a copy to ensure it persists</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t474" href="#t474">474</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t475" href="#t475">475</a></span><span class="t"> <span class="com"># Set width and height on the block from the loaded image</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t476" href="#t476">476</a></span><span class="t"> <span class="com"># This is required for layout calculations</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t477" href="#t477">477</a></span><span class="t"> <span class="nam">block</span><span class="op">.</span><span class="nam">_width</span> <span class="op">=</span> <span class="nam">pil_image</span><span class="op">.</span><span class="nam">width</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t478" href="#t478">478</a></span><span class="t"> <span class="nam">block</span><span class="op">.</span><span class="nam">_height</span> <span class="op">=</span> <span class="nam">pil_image</span><span class="op">.</span><span class="nam">height</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t479" href="#t479">479</a></span><span class="t"> <span class="key">except</span> <span class="nam">Exception</span> <span class="key">as</span> <span class="nam">e</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t480" href="#t480">480</a></span><span class="t"> <span class="nam">print</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Warning: Failed to load image '</span><span class="op">{</span><span class="nam">block</span><span class="op">.</span><span class="nam">source</span><span class="op">}</span><span class="fst">': </span><span class="op">{</span><span class="nam">str</span><span class="op">(</span><span class="nam">e</span><span class="op">)</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t481" href="#t481">481</a></span><span class="t"> <span class="com"># Continue without the image</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t482" href="#t482">482</a></span><span class="t"> <span class="key">continue</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t483" href="#t483">483</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t484" href="#t484">484</a></span><span class="t"> <span class="com"># Apply image processing if enabled and image is loaded</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t485" href="#t485">485</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">image_processor</span> <span class="key">and</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="str">'_loaded_image'</span><span class="op">)</span> <span class="key">and</span> <span class="nam">block</span><span class="op">.</span><span class="nam">_loaded_image</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t486" href="#t486">486</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t487" href="#t487">487</a></span><span class="t"> <span class="nam">block</span><span class="op">.</span><span class="nam">_loaded_image</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">image_processor</span><span class="op">(</span><span class="nam">block</span><span class="op">.</span><span class="nam">_loaded_image</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t488" href="#t488">488</a></span><span class="t"> <span class="key">except</span> <span class="nam">Exception</span> <span class="key">as</span> <span class="nam">e</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t489" href="#t489">489</a></span><span class="t"> <span class="nam">print</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t490" href="#t490">490</a></span><span class="t"> <span class="fst">f"</span><span class="fst">Warning: Image processing failed for image '</span><span class="op">{</span><span class="nam">block</span><span class="op">.</span><span class="nam">alt_text</span><span class="op">}</span><span class="fst">': </span><span class="op">{</span><span class="nam">str</span><span class="op">(</span><span class="nam">e</span><span class="op">)</span><span class="op">}</span><span class="fst">"</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t491" href="#t491">491</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t492" href="#t492">492</a></span><span class="t"> <span class="com"># Continue with unprocessed image</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t493" href="#t493">493</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t494" href="#t494">494</a></span><span class="t"> <span class="key">def</span> <span class="nam">_process_content_images</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t495" href="#t495">495</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t496" href="#t496">496</a></span><span class="t"><span class="str"> Load all images into memory and apply image processing.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t497" href="#t497">497</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t498" href="#t498">498</a></span><span class="t"><span class="str"> This must be called before the temporary EPUB directory is cleaned up,</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t499" href="#t499">499</a></span><span class="t"><span class="str"> to ensure images are loaded from disk into memory.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t500" href="#t500">500</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t501" href="#t501">501</a></span><span class="t"> <span class="key">for</span> <span class="nam">chapter</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">book</span><span class="op">.</span><span class="nam">chapters</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t502" href="#t502">502</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_process_chapter_images</span><span class="op">(</span><span class="nam">chapter</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t503" href="#t503">503</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t504" href="#t504">504</a></span><span class="t"> <span class="key">def</span> <span class="nam">_add_chapters</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t505" href="#t505">505</a></span><span class="t"> <span class="str">"""Add chapters to the book based on the spine and TOC."""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t506" href="#t506">506</a></span><span class="t"> <span class="com"># Add cover chapter first if available</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t507" href="#t507">507</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_add_cover_chapter</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t508" href="#t508">508</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t509" href="#t509">509</a></span><span class="t"> <span class="com"># Create a mapping from src to TOC entry</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t510" href="#t510">510</a></span><span class="t"> <span class="nam">toc_map</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t511" href="#t511">511</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t512" href="#t512">512</a></span><span class="t"> <span class="key">def</span> <span class="nam">add_to_toc_map</span><span class="op">(</span><span class="nam">entries</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t513" href="#t513">513</a></span><span class="t"> <span class="key">for</span> <span class="nam">entry</span> <span class="key">in</span> <span class="nam">entries</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t514" href="#t514">514</a></span><span class="t"> <span class="key">if</span> <span class="nam">entry</span><span class="op">[</span><span class="str">'src'</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">514&#x202F;&#x219B;&#x202F;521</span><span class="annotate long">line 514 didn't jump to line 521 because the condition on line 514 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t515" href="#t515">515</a></span><span class="t"> <span class="com"># Extract the path part of the src (remove fragment)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t516" href="#t516">516</a></span><span class="t"> <span class="nam">src_parts</span> <span class="op">=</span> <span class="nam">entry</span><span class="op">[</span><span class="str">'src'</span><span class="op">]</span><span class="op">.</span><span class="nam">split</span><span class="op">(</span><span class="str">'#'</span><span class="op">,</span> <span class="num">1</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t517" href="#t517">517</a></span><span class="t"> <span class="nam">path</span> <span class="op">=</span> <span class="nam">src_parts</span><span class="op">[</span><span class="num">0</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t518" href="#t518">518</a></span><span class="t"> <span class="nam">toc_map</span><span class="op">[</span><span class="nam">path</span><span class="op">]</span> <span class="op">=</span> <span class="nam">entry</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t519" href="#t519">519</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t520" href="#t520">520</a></span><span class="t"> <span class="com"># Process children</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t521" href="#t521">521</a></span><span class="t"> <span class="key">if</span> <span class="nam">entry</span><span class="op">[</span><span class="str">'children'</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">521&#x202F;&#x219B;&#x202F;522</span><span class="annotate long">line 521 didn't jump to line 522 because the condition on line 521 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t522" href="#t522">522</a></span><span class="t"> <span class="nam">add_to_toc_map</span><span class="op">(</span><span class="nam">entry</span><span class="op">[</span><span class="str">'children'</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t523" href="#t523">523</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t524" href="#t524">524</a></span><span class="t"> <span class="nam">add_to_toc_map</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">toc</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t525" href="#t525">525</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t526" href="#t526">526</a></span><span class="t"> <span class="com"># Process spine items</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t527" href="#t527">527</a></span><span class="t"> <span class="com"># Start from chapter_index = 1 if cover was added, otherwise 0</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t528" href="#t528">528</a></span><span class="t"> <span class="nam">chapter_index</span> <span class="op">=</span> <span class="num">1</span> <span class="key">if</span> <span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">cover_id</span> <span class="key">and</span> <span class="nam">self</span><span class="op">.</span><span class="nam">cover_id</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">manifest</span><span class="op">)</span> <span class="key">else</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t529" href="#t529">529</a></span><span class="t"> <span class="key">for</span> <span class="nam">i</span><span class="op">,</span> <span class="nam">idref</span> <span class="key">in</span> <span class="nam">enumerate</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">spine</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t530" href="#t530">530</a></span><span class="t"> <span class="key">if</span> <span class="nam">idref</span> <span class="key">not</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">manifest</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">530&#x202F;&#x219B;&#x202F;531</span><span class="annotate long">line 530 didn't jump to line 531 because the condition on line 530 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t531" href="#t531">531</a></span><span class="t"> <span class="key">continue</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t532" href="#t532">532</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t533" href="#t533">533</a></span><span class="t"> <span class="nam">item</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">manifest</span><span class="op">[</span><span class="nam">idref</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t534" href="#t534">534</a></span><span class="t"> <span class="nam">path</span> <span class="op">=</span> <span class="nam">item</span><span class="op">[</span><span class="str">'path'</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t535" href="#t535">535</a></span><span class="t"> <span class="nam">href</span> <span class="op">=</span> <span class="nam">item</span><span class="op">[</span><span class="str">'href'</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t536" href="#t536">536</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t537" href="#t537">537</a></span><span class="t"> <span class="com"># Skip navigation files</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t538" href="#t538">538</a></span><span class="t"> <span class="key">if</span> <span class="op">(</span><span class="nam">idref</span> <span class="op">==</span> <span class="str">'nav'</span> <span class="key">or</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t539" href="#t539">539</a></span><span class="t"> <span class="nam">item</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="str">'media_type'</span><span class="op">)</span> <span class="op">==</span> <span class="str">'application/xhtml+xml'</span> <span class="key">and</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t540" href="#t540">540</a></span><span class="t"> <span class="op">(</span><span class="str">'nav'</span> <span class="key">in</span> <span class="nam">href</span><span class="op">.</span><span class="nam">lower</span><span class="op">(</span><span class="op">)</span> <span class="key">or</span> <span class="str">'toc'</span> <span class="key">in</span> <span class="nam">href</span><span class="op">.</span><span class="nam">lower</span><span class="op">(</span><span class="op">)</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t541" href="#t541">541</a></span><span class="t"> <span class="key">continue</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t542" href="#t542">542</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t543" href="#t543">543</a></span><span class="t"> <span class="com"># Check if this item is in the TOC</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t544" href="#t544">544</a></span><span class="t"> <span class="nam">chapter_title</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t545" href="#t545">545</a></span><span class="t"> <span class="key">if</span> <span class="nam">href</span> <span class="key">in</span> <span class="nam">toc_map</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">545&#x202F;&#x219B;&#x202F;549</span><span class="annotate long">line 545 didn't jump to line 549 because the condition on line 545 was always true</span></span></p>
<p class="run"><span class="n"><a id="t546" href="#t546">546</a></span><span class="t"> <span class="nam">chapter_title</span> <span class="op">=</span> <span class="nam">toc_map</span><span class="op">[</span><span class="nam">href</span><span class="op">]</span><span class="op">[</span><span class="str">'label'</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t547" href="#t547">547</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t548" href="#t548">548</a></span><span class="t"> <span class="com"># Create a chapter</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t549" href="#t549">549</a></span><span class="t"> <span class="nam">chapter_index</span> <span class="op">+=</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t550" href="#t550">550</a></span><span class="t"> <span class="nam">chapter</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">book</span><span class="op">.</span><span class="nam">create_chapter</span><span class="op">(</span><span class="nam">chapter_title</span><span class="op">,</span> <span class="nam">chapter_index</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t551" href="#t551">551</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t552" href="#t552">552</a></span><span class="t"> <span class="com"># Parse the HTML content</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t553" href="#t553">553</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t554" href="#t554">554</a></span><span class="t"> <span class="com"># Read the HTML file</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t555" href="#t555">555</a></span><span class="t"> <span class="key">with</span> <span class="nam">open</span><span class="op">(</span><span class="nam">path</span><span class="op">,</span> <span class="str">'r'</span><span class="op">,</span> <span class="nam">encoding</span><span class="op">=</span><span class="str">'utf-8'</span><span class="op">)</span> <span class="key">as</span> <span class="nam">f</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t556" href="#t556">556</a></span><span class="t"> <span class="nam">html</span> <span class="op">=</span> <span class="nam">f</span><span class="op">.</span><span class="nam">read</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t557" href="#t557">557</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t558" href="#t558">558</a></span><span class="t"> <span class="com"># Get the directory of the HTML file for resolving relative paths</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t559" href="#t559">559</a></span><span class="t"> <span class="nam">html_dir</span> <span class="op">=</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">dirname</span><span class="op">(</span><span class="nam">path</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t560" href="#t560">560</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t561" href="#t561">561</a></span><span class="t"> <span class="com"># Parse HTML and add blocks to chapter, passing base_path for image resolution</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t562" href="#t562">562</a></span><span class="t"> <span class="nam">blocks</span> <span class="op">=</span> <span class="nam">parse_html_string</span><span class="op">(</span><span class="nam">html</span><span class="op">,</span> <span class="nam">document</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">book</span><span class="op">,</span> <span class="nam">base_path</span><span class="op">=</span><span class="nam">html_dir</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t563" href="#t563">563</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t564" href="#t564">564</a></span><span class="t"> <span class="com"># Copy blocks to the chapter</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t565" href="#t565">565</a></span><span class="t"> <span class="key">for</span> <span class="nam">block</span> <span class="key">in</span> <span class="nam">blocks</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t566" href="#t566">566</a></span><span class="t"> <span class="nam">chapter</span><span class="op">.</span><span class="nam">add_block</span><span class="op">(</span><span class="nam">block</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t567" href="#t567">567</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t568" href="#t568">568</a></span><span class="t"> <span class="com"># Add a PageBreak after the chapter to ensure next chapter starts on new page</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t569" href="#t569">569</a></span><span class="t"> <span class="com"># This helps maintain chapter boundaries during pagination</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t570" href="#t570">570</a></span><span class="t"> <span class="nam">chapter</span><span class="op">.</span><span class="nam">add_block</span><span class="op">(</span><span class="nam">PageBreak</span><span class="op">(</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t571" href="#t571">571</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t572" href="#t572">572</a></span><span class="t"> <span class="key">except</span> <span class="nam">Exception</span> <span class="key">as</span> <span class="nam">e</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t573" href="#t573">573</a></span><span class="t"> <span class="nam">print</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Error parsing chapter </span><span class="op">{</span><span class="nam">i</span> <span class="op">+</span> <span class="num">1</span><span class="op">}</span><span class="fst">: </span><span class="op">{</span><span class="nam">str</span><span class="op">(</span><span class="nam">e</span><span class="op">)</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t574" href="#t574">574</a></span><span class="t"> <span class="com"># Add an error message block</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t575" href="#t575">575</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">block</span> <span class="key">import</span> <span class="nam">Paragraph</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t576" href="#t576">576</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">inline</span> <span class="key">import</span> <span class="nam">Word</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t577" href="#t577">577</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span> <span class="key">import</span> <span class="nam">Font</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t578" href="#t578">578</a></span><span class="t"> <span class="nam">error_para</span> <span class="op">=</span> <span class="nam">Paragraph</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t579" href="#t579">579</a></span><span class="t"> <span class="com"># Create a default font style for the error message</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t580" href="#t580">580</a></span><span class="t"> <span class="nam">default_font</span> <span class="op">=</span> <span class="nam">Font</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t581" href="#t581">581</a></span><span class="t"> <span class="nam">error_para</span><span class="op">.</span><span class="nam">add_word</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t582" href="#t582">582</a></span><span class="t"> <span class="nam">Word</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t583" href="#t583">583</a></span><span class="t"> <span class="fst">f"</span><span class="fst">Error loading chapter: </span><span class="op">{</span><span class="nam">str</span><span class="op">(</span><span class="nam">e</span><span class="op">)</span><span class="op">}</span><span class="fst">"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t584" href="#t584">584</a></span><span class="t"> <span class="nam">default_font</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t585" href="#t585">585</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t586" href="#t586">586</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t587" href="#t587">587</a></span><span class="t"> <span class="nam">chapter</span><span class="op">.</span><span class="nam">add_block</span><span class="op">(</span><span class="nam">error_para</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t588" href="#t588">588</a></span><span class="t"> <span class="com"># Still add PageBreak even after error</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t589" href="#t589">589</a></span><span class="t"> <span class="nam">chapter</span><span class="op">.</span><span class="nam">add_block</span><span class="op">(</span><span class="nam">PageBreak</span><span class="op">(</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t590" href="#t590">590</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t591" href="#t591">591</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t592" href="#t592">592</a></span><span class="t"><span class="key">def</span> <span class="nam">read_epub</span><span class="op">(</span><span class="nam">epub_path</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Book</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t593" href="#t593">593</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t594" href="#t594">594</a></span><span class="t"><span class="str"> Read an EPUB file and convert it to a Book.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t595" href="#t595">595</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t596" href="#t596">596</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t597" href="#t597">597</a></span><span class="t"><span class="str"> epub_path: Path to the EPUB file</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t598" href="#t598">598</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t599" href="#t599">599</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t600" href="#t600">600</a></span><span class="t"><span class="str"> Book: The parsed book</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t601" href="#t601">601</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t602" href="#t602">602</a></span><span class="t"> <span class="nam">reader</span> <span class="op">=</span> <span class="nam">EPUBReader</span><span class="op">(</span><span class="nam">epub_path</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t603" href="#t603">603</a></span><span class="t"> <span class="key">return</span> <span class="nam">reader</span><span class="op">.</span><span class="nam">read</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_263f2e628cef8c50___init___py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_263f2e628cef8c50_html_extraction_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,133 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/core/__init__.py: 100%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/core/__init__.py</b>:
<span class="pc_cov">100%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">2 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">2<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">0<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">1<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">0<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_7d48e1f4c6486fa2_text_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_40407af872b0cf37_base_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">Core functionality for the pyWebLayout library.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">This package contains the core abstractions and base classes that form the foundation</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">of the pyWebLayout rendering system.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">base</span> <span class="key">import</span> <span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"> <span class="nam">Renderable</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"> <span class="nam">Interactable</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"> <span class="nam">Layoutable</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"> <span class="nam">Queriable</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"> <span class="nam">Hierarchical</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t"> <span class="nam">Geometric</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"> <span class="nam">Styleable</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"> <span class="nam">FontRegistry</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"> <span class="nam">MetadataContainer</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"> <span class="nam">BlockContainer</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"> <span class="nam">ContainerAware</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"><span class="nam">__all__</span> <span class="op">=</span> <span class="op">[</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"> <span class="str">'Renderable'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"> <span class="str">'Interactable'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"> <span class="str">'Layoutable'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"> <span class="str">'Queriable'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"> <span class="str">'Hierarchical'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t"> <span class="str">'Geometric'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"> <span class="str">'Styleable'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"> <span class="str">'FontRegistry'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"> <span class="str">'MetadataContainer'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"> <span class="str">'BlockContainer'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"> <span class="str">'ContainerAware'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_7d48e1f4c6486fa2_text_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_40407af872b0cf37_base_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,547 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/core/base.py: 72%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/core/base.py</b>:
<span class="pc_cov">72%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">134 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">105<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">29<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">33<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">3<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_40407af872b0cf37___init___py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_40407af872b0cf37_callback_registry_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="run"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="key">from</span> <span class="nam">abc</span> <span class="key">import</span> <span class="nam">ABC</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">Tuple</span><span class="op">,</span> <span class="nam">TYPE_CHECKING</span><span class="op">,</span> <span class="nam">Any</span><span class="op">,</span> <span class="nam">Dict</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t"><span class="key">import</span> <span class="nam">numpy</span> <span class="key">as</span> <span class="nam">np</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="key">if</span> <span class="nam">TYPE_CHECKING</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">6&#x202F;&#x219B;&#x202F;7</span><span class="annotate long">line 6 didn't jump to line 7 because the condition on line 6 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span> <span class="key">import</span> <span class="nam">Font</span><span class="op">,</span> <span class="nam">FontWeight</span><span class="op">,</span> <span class="nam">FontStyle</span><span class="op">,</span> <span class="nam">TextDecoration</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="key">class</span> <span class="nam">Renderable</span><span class="op">(</span><span class="nam">ABC</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="str"> Abstract base class for any object that can be rendered to an image.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"><span class="str"> All renderable objects must implement the render method.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"> <span class="key">def</span> <span class="nam">render</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"><span class="str"> Render the object to an image.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"><span class="str"> PIL.Image: The rendered image</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"> <span class="key">def</span> <span class="nam">origin</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"><span class="key">class</span> <span class="nam">Interactable</span><span class="op">(</span><span class="nam">ABC</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"><span class="str"> Abstract base class for any object that can be interacted with.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"><span class="str"> Interactable objects must have a callback that is executed when interacted with.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">callback</span><span class="op">=</span><span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"><span class="str"> Initialize an interactable object.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"><span class="str"> callback: The function to call when this object is interacted with</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_callback</span> <span class="op">=</span> <span class="nam">callback</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"> <span class="key">def</span> <span class="nam">interact</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">point</span><span class="op">:</span> <span class="nam">np</span><span class="op">.</span><span class="nam">generic</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"><span class="str"> Handle interaction at the given point.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t"><span class="str"> point: The coordinates of the interaction</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t"><span class="str"> The result of calling the callback function with the point</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_callback</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">54&#x202F;&#x219B;&#x202F;55</span><span class="annotate long">line 54 didn't jump to line 55 because the condition on line 54 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_callback</span><span class="op">(</span><span class="nam">point</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"><span class="key">class</span> <span class="nam">Layoutable</span><span class="op">(</span><span class="nam">ABC</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"><span class="str"> Abstract base class for any object that can be laid out.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t"><span class="str"> Layoutable objects must implement the layout method which arranges their contents.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"> <span class="key">def</span> <span class="nam">layout</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t"><span class="str"> Layout the object's contents.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"><span class="str"> This method should be called before rendering to properly arrange the object's contents.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t"><span class="key">class</span> <span class="nam">Queriable</span><span class="op">(</span><span class="nam">ABC</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t"> <span class="key">def</span> <span class="nam">in_object</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">point</span><span class="op">:</span> <span class="nam">np</span><span class="op">.</span><span class="nam">generic</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t"><span class="str"> check if a point is in the object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"> <span class="nam">point_array</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="nam">point</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t"> <span class="nam">relative_point</span> <span class="op">=</span> <span class="nam">point_array</span> <span class="op">-</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t"> <span class="key">return</span> <span class="nam">np</span><span class="op">.</span><span class="nam">all</span><span class="op">(</span><span class="op">(</span><span class="num">0</span> <span class="op">&lt;=</span> <span class="nam">relative_point</span><span class="op">)</span> <span class="op">&amp;</span> <span class="op">(</span><span class="nam">relative_point</span> <span class="op">&lt;</span> <span class="nam">self</span><span class="op">.</span><span class="nam">size</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t"><span class="com"># ==============================================================================</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"><span class="com"># Mixins - Reusable components for common patterns</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t"><span class="com"># ==============================================================================</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t"><span class="key">class</span> <span class="nam">Hierarchical</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t"><span class="str"> Mixin providing parent-child relationship management.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t"><span class="str"> Classes using this mixin can track their parent in a document hierarchy.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="op">*</span><span class="nam">args</span><span class="op">,</span> <span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="op">*</span><span class="nam">args</span><span class="op">,</span> <span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_parent</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Any</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t"> <span class="key">def</span> <span class="nam">parent</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Any</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"> <span class="str">"""Get the parent object containing this object, if any"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_parent</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t"> <span class="op">@</span><span class="nam">parent</span><span class="op">.</span><span class="nam">setter</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t"> <span class="key">def</span> <span class="nam">parent</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">parent</span><span class="op">:</span> <span class="nam">Any</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t"> <span class="str">"""Set the parent object"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_parent</span> <span class="op">=</span> <span class="nam">parent</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"><span class="key">class</span> <span class="nam">Geometric</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"><span class="str"> Mixin providing origin and size properties for positioned elements.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t"><span class="str"> Provides standard geometric properties for elements that have a position</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t"><span class="str"> and size in 2D space. Uses numpy arrays for efficient calculations.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="op">*</span><span class="nam">args</span><span class="op">,</span> <span class="nam">origin</span><span class="op">=</span><span class="key">None</span><span class="op">,</span> <span class="nam">size</span><span class="op">=</span><span class="key">None</span><span class="op">,</span> <span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="op">*</span><span class="nam">args</span><span class="op">,</span> <span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="nam">origin</span><span class="op">)</span> <span class="key">if</span> <span class="nam">origin</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span> <span class="key">else</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="op">[</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="nam">size</span><span class="op">)</span> <span class="key">if</span> <span class="nam">size</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span> <span class="key">else</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="op">[</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t"> <span class="key">def</span> <span class="nam">origin</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">np</span><span class="op">.</span><span class="nam">ndarray</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t"> <span class="str">"""Get the origin (top-left corner) of the element"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t"> <span class="op">@</span><span class="nam">origin</span><span class="op">.</span><span class="nam">setter</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t"> <span class="key">def</span> <span class="nam">origin</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">origin</span><span class="op">:</span> <span class="nam">np</span><span class="op">.</span><span class="nam">ndarray</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t"> <span class="str">"""Set the origin of the element"""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="nam">origin</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t"> <span class="key">def</span> <span class="nam">size</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">np</span><span class="op">.</span><span class="nam">ndarray</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t"> <span class="str">"""Get the size (width, height) of the element"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"> <span class="op">@</span><span class="nam">size</span><span class="op">.</span><span class="nam">setter</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t"> <span class="key">def</span> <span class="nam">size</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">size</span><span class="op">:</span> <span class="nam">np</span><span class="op">.</span><span class="nam">ndarray</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t"> <span class="str">"""Set the size of the element"""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="nam">size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_origin</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">origin</span><span class="op">:</span> <span class="nam">np</span><span class="op">.</span><span class="nam">ndarray</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"> <span class="str">"""Set the origin of this element (alternative setter method)"""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="nam">origin</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"><span class="key">class</span> <span class="nam">Styleable</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t"><span class="str"> Mixin providing style property management.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t"><span class="str"> Classes using this mixin can have a style property that can be</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t"><span class="str"> inherited from parents or set explicitly.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="op">*</span><span class="nam">args</span><span class="op">,</span> <span class="nam">style</span><span class="op">=</span><span class="key">None</span><span class="op">,</span> <span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="op">*</span><span class="nam">args</span><span class="op">,</span> <span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span> <span class="op">=</span> <span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t"> <span class="key">def</span> <span class="nam">style</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Any</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t"> <span class="str">"""Get the style for this element"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t"> <span class="op">@</span><span class="nam">style</span><span class="op">.</span><span class="nam">setter</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"> <span class="key">def</span> <span class="nam">style</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">style</span><span class="op">:</span> <span class="nam">Any</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t"> <span class="str">"""Set the style for this element"""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span> <span class="op">=</span> <span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t"><span class="key">class</span> <span class="nam">FontRegistry</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t"><span class="str"> Mixin providing font caching and creation with parent delegation.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t"><span class="str"> This mixin allows classes to maintain a local font registry and create/reuse</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t"><span class="str"> Font objects efficiently. It supports parent delegation, where font requests</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t"><span class="str"> can cascade up to a parent container if one exists.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t"><span class="str"> Classes using this mixin should also use Hierarchical to support parent delegation.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="op">*</span><span class="nam">args</span><span class="op">,</span> <span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="op">*</span><span class="nam">args</span><span class="op">,</span> <span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_fonts</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="str">'Font'</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_or_create_font</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t"> <span class="nam">font_path</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t"> <span class="nam">font_size</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">16</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t"> <span class="nam">colour</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t"> <span class="nam">weight</span><span class="op">:</span> <span class="str">'FontWeight'</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t"> <span class="nam">style</span><span class="op">:</span> <span class="str">'FontStyle'</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t"> <span class="nam">decoration</span><span class="op">:</span> <span class="str">'TextDecoration'</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t"> <span class="nam">background</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t"> <span class="nam">language</span><span class="op">:</span> <span class="nam">str</span> <span class="op">=</span> <span class="str">"en_EN"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t"> <span class="nam">min_hyphenation_width</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="str">'Font'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"><span class="str"> Get or create a font with the specified properties.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t"><span class="str"> This method will first check if a parent object has a get_or_create_font</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t"><span class="str"> method and delegate to it. Otherwise, it will manage fonts locally.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t"><span class="str"> font_path: Path to the font file (.ttf, .otf). If None, uses default font.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t"><span class="str"> font_size: Size of the font in points.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t"><span class="str"> colour: RGB color tuple for the text.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t"><span class="str"> weight: Font weight (normal or bold).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t"><span class="str"> style: Font style (normal or italic).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"><span class="str"> decoration: Text decoration (none, underline, or strikethrough).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t"><span class="str"> background: RGBA background color for the text. If None, transparent background.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t"><span class="str"> language: Language code for hyphenation and text processing.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t"><span class="str"> min_hyphenation_width: Minimum width in pixels required for hyphenation.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t"><span class="str"> Font object (either existing or newly created)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t"> <span class="com"># Import here to avoid circular imports</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span> <span class="key">import</span> <span class="nam">Font</span><span class="op">,</span> <span class="nam">FontWeight</span><span class="op">,</span> <span class="nam">FontStyle</span><span class="op">,</span> <span class="nam">TextDecoration</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t"> <span class="com"># Set defaults for enum types</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t"> <span class="key">if</span> <span class="nam">weight</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t"> <span class="nam">weight</span> <span class="op">=</span> <span class="nam">FontWeight</span><span class="op">.</span><span class="nam">NORMAL</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"> <span class="key">if</span> <span class="nam">style</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t"> <span class="nam">style</span> <span class="op">=</span> <span class="nam">FontStyle</span><span class="op">.</span><span class="nam">NORMAL</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t"> <span class="key">if</span> <span class="nam">decoration</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t"> <span class="nam">decoration</span> <span class="op">=</span> <span class="nam">TextDecoration</span><span class="op">.</span><span class="nam">NONE</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t"> <span class="com"># If we have a parent with font management, delegate to parent</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t"> <span class="str">'_parent'</span><span class="op">)</span> <span class="key">and</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_parent</span> <span class="key">and</span> <span class="nam">hasattr</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_parent</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t"> <span class="str">'get_or_create_font'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_parent</span><span class="op">.</span><span class="nam">get_or_create_font</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t"> <span class="nam">font_path</span><span class="op">=</span><span class="nam">font_path</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t"> <span class="nam">font_size</span><span class="op">=</span><span class="nam">font_size</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t"> <span class="nam">colour</span><span class="op">=</span><span class="nam">colour</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t"> <span class="nam">weight</span><span class="op">=</span><span class="nam">weight</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t"> <span class="nam">style</span><span class="op">=</span><span class="nam">style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t"> <span class="nam">decoration</span><span class="op">=</span><span class="nam">decoration</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t"> <span class="nam">background</span><span class="op">=</span><span class="nam">background</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t"> <span class="nam">language</span><span class="op">=</span><span class="nam">language</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t"> <span class="nam">min_hyphenation_width</span><span class="op">=</span><span class="nam">min_hyphenation_width</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t"> <span class="com"># Otherwise manage our own fonts</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t"> <span class="com"># Create a unique key for this font configuration</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t"> <span class="nam">bg_tuple</span> <span class="op">=</span> <span class="nam">background</span> <span class="key">if</span> <span class="nam">background</span> <span class="key">else</span> <span class="op">(</span><span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t"> <span class="nam">min_hyph_width</span> <span class="op">=</span> <span class="nam">min_hyphenation_width</span> <span class="key">if</span> <span class="nam">min_hyphenation_width</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span> <span class="key">else</span> <span class="nam">font_size</span> <span class="op">*</span> <span class="num">4</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t"> <span class="nam">font_key</span> <span class="op">=</span> <span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t"> <span class="nam">font_path</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t"> <span class="nam">font_size</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t"> <span class="nam">colour</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t"> <span class="nam">weight</span><span class="op">.</span><span class="nam">value</span> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">weight</span><span class="op">,</span> <span class="str">'value'</span><span class="op">)</span> <span class="key">else</span> <span class="nam">weight</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t"> <span class="nam">style</span><span class="op">.</span><span class="nam">value</span> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">style</span><span class="op">,</span> <span class="str">'value'</span><span class="op">)</span> <span class="key">else</span> <span class="nam">style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t"> <span class="nam">decoration</span><span class="op">.</span><span class="nam">value</span> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">decoration</span><span class="op">,</span> <span class="str">'value'</span><span class="op">)</span> <span class="key">else</span> <span class="nam">decoration</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t"> <span class="nam">bg_tuple</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t"> <span class="nam">language</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t"> <span class="nam">min_hyph_width</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t"> <span class="com"># Convert tuple to string for dictionary key</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t"> <span class="nam">key_str</span> <span class="op">=</span> <span class="nam">str</span><span class="op">(</span><span class="nam">font_key</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t"> <span class="com"># Check if we already have this font</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t"> <span class="key">if</span> <span class="nam">key_str</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_fonts</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_fonts</span><span class="op">[</span><span class="nam">key_str</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t"> <span class="com"># Create new font and store it</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t"> <span class="nam">new_font</span> <span class="op">=</span> <span class="nam">Font</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t"> <span class="nam">font_path</span><span class="op">=</span><span class="nam">font_path</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t"> <span class="nam">font_size</span><span class="op">=</span><span class="nam">font_size</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t"> <span class="nam">colour</span><span class="op">=</span><span class="nam">colour</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t"> <span class="nam">weight</span><span class="op">=</span><span class="nam">weight</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t"> <span class="nam">style</span><span class="op">=</span><span class="nam">style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t"> <span class="nam">decoration</span><span class="op">=</span><span class="nam">decoration</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t"> <span class="nam">background</span><span class="op">=</span><span class="nam">background</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t"> <span class="nam">language</span><span class="op">=</span><span class="nam">language</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t279" href="#t279">279</a></span><span class="t"> <span class="nam">min_hyphenation_width</span><span class="op">=</span><span class="nam">min_hyphenation_width</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t280" href="#t280">280</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t281" href="#t281">281</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t282" href="#t282">282</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_fonts</span><span class="op">[</span><span class="nam">key_str</span><span class="op">]</span> <span class="op">=</span> <span class="nam">new_font</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t283" href="#t283">283</a></span><span class="t"> <span class="key">return</span> <span class="nam">new_font</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t284" href="#t284">284</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t285" href="#t285">285</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t286" href="#t286">286</a></span><span class="t"><span class="key">class</span> <span class="nam">MetadataContainer</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t287" href="#t287">287</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t288" href="#t288">288</a></span><span class="t"><span class="str"> Mixin providing metadata dictionary management.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t289" href="#t289">289</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t290" href="#t290">290</a></span><span class="t"><span class="str"> Allows classes to store and retrieve arbitrary metadata as key-value pairs.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t291" href="#t291">291</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t292" href="#t292">292</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t293" href="#t293">293</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="op">*</span><span class="nam">args</span><span class="op">,</span> <span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t294" href="#t294">294</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="op">*</span><span class="nam">args</span><span class="op">,</span> <span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t295" href="#t295">295</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_metadata</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">Any</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t296" href="#t296">296</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t297" href="#t297">297</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_metadata</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">key</span><span class="op">:</span> <span class="nam">Any</span><span class="op">,</span> <span class="nam">value</span><span class="op">:</span> <span class="nam">Any</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t298" href="#t298">298</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t299" href="#t299">299</a></span><span class="t"><span class="str"> Set a metadata value.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t300" href="#t300">300</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t301" href="#t301">301</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t302" href="#t302">302</a></span><span class="t"><span class="str"> key: The metadata key</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t303" href="#t303">303</a></span><span class="t"><span class="str"> value: The metadata value</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t304" href="#t304">304</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t305" href="#t305">305</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_metadata</span><span class="op">[</span><span class="nam">key</span><span class="op">]</span> <span class="op">=</span> <span class="nam">value</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t306" href="#t306">306</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t307" href="#t307">307</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_metadata</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">key</span><span class="op">:</span> <span class="nam">Any</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Any</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t308" href="#t308">308</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t309" href="#t309">309</a></span><span class="t"><span class="str"> Get a metadata value.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t310" href="#t310">310</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t311" href="#t311">311</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t312" href="#t312">312</a></span><span class="t"><span class="str"> key: The metadata key</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t313" href="#t313">313</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t314" href="#t314">314</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t315" href="#t315">315</a></span><span class="t"><span class="str"> The metadata value, or None if not set</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t316" href="#t316">316</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t317" href="#t317">317</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_metadata</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="nam">key</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t318" href="#t318">318</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t319" href="#t319">319</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t320" href="#t320">320</a></span><span class="t"><span class="key">class</span> <span class="nam">BlockContainer</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t321" href="#t321">321</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t322" href="#t322">322</a></span><span class="t"><span class="str"> Mixin providing block management methods.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t323" href="#t323">323</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t324" href="#t324">324</a></span><span class="t"><span class="str"> Provides standard methods for managing block-level children including</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t325" href="#t325">325</a></span><span class="t"><span class="str"> adding blocks and creating common block types.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t326" href="#t326">326</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t327" href="#t327">327</a></span><span class="t"><span class="str"> Classes using this mixin should also use Styleable to support style inheritance.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t328" href="#t328">328</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t329" href="#t329">329</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t330" href="#t330">330</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="op">*</span><span class="nam">args</span><span class="op">,</span> <span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t331" href="#t331">331</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="op">*</span><span class="nam">args</span><span class="op">,</span> <span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t332" href="#t332">332</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_blocks</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t333" href="#t333">333</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t334" href="#t334">334</a></span><span class="t"> <span class="key">def</span> <span class="nam">blocks</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t335" href="#t335">335</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t336" href="#t336">336</a></span><span class="t"><span class="str"> Get an iterator over the blocks in this container.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t337" href="#t337">337</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t338" href="#t338">338</a></span><span class="t"><span class="str"> Can be used as blocks() for iteration or accessing the _blocks list directly.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t339" href="#t339">339</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t340" href="#t340">340</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t341" href="#t341">341</a></span><span class="t"><span class="str"> Iterator over blocks</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t342" href="#t342">342</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t343" href="#t343">343</a></span><span class="t"> <span class="key">return</span> <span class="nam">iter</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_blocks</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t344" href="#t344">344</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t345" href="#t345">345</a></span><span class="t"> <span class="key">def</span> <span class="nam">add_block</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">block</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t346" href="#t346">346</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t347" href="#t347">347</a></span><span class="t"><span class="str"> Add a block to this container.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t348" href="#t348">348</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t349" href="#t349">349</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t350" href="#t350">350</a></span><span class="t"><span class="str"> block: The block to add</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t351" href="#t351">351</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t352" href="#t352">352</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_blocks</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">block</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t353" href="#t353">353</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="str">'parent'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">353&#x202F;&#x219B;&#x202F;exit</span><span class="annotate long">line 353 didn't return from function 'add_block' because the condition on line 353 was always true</span></span></p>
<p class="run"><span class="n"><a id="t354" href="#t354">354</a></span><span class="t"> <span class="nam">block</span><span class="op">.</span><span class="nam">parent</span> <span class="op">=</span> <span class="nam">self</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t355" href="#t355">355</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t356" href="#t356">356</a></span><span class="t"> <span class="key">def</span> <span class="nam">create_paragraph</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">style</span><span class="op">=</span><span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t357" href="#t357">357</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t358" href="#t358">358</a></span><span class="t"><span class="str"> Create a new paragraph and add it to this container.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t359" href="#t359">359</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t360" href="#t360">360</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t361" href="#t361">361</a></span><span class="t"><span class="str"> style: Optional style override. If None, inherits from container</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t362" href="#t362">362</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t363" href="#t363">363</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t364" href="#t364">364</a></span><span class="t"><span class="str"> The newly created Paragraph object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t365" href="#t365">365</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t366" href="#t366">366</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">block</span> <span class="key">import</span> <span class="nam">Paragraph</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t367" href="#t367">367</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t368" href="#t368">368</a></span><span class="t"> <span class="key">if</span> <span class="nam">style</span> <span class="key">is</span> <span class="key">None</span> <span class="key">and</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="str">'_style'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t369" href="#t369">369</a></span><span class="t"> <span class="nam">style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t370" href="#t370">370</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t371" href="#t371">371</a></span><span class="t"> <span class="nam">paragraph</span> <span class="op">=</span> <span class="nam">Paragraph</span><span class="op">(</span><span class="nam">style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t372" href="#t372">372</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">add_block</span><span class="op">(</span><span class="nam">paragraph</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t373" href="#t373">373</a></span><span class="t"> <span class="key">return</span> <span class="nam">paragraph</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t374" href="#t374">374</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t375" href="#t375">375</a></span><span class="t"> <span class="key">def</span> <span class="nam">create_heading</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">level</span><span class="op">=</span><span class="key">None</span><span class="op">,</span> <span class="nam">style</span><span class="op">=</span><span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t376" href="#t376">376</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t377" href="#t377">377</a></span><span class="t"><span class="str"> Create a new heading and add it to this container.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t378" href="#t378">378</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t379" href="#t379">379</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t380" href="#t380">380</a></span><span class="t"><span class="str"> level: The heading level (h1-h6)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t381" href="#t381">381</a></span><span class="t"><span class="str"> style: Optional style override. If None, inherits from container</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t382" href="#t382">382</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t383" href="#t383">383</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t384" href="#t384">384</a></span><span class="t"><span class="str"> The newly created Heading object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t385" href="#t385">385</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t386" href="#t386">386</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">block</span> <span class="key">import</span> <span class="nam">Heading</span><span class="op">,</span> <span class="nam">HeadingLevel</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t387" href="#t387">387</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t388" href="#t388">388</a></span><span class="t"> <span class="key">if</span> <span class="nam">level</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t389" href="#t389">389</a></span><span class="t"> <span class="nam">level</span> <span class="op">=</span> <span class="nam">HeadingLevel</span><span class="op">.</span><span class="nam">H1</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t390" href="#t390">390</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t391" href="#t391">391</a></span><span class="t"> <span class="key">if</span> <span class="nam">style</span> <span class="key">is</span> <span class="key">None</span> <span class="key">and</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="str">'_style'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t392" href="#t392">392</a></span><span class="t"> <span class="nam">style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t393" href="#t393">393</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t394" href="#t394">394</a></span><span class="t"> <span class="nam">heading</span> <span class="op">=</span> <span class="nam">Heading</span><span class="op">(</span><span class="nam">level</span><span class="op">,</span> <span class="nam">style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t395" href="#t395">395</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">add_block</span><span class="op">(</span><span class="nam">heading</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t396" href="#t396">396</a></span><span class="t"> <span class="key">return</span> <span class="nam">heading</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t397" href="#t397">397</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t398" href="#t398">398</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t399" href="#t399">399</a></span><span class="t"><span class="key">class</span> <span class="nam">ContainerAware</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t400" href="#t400">400</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t401" href="#t401">401</a></span><span class="t"><span class="str"> Mixin providing support for the create_and_add_to factory pattern.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t402" href="#t402">402</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t403" href="#t403">403</a></span><span class="t"><span class="str"> This is a base that can be extended to provide the create_and_add_to</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t404" href="#t404">404</a></span><span class="t"><span class="str"> class method pattern used throughout the abstract module.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t405" href="#t405">405</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t406" href="#t406">406</a></span><span class="t"><span class="str"> Note: This is a framework for future refactoring. Currently, each class</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t407" href="#t407">407</a></span><span class="t"><span class="str"> has its own create_and_add_to implementation due to varying constructor</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t408" href="#t408">408</a></span><span class="t"><span class="str"> signatures. This mixin provides a foundation for standardizing that pattern.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t409" href="#t409">409</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t410" href="#t410">410</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t411" href="#t411">411</a></span><span class="t"> <span class="op">@</span><span class="nam">classmethod</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t412" href="#t412">412</a></span><span class="t"> <span class="key">def</span> <span class="nam">_validate_container</span><span class="op">(</span><span class="nam">cls</span><span class="op">,</span> <span class="nam">container</span><span class="op">,</span> <span class="nam">required_method</span><span class="op">=</span><span class="str">'add_block'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t413" href="#t413">413</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t414" href="#t414">414</a></span><span class="t"><span class="str"> Validate that a container has the required method.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t415" href="#t415">415</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t416" href="#t416">416</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t417" href="#t417">417</a></span><span class="t"><span class="str"> container: The container to validate</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t418" href="#t418">418</a></span><span class="t"><span class="str"> required_method: The method name to check for</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t419" href="#t419">419</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t420" href="#t420">420</a></span><span class="t"><span class="str"> Raises:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t421" href="#t421">421</a></span><span class="t"><span class="str"> AttributeError: If the container doesn't have the required method</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t422" href="#t422">422</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t423" href="#t423">423</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">container</span><span class="op">,</span> <span class="nam">required_method</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t424" href="#t424">424</a></span><span class="t"> <span class="key">raise</span> <span class="nam">AttributeError</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t425" href="#t425">425</a></span><span class="t"> <span class="fst">f"</span><span class="fst">Container </span><span class="op">{</span><span class="nam">type</span><span class="op">(</span><span class="nam">container</span><span class="op">)</span><span class="op">.</span><span class="nam">__name__</span><span class="op">}</span><span class="fst"> must have a '</span><span class="op">{</span><span class="nam">required_method</span><span class="op">}</span><span class="fst">' method</span><span class="fst">"</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t426" href="#t426">426</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t427" href="#t427">427</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t428" href="#t428">428</a></span><span class="t"> <span class="op">@</span><span class="nam">classmethod</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t429" href="#t429">429</a></span><span class="t"> <span class="key">def</span> <span class="nam">_inherit_style</span><span class="op">(</span><span class="nam">cls</span><span class="op">,</span> <span class="nam">container</span><span class="op">,</span> <span class="nam">style</span><span class="op">=</span><span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t430" href="#t430">430</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t431" href="#t431">431</a></span><span class="t"><span class="str"> Inherit style from container if not explicitly provided.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t432" href="#t432">432</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t433" href="#t433">433</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t434" href="#t434">434</a></span><span class="t"><span class="str"> container: The container to inherit from</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t435" href="#t435">435</a></span><span class="t"><span class="str"> style: Optional explicit style</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t436" href="#t436">436</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t437" href="#t437">437</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t438" href="#t438">438</a></span><span class="t"><span class="str"> The style to use (explicit or inherited)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t439" href="#t439">439</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t440" href="#t440">440</a></span><span class="t"> <span class="key">if</span> <span class="nam">style</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t441" href="#t441">441</a></span><span class="t"> <span class="key">return</span> <span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t442" href="#t442">442</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t443" href="#t443">443</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">container</span><span class="op">,</span> <span class="str">'style'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t444" href="#t444">444</a></span><span class="t"> <span class="key">return</span> <span class="nam">container</span><span class="op">.</span><span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t445" href="#t445">445</a></span><span class="t"> <span class="key">elif</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">container</span><span class="op">,</span> <span class="str">'default_style'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t446" href="#t446">446</a></span><span class="t"> <span class="key">return</span> <span class="nam">container</span><span class="op">.</span><span class="nam">default_style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t447" href="#t447">447</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t448" href="#t448">448</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_40407af872b0cf37___init___py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_40407af872b0cf37_callback_registry_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,377 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/core/callback_registry.py: 92%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/core/callback_registry.py</b>:
<span class="pc_cov">92%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">75 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">71<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">4<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">21<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">3<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_40407af872b0cf37_base_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_40407af872b0cf37_highlight_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">Callback Registry for managing interactable elements and their callbacks.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">This module provides a registry system for tracking interactive elements (links, buttons, forms)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">and managing their callbacks. Supports multiple binding strategies:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="str">- HTML id attributes for HTML-generated content</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="str">- Auto-generated ids for programmatic construction</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="str">- Type-based batch operations</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">Dict</span><span class="op">,</span> <span class="nam">List</span><span class="op">,</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">Callable</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">core</span><span class="op">.</span><span class="nam">base</span> <span class="key">import</span> <span class="nam">Interactable</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"><span class="key">class</span> <span class="nam">CallbackRegistry</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"><span class="str"> Registry for managing interactable callbacks with multiple binding strategies.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"><span class="str"> Supports:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"><span class="str"> - Direct references by object id</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"><span class="str"> - HTML id attributes (from parsed HTML)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"><span class="str"> - Type-based queries (all buttons, all links, etc.)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"><span class="str"> - Auto-generated ids for programmatic construction</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"><span class="str"> This enables flexible callback binding for both HTML-generated content</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"><span class="str"> and manually constructed UIs.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"> <span class="str">"""Initialize an empty callback registry."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_by_reference</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">Interactable</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span> <span class="com"># id(obj) -> obj</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_by_id</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Interactable</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span> <span class="com"># HTML id or auto id -> obj</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_by_type</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">List</span><span class="op">[</span><span class="nam">Interactable</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span> <span class="com"># type name -> [objs]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_auto_counter</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"> <span class="key">def</span> <span class="nam">register</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">obj</span><span class="op">:</span> <span class="nam">Interactable</span><span class="op">,</span> <span class="nam">html_id</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">str</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t"><span class="str"> Register an interactable object with optional HTML id.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"><span class="str"> The object is always registered by reference (using Python's id()).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t"><span class="str"> If an html_id is provided, it's also registered by that id.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t"><span class="str"> If no html_id is provided, an auto-generated id is created.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t"><span class="str"> obj: The interactable object to register</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"><span class="str"> html_id: Optional HTML id attribute value (e.g., from &lt;button id="save-btn">)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t"><span class="str"> The id used for registration (either html_id or auto-generated)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t"><span class="str"> Example:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t"><span class="str"> >>> button = ButtonText(...)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"><span class="str"> >>> registry.register(button, html_id="save-btn")</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t"><span class="str"> 'save-btn'</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"><span class="str"> >>> registry.register(other_button) # No html_id</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t"><span class="str"> 'auto_button_0'</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t"> <span class="com"># Always register by Python object id for direct lookups</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"> <span class="nam">obj_id</span> <span class="op">=</span> <span class="nam">id</span><span class="op">(</span><span class="nam">obj</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_by_reference</span><span class="op">[</span><span class="nam">obj_id</span><span class="op">]</span> <span class="op">=</span> <span class="nam">obj</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t"> <span class="com"># Determine type name and register by type</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t"> <span class="nam">type_name</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_get_type_name</span><span class="op">(</span><span class="nam">obj</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"> <span class="key">if</span> <span class="nam">type_name</span> <span class="key">not</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_by_type</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_by_type</span><span class="op">[</span><span class="nam">type_name</span><span class="op">]</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_by_type</span><span class="op">[</span><span class="nam">type_name</span><span class="op">]</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">obj</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"> <span class="com"># Register by HTML id or generate auto id</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"> <span class="key">if</span> <span class="nam">html_id</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t"> <span class="com"># Use provided HTML id</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_by_id</span><span class="op">[</span><span class="nam">html_id</span><span class="op">]</span> <span class="op">=</span> <span class="nam">obj</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t"> <span class="key">return</span> <span class="nam">html_id</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t"> <span class="com"># Generate automatic id</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"> <span class="nam">auto_id</span> <span class="op">=</span> <span class="fst">f"</span><span class="fst">auto_</span><span class="op">{</span><span class="nam">type_name</span><span class="op">}</span><span class="fst">_</span><span class="op">{</span><span class="nam">self</span><span class="op">.</span><span class="nam">_auto_counter</span><span class="op">}</span><span class="fst">"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_auto_counter</span> <span class="op">+=</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_by_id</span><span class="op">[</span><span class="nam">auto_id</span><span class="op">]</span> <span class="op">=</span> <span class="nam">obj</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"> <span class="key">return</span> <span class="nam">auto_id</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_by_id</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">identifier</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Interactable</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t"><span class="str"> Get an interactable by its id (HTML id or auto-generated id).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t"><span class="str"> identifier: The id to lookup (e.g., "save-btn" or "auto_button_0")</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t"><span class="str"> The interactable object, or None if not found</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t"><span class="str"> Example:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t"><span class="str"> >>> button = registry.get_by_id("save-btn")</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t"><span class="str"> >>> if button:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t"><span class="str"> ... button._callback = my_save_function</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_by_id</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="nam">identifier</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_by_type</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">type_name</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">Interactable</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"><span class="str"> Get all interactables of a specific type.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"><span class="str"> type_name: The type name (e.g., "link", "button", "form_field")</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t"><span class="str"> List of interactable objects of that type (may be empty)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t"><span class="str"> Example:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t"><span class="str"> >>> all_buttons = registry.get_by_type("button")</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t"><span class="str"> >>> for button in all_buttons:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"><span class="str"> ... print(button.text)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_by_type</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="nam">type_name</span><span class="op">,</span> <span class="op">[</span><span class="op">]</span><span class="op">)</span><span class="op">.</span><span class="nam">copy</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_all_ids</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"><span class="str"> Get all registered ids (both HTML ids and auto-generated ids).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"><span class="str"> List of all ids in the registry</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t"><span class="str"> Example:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t"><span class="str"> >>> ids = registry.get_all_ids()</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"><span class="str"> >>> print(ids)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t"><span class="str"> ['save-btn', 'cancel-btn', 'auto_link_0', 'auto_button_1']</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t"> <span class="key">return</span> <span class="nam">list</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_by_id</span><span class="op">.</span><span class="nam">keys</span><span class="op">(</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_all_types</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t"><span class="str"> Get all registered type names.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t"><span class="str"> List of type names that have registered objects</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t"><span class="str"> Example:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"><span class="str"> >>> types = registry.get_all_types()</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t"><span class="str"> >>> print(types)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"><span class="str"> ['link', 'button', 'form_field']</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t"> <span class="key">return</span> <span class="nam">list</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_by_type</span><span class="op">.</span><span class="nam">keys</span><span class="op">(</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_callback</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">identifier</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span> <span class="nam">callback</span><span class="op">:</span> <span class="nam">Callable</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"><span class="str"> Set the callback for an interactable by its id.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"><span class="str"> identifier: The id of the interactable</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"><span class="str"> callback: The callback function to set</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t"><span class="str"> True if the interactable was found and callback set, False otherwise</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t"><span class="str"> Example:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t"><span class="str"> >>> def on_save(point):</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t"><span class="str"> ... print("Save clicked!")</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t"><span class="str"> >>> registry.set_callback("save-btn", on_save)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t"><span class="str"> True</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t"> <span class="nam">obj</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_by_id</span><span class="op">(</span><span class="nam">identifier</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"> <span class="key">if</span> <span class="nam">obj</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t"> <span class="nam">obj</span><span class="op">.</span><span class="nam">_callback</span> <span class="op">=</span> <span class="nam">callback</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_callbacks_by_type</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">type_name</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span> <span class="nam">callback</span><span class="op">:</span> <span class="nam">Callable</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t"><span class="str"> Set the callback for all interactables of a specific type.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t"><span class="str"> Useful for batch operations like setting a default click sound</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"><span class="str"> for all buttons, or a default link handler for all links.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t"><span class="str"> type_name: The type name (e.g., "button", "link")</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t"><span class="str"> callback: The callback function to set</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t"><span class="str"> Number of objects that had their callback set</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t"><span class="str"> Example:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t"><span class="str"> >>> def play_click_sound(point):</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t"><span class="str"> ... audio.play("click.wav")</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t"><span class="str"> >>> count = registry.set_callbacks_by_type("button", play_click_sound)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t"><span class="str"> >>> print(f"Set callback for {count} buttons")</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t"> <span class="nam">objects</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_by_type</span><span class="op">(</span><span class="nam">type_name</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t"> <span class="key">for</span> <span class="nam">obj</span> <span class="key">in</span> <span class="nam">objects</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t"> <span class="nam">obj</span><span class="op">.</span><span class="nam">_callback</span> <span class="op">=</span> <span class="nam">callback</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t"> <span class="key">return</span> <span class="nam">len</span><span class="op">(</span><span class="nam">objects</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t"> <span class="key">def</span> <span class="nam">unregister</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">identifier</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t"><span class="str"> Unregister an interactable by its id.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t"><span class="str"> identifier: The id of the interactable to unregister</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t"><span class="str"> True if the interactable was found and unregistered, False otherwise</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t"> <span class="nam">obj</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_by_id</span><span class="op">.</span><span class="nam">pop</span><span class="op">(</span><span class="nam">identifier</span><span class="op">,</span> <span class="key">None</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t"> <span class="key">if</span> <span class="nam">obj</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">201&#x202F;&#x219B;&#x202F;214</span><span class="annotate long">line 201 didn't jump to line 214 because the condition on line 201 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t"> <span class="com"># Remove from reference map</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_by_reference</span><span class="op">.</span><span class="nam">pop</span><span class="op">(</span><span class="nam">id</span><span class="op">(</span><span class="nam">obj</span><span class="op">)</span><span class="op">,</span> <span class="key">None</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t"> <span class="com"># Remove from type map</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t"> <span class="nam">type_name</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_get_type_name</span><span class="op">(</span><span class="nam">obj</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t"> <span class="key">if</span> <span class="nam">type_name</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_by_type</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">207&#x202F;&#x219B;&#x202F;213</span><span class="annotate long">line 207 didn't jump to line 213 because the condition on line 207 was always true</span></span></p>
<p class="run"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_by_type</span><span class="op">[</span><span class="nam">type_name</span><span class="op">]</span><span class="op">.</span><span class="nam">remove</span><span class="op">(</span><span class="nam">obj</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t"> <span class="key">except</span> <span class="nam">ValueError</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t"> <span class="key">pass</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t"> <span class="key">def</span> <span class="nam">clear</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t"> <span class="str">"""Clear all registered interactables."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_by_reference</span><span class="op">.</span><span class="nam">clear</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_by_id</span><span class="op">.</span><span class="nam">clear</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_by_type</span><span class="op">.</span><span class="nam">clear</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_auto_counter</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t"> <span class="key">def</span> <span class="nam">count</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t"><span class="str"> Get the total number of registered interactables.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t"><span class="str"> Total count of registered objects</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t"> <span class="key">return</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_by_id</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t"> <span class="key">def</span> <span class="nam">count_by_type</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">type_name</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t"><span class="str"> Get the count of interactables of a specific type.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t"><span class="str"> type_name: The type name to count</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t"><span class="str"> Number of objects of that type</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t"> <span class="key">return</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_by_type</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="nam">type_name</span><span class="op">,</span> <span class="op">[</span><span class="op">]</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t"> <span class="key">def</span> <span class="nam">_get_type_name</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">obj</span><span class="op">:</span> <span class="nam">Interactable</span><span class="op">)</span> <span class="op">-></span> <span class="nam">str</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t"><span class="str"> Get a normalized type name for an interactable object.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t"><span class="str"> obj: The interactable object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t"><span class="str"> Type name string (e.g., "link", "button", "form_field")</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t"> <span class="com"># Import here to avoid circular imports</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span><span class="op">.</span><span class="nam">functional</span> <span class="key">import</span> <span class="nam">LinkText</span><span class="op">,</span> <span class="nam">ButtonText</span><span class="op">,</span> <span class="nam">FormFieldText</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">obj</span><span class="op">,</span> <span class="nam">LinkText</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t"> <span class="key">return</span> <span class="str">"link"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t"> <span class="key">elif</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">obj</span><span class="op">,</span> <span class="nam">ButtonText</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t"> <span class="key">return</span> <span class="str">"button"</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t"> <span class="key">elif</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">obj</span><span class="op">,</span> <span class="nam">FormFieldText</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">261&#x202F;&#x219B;&#x202F;265</span><span class="annotate long">line 261 didn't jump to line 265 because the condition on line 261 was always true</span></span></p>
<p class="run"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t"> <span class="key">return</span> <span class="str">"form_field"</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t"> <span class="com"># Fallback to class name</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t"> <span class="key">return</span> <span class="nam">obj</span><span class="op">.</span><span class="nam">__class__</span><span class="op">.</span><span class="nam">__name__</span><span class="op">.</span><span class="nam">lower</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t"> <span class="key">def</span> <span class="nam">__len__</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t"> <span class="str">"""Support len() to get count of registered interactables."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">count</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t"> <span class="key">def</span> <span class="nam">__contains__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">identifier</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t"> <span class="str">"""Support 'in' operator to check if an id is registered."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t"> <span class="key">return</span> <span class="nam">identifier</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_by_id</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t"> <span class="key">def</span> <span class="nam">__repr__</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">str</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t"> <span class="str">"""String representation showing registry statistics."""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t"> <span class="nam">type_counts</span> <span class="op">=</span> <span class="op">{</span><span class="nam">t</span><span class="op">:</span> <span class="nam">len</span><span class="op">(</span><span class="nam">objs</span><span class="op">)</span> <span class="key">for</span> <span class="nam">t</span><span class="op">,</span> <span class="nam">objs</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_by_type</span><span class="op">.</span><span class="nam">items</span><span class="op">(</span><span class="op">)</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t"> <span class="key">return</span> <span class="fst">f"</span><span class="fst">CallbackRegistry(total=</span><span class="op">{</span><span class="nam">self</span><span class="op">.</span><span class="nam">count</span><span class="op">(</span><span class="op">)</span><span class="op">}</span><span class="fst">, types=</span><span class="op">{</span><span class="nam">type_counts</span><span class="op">}</span><span class="fst">)</span><span class="fst">"</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_40407af872b0cf37_base_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_40407af872b0cf37_highlight_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,348 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/core/highlight.py: 95%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/core/highlight.py</b>:
<span class="pc_cov">95%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">95 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">90<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">5<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">18<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">0<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_40407af872b0cf37_callback_registry_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_40407af872b0cf37_query_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">Text highlighting system for ebook reader.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">Provides data structures and utilities for highlighting text regions,</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">managing highlight collections, and rendering highlights on pages.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="key">from</span> <span class="nam">__future__</span> <span class="key">import</span> <span class="nam">annotations</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="key">from</span> <span class="nam">dataclasses</span> <span class="key">import</span> <span class="nam">dataclass</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">List</span><span class="op">,</span> <span class="nam">Tuple</span><span class="op">,</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">Dict</span><span class="op">,</span> <span class="nam">Any</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="key">from</span> <span class="nam">enum</span> <span class="key">import</span> <span class="nam">Enum</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="key">import</span> <span class="nam">json</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"><span class="key">from</span> <span class="nam">pathlib</span> <span class="key">import</span> <span class="nam">Path</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"><span class="key">class</span> <span class="nam">HighlightColor</span><span class="op">(</span><span class="nam">Enum</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"> <span class="str">"""Predefined highlight colors with RGBA values"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"> <span class="nam">YELLOW</span> <span class="op">=</span> <span class="op">(</span><span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">100</span><span class="op">)</span> <span class="com"># Classic highlight yellow</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"> <span class="nam">GREEN</span> <span class="op">=</span> <span class="op">(</span><span class="num">100</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">100</span><span class="op">,</span> <span class="num">100</span><span class="op">)</span> <span class="com"># Green for verified/correct</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"> <span class="nam">BLUE</span> <span class="op">=</span> <span class="op">(</span><span class="num">100</span><span class="op">,</span> <span class="num">200</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">100</span><span class="op">)</span> <span class="com"># Blue for important</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"> <span class="nam">PINK</span> <span class="op">=</span> <span class="op">(</span><span class="num">255</span><span class="op">,</span> <span class="num">150</span><span class="op">,</span> <span class="num">200</span><span class="op">,</span> <span class="num">100</span><span class="op">)</span> <span class="com"># Pink for questions</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"> <span class="nam">ORANGE</span> <span class="op">=</span> <span class="op">(</span><span class="num">255</span><span class="op">,</span> <span class="num">180</span><span class="op">,</span> <span class="num">100</span><span class="op">,</span> <span class="num">100</span><span class="op">)</span> <span class="com"># Orange for warnings</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"> <span class="nam">PURPLE</span> <span class="op">=</span> <span class="op">(</span><span class="num">200</span><span class="op">,</span> <span class="num">150</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">100</span><span class="op">)</span> <span class="com"># Purple for definitions</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"> <span class="nam">RED</span> <span class="op">=</span> <span class="op">(</span><span class="num">255</span><span class="op">,</span> <span class="num">100</span><span class="op">,</span> <span class="num">100</span><span class="op">,</span> <span class="num">100</span><span class="op">)</span> <span class="com"># Red for errors/concerns</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"><span class="op">@</span><span class="nam">dataclass</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t"><span class="key">class</span> <span class="nam">Highlight</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"><span class="str"> Represents a highlighted text region.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"><span class="str"> Highlights are stored with both pixel bounds (for rendering) and</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"><span class="str"> semantic bounds (text content, for persistence across font changes).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"> <span class="com"># Identification</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"> <span class="nam">id</span><span class="op">:</span> <span class="nam">str</span> <span class="com"># Unique identifier</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t"> <span class="com"># Visual properties</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"> <span class="nam">bounds</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">]</span> <span class="com"># List of (x, y, w, h) rectangles</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"> <span class="nam">color</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span> <span class="com"># RGBA color</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t"> <span class="com"># Semantic properties (for persistence)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t"> <span class="nam">text</span><span class="op">:</span> <span class="nam">str</span> <span class="com"># The highlighted text</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"> <span class="nam">start_word_index</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span> <span class="com"># Word index in document (if available)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t"> <span class="nam">end_word_index</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"> <span class="com"># Metadata</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"> <span class="nam">note</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span> <span class="com"># Optional annotation</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t"> <span class="nam">tags</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span> <span class="com"># Optional categorization tags</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"> <span class="nam">timestamp</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">float</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span> <span class="com"># When created</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t"> <span class="key">def</span> <span class="nam">__post_init__</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"> <span class="str">"""Initialize default values"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">tags</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">tags</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t"> <span class="key">def</span> <span class="nam">to_dict</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t"> <span class="str">"""Serialize to dictionary"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"> <span class="key">return</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"> <span class="str">'id'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">id</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"> <span class="str">'bounds'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">bounds</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t"> <span class="str">'color'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">color</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t"> <span class="str">'text'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">text</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"> <span class="str">'start_word_index'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">start_word_index</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"> <span class="str">'end_word_index'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">end_word_index</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t"> <span class="str">'note'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">note</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t"> <span class="str">'tags'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">tags</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"> <span class="str">'timestamp'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">timestamp</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t"> <span class="op">@</span><span class="nam">classmethod</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t"> <span class="key">def</span> <span class="nam">from_dict</span><span class="op">(</span><span class="nam">cls</span><span class="op">,</span> <span class="nam">data</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="str">'Highlight'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"> <span class="str">"""Deserialize from dictionary"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t"> <span class="key">return</span> <span class="nam">cls</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"> <span class="nam">id</span><span class="op">=</span><span class="nam">data</span><span class="op">[</span><span class="str">'id'</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t"> <span class="nam">bounds</span><span class="op">=</span><span class="op">[</span><span class="nam">tuple</span><span class="op">(</span><span class="nam">b</span><span class="op">)</span> <span class="key">for</span> <span class="nam">b</span> <span class="key">in</span> <span class="nam">data</span><span class="op">[</span><span class="str">'bounds'</span><span class="op">]</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t"> <span class="nam">color</span><span class="op">=</span><span class="nam">tuple</span><span class="op">(</span><span class="nam">data</span><span class="op">[</span><span class="str">'color'</span><span class="op">]</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"> <span class="nam">text</span><span class="op">=</span><span class="nam">data</span><span class="op">[</span><span class="str">'text'</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t"> <span class="nam">start_word_index</span><span class="op">=</span><span class="nam">data</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="str">'start_word_index'</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t"> <span class="nam">end_word_index</span><span class="op">=</span><span class="nam">data</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="str">'end_word_index'</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t"> <span class="nam">note</span><span class="op">=</span><span class="nam">data</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="str">'note'</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t"> <span class="nam">tags</span><span class="op">=</span><span class="nam">data</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="str">'tags'</span><span class="op">,</span> <span class="op">[</span><span class="op">]</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t"> <span class="nam">timestamp</span><span class="op">=</span><span class="nam">data</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="str">'timestamp'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t"><span class="key">class</span> <span class="nam">HighlightManager</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"><span class="str"> Manages highlights for a document.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t"><span class="str"> Handles adding, removing, listing, and persisting highlights.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">document_id</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span> <span class="nam">highlights_dir</span><span class="op">:</span> <span class="nam">str</span> <span class="op">=</span> <span class="str">"highlights"</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t"><span class="str"> Initialize highlight manager.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"><span class="str"> document_id: Unique identifier for the document</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t"><span class="str"> highlights_dir: Directory to store highlight data</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">document_id</span> <span class="op">=</span> <span class="nam">document_id</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">highlights_dir</span> <span class="op">=</span> <span class="nam">Path</span><span class="op">(</span><span class="nam">highlights_dir</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">highlights</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Highlight</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span> <span class="com"># id -> Highlight</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t"> <span class="com"># Create directory if it doesn't exist</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">highlights_dir</span><span class="op">.</span><span class="nam">mkdir</span><span class="op">(</span><span class="nam">parents</span><span class="op">=</span><span class="key">True</span><span class="op">,</span> <span class="nam">exist_ok</span><span class="op">=</span><span class="key">True</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t"> <span class="com"># Load existing highlights</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_load_highlights</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"> <span class="key">def</span> <span class="nam">add_highlight</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">highlight</span><span class="op">:</span> <span class="nam">Highlight</span><span class="op">)</span> <span class="op">-></span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t"><span class="str"> Add a highlight.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t"><span class="str"> highlight: Highlight to add</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">highlights</span><span class="op">[</span><span class="nam">highlight</span><span class="op">.</span><span class="nam">id</span><span class="op">]</span> <span class="op">=</span> <span class="nam">highlight</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_save_highlights</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t"> <span class="key">def</span> <span class="nam">remove_highlight</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">highlight_id</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t"><span class="str"> Remove a highlight by ID.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t"><span class="str"> highlight_id: ID of highlight to remove</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t"><span class="str"> True if removed, False if not found</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t"> <span class="key">if</span> <span class="nam">highlight_id</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">highlights</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t"> <span class="key">del</span> <span class="nam">self</span><span class="op">.</span><span class="nam">highlights</span><span class="op">[</span><span class="nam">highlight_id</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_save_highlights</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_highlight</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">highlight_id</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Highlight</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t"> <span class="str">"""Get a highlight by ID"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">highlights</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="nam">highlight_id</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t"> <span class="key">def</span> <span class="nam">list_highlights</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">Highlight</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t"> <span class="str">"""Get all highlights"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"> <span class="key">return</span> <span class="nam">list</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">highlights</span><span class="op">.</span><span class="nam">values</span><span class="op">(</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t"> <span class="key">def</span> <span class="nam">clear_all</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"> <span class="str">"""Remove all highlights"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">highlights</span><span class="op">.</span><span class="nam">clear</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_save_highlights</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_highlights_for_page</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span> <span class="nam">page_bounds</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">Highlight</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t"><span class="str"> Get highlights that appear on a specific page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t"><span class="str"> page_bounds: Page bounds (x, y, width, height)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"><span class="str"> List of highlights on this page</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t"> <span class="nam">page_x</span><span class="op">,</span> <span class="nam">page_y</span><span class="op">,</span> <span class="nam">page_w</span><span class="op">,</span> <span class="nam">page_h</span> <span class="op">=</span> <span class="nam">page_bounds</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"> <span class="nam">page_highlights</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t"> <span class="key">for</span> <span class="nam">highlight</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">highlights</span><span class="op">.</span><span class="nam">values</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"> <span class="com"># Check if any highlight bounds overlap with page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t"> <span class="key">for</span> <span class="nam">hx</span><span class="op">,</span> <span class="nam">hy</span><span class="op">,</span> <span class="nam">hw</span><span class="op">,</span> <span class="nam">hh</span> <span class="key">in</span> <span class="nam">highlight</span><span class="op">.</span><span class="nam">bounds</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t"> <span class="key">if</span> <span class="op">(</span><span class="nam">hx</span> <span class="op">&lt;</span> <span class="nam">page_x</span> <span class="op">+</span> <span class="nam">page_w</span> <span class="key">and</span> <span class="nam">hx</span> <span class="op">+</span> <span class="nam">hw</span> <span class="op">></span> <span class="nam">page_x</span> <span class="key">and</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t"> <span class="nam">hy</span> <span class="op">&lt;</span> <span class="nam">page_y</span> <span class="op">+</span> <span class="nam">page_h</span> <span class="key">and</span> <span class="nam">hy</span> <span class="op">+</span> <span class="nam">hh</span> <span class="op">></span> <span class="nam">page_y</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"> <span class="nam">page_highlights</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">highlight</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t"> <span class="key">break</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t"> <span class="key">return</span> <span class="nam">page_highlights</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t"> <span class="key">def</span> <span class="nam">_get_filepath</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Path</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t"> <span class="str">"""Get filepath for this document's highlights"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">highlights_dir</span> <span class="op">/</span> <span class="fst">f"</span><span class="op">{</span><span class="nam">self</span><span class="op">.</span><span class="nam">document_id</span><span class="op">}</span><span class="fst">_highlights.json</span><span class="fst">"</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t"> <span class="key">def</span> <span class="nam">_save_highlights</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t"> <span class="str">"""Persist highlights to disk"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t"> <span class="nam">filepath</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_get_filepath</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t"> <span class="nam">data</span> <span class="op">=</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t"> <span class="str">'document_id'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">document_id</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t"> <span class="str">'highlights'</span><span class="op">:</span> <span class="op">[</span><span class="nam">h</span><span class="op">.</span><span class="nam">to_dict</span><span class="op">(</span><span class="op">)</span> <span class="key">for</span> <span class="nam">h</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">highlights</span><span class="op">.</span><span class="nam">values</span><span class="op">(</span><span class="op">)</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t"> <span class="key">with</span> <span class="nam">open</span><span class="op">(</span><span class="nam">filepath</span><span class="op">,</span> <span class="str">'w'</span><span class="op">)</span> <span class="key">as</span> <span class="nam">f</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t"> <span class="nam">json</span><span class="op">.</span><span class="nam">dump</span><span class="op">(</span><span class="nam">data</span><span class="op">,</span> <span class="nam">f</span><span class="op">,</span> <span class="nam">indent</span><span class="op">=</span><span class="num">2</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t"> <span class="key">except</span> <span class="nam">Exception</span> <span class="key">as</span> <span class="nam">e</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t"> <span class="nam">print</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Error saving highlights: </span><span class="op">{</span><span class="nam">e</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t"> <span class="key">def</span> <span class="nam">_load_highlights</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t"> <span class="str">"""Load highlights from disk"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t"> <span class="nam">filepath</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_get_filepath</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">filepath</span><span class="op">.</span><span class="nam">exists</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t"> <span class="key">return</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t"> <span class="key">with</span> <span class="nam">open</span><span class="op">(</span><span class="nam">filepath</span><span class="op">,</span> <span class="str">'r'</span><span class="op">)</span> <span class="key">as</span> <span class="nam">f</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t"> <span class="nam">data</span> <span class="op">=</span> <span class="nam">json</span><span class="op">.</span><span class="nam">load</span><span class="op">(</span><span class="nam">f</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">highlights</span> <span class="op">=</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t"> <span class="nam">h</span><span class="op">[</span><span class="str">'id'</span><span class="op">]</span><span class="op">:</span> <span class="nam">Highlight</span><span class="op">.</span><span class="nam">from_dict</span><span class="op">(</span><span class="nam">h</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t"> <span class="key">for</span> <span class="nam">h</span> <span class="key">in</span> <span class="nam">data</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="str">'highlights'</span><span class="op">,</span> <span class="op">[</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t"> <span class="key">except</span> <span class="nam">Exception</span> <span class="key">as</span> <span class="nam">e</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"> <span class="nam">print</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Error loading highlights: </span><span class="op">{</span><span class="nam">e</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">highlights</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t"><span class="key">def</span> <span class="nam">create_highlight_from_query_result</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"> <span class="nam">result</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t"> <span class="nam">color</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="nam">HighlightColor</span><span class="op">.</span><span class="nam">YELLOW</span><span class="op">.</span><span class="nam">value</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t"> <span class="nam">note</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t"> <span class="nam">tags</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">List</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t"><span class="op">)</span> <span class="op">-></span> <span class="nam">Highlight</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t"><span class="str"> Create a highlight from a QueryResult.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"><span class="str"> result: QueryResult from query_pixel or query_range</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t"><span class="str"> color: RGBA color tuple</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t"><span class="str"> note: Optional annotation</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t"><span class="str"> tags: Optional categorization tags</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t"><span class="str"> Highlight instance</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t"> <span class="key">from</span> <span class="nam">time</span> <span class="key">import</span> <span class="nam">time</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t"> <span class="key">import</span> <span class="nam">uuid</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t"> <span class="com"># Handle single result or SelectionRange</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">result</span><span class="op">,</span> <span class="str">'results'</span><span class="op">)</span><span class="op">:</span> <span class="com"># SelectionRange</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t"> <span class="nam">bounds</span> <span class="op">=</span> <span class="nam">result</span><span class="op">.</span><span class="nam">bounds_list</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t"> <span class="nam">text</span> <span class="op">=</span> <span class="nam">result</span><span class="op">.</span><span class="nam">text</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t"> <span class="key">else</span><span class="op">:</span> <span class="com"># Single QueryResult</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t"> <span class="nam">bounds</span> <span class="op">=</span> <span class="op">[</span><span class="nam">result</span><span class="op">.</span><span class="nam">bounds</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t"> <span class="nam">text</span> <span class="op">=</span> <span class="nam">result</span><span class="op">.</span><span class="nam">text</span> <span class="key">or</span> <span class="str">""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t"> <span class="key">return</span> <span class="nam">Highlight</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t"> <span class="nam">id</span><span class="op">=</span><span class="nam">str</span><span class="op">(</span><span class="nam">uuid</span><span class="op">.</span><span class="nam">uuid4</span><span class="op">(</span><span class="op">)</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t"> <span class="nam">bounds</span><span class="op">=</span><span class="nam">bounds</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t"> <span class="nam">color</span><span class="op">=</span><span class="nam">color</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t"> <span class="nam">text</span><span class="op">=</span><span class="nam">text</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t"> <span class="nam">note</span><span class="op">=</span><span class="nam">note</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t"> <span class="nam">tags</span><span class="op">=</span><span class="nam">tags</span> <span class="key">or</span> <span class="op">[</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t"> <span class="nam">timestamp</span><span class="op">=</span><span class="nam">time</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_40407af872b0cf37_callback_registry_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_40407af872b0cf37_query_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,185 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/core/query.py: 94%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/core/query.py</b>:
<span class="pc_cov">94%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">33 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">32<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">1<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">7<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">1<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_40407af872b0cf37_highlight_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_fc521de9aff00981___init___py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">Query system for pixel-to-content mapping.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">This module provides data structures for querying rendered content,</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">enabling interactive features like link clicking, word definition lookup,</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="str">and text selection.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="key">from</span> <span class="nam">__future__</span> <span class="key">import</span> <span class="nam">annotations</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="key">from</span> <span class="nam">dataclasses</span> <span class="key">import</span> <span class="nam">dataclass</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">Tuple</span><span class="op">,</span> <span class="nam">List</span><span class="op">,</span> <span class="nam">Any</span><span class="op">,</span> <span class="nam">TYPE_CHECKING</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"><span class="key">if</span> <span class="nam">TYPE_CHECKING</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">13&#x202F;&#x219B;&#x202F;14</span><span class="annotate long">line 13 didn't jump to line 14 because the condition on line 13 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">core</span><span class="op">.</span><span class="nam">base</span> <span class="key">import</span> <span class="nam">Queriable</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"><span class="op">@</span><span class="nam">dataclass</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"><span class="key">class</span> <span class="nam">QueryResult</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"><span class="str"> Result of querying a point on a rendered page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"><span class="str"> This encapsulates all information about what was found at a pixel location,</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"><span class="str"> including geometry, content, and interaction capabilities.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"> <span class="com"># What was found</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"> <span class="nam">object</span><span class="op">:</span> <span class="str">'Queriable'</span> <span class="com"># The object at this point</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"> <span class="nam">object_type</span><span class="op">:</span> <span class="nam">str</span> <span class="com"># "link", "text", "image", "button", "word", "empty"</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"> <span class="com"># Geometry</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"> <span class="nam">bounds</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span> <span class="com"># (x, y, width, height) in page coordinates</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"> <span class="com"># Content (for text/words)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"> <span class="nam">text</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"> <span class="nam">word_index</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span> <span class="com"># Index in abstract document structure</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"> <span class="nam">block_index</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span> <span class="com"># Block index in document</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"> <span class="com"># Interaction (for links/buttons)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t"> <span class="nam">is_interactive</span><span class="op">:</span> <span class="nam">bool</span> <span class="op">=</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"> <span class="nam">link_target</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span> <span class="com"># URL or internal reference</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"> <span class="nam">callback</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Any</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span> <span class="com"># Interaction callback</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t"> <span class="com"># Hierarchy (for debugging/traversal)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t"> <span class="nam">parent_line</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Any</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"> <span class="nam">parent_page</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Any</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"> <span class="key">def</span> <span class="nam">to_dict</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">dict</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"> <span class="str">"""Convert to dictionary for serialization"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"> <span class="key">return</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t"> <span class="str">'object_type'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">object_type</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"> <span class="str">'bounds'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">bounds</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t"> <span class="str">'text'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">text</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t"> <span class="str">'is_interactive'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">is_interactive</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"> <span class="str">'link_target'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">link_target</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t"> <span class="str">'word_index'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">word_index</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"> <span class="str">'block_index'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">block_index</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"><span class="op">@</span><span class="nam">dataclass</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"><span class="key">class</span> <span class="nam">SelectionRange</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t"><span class="str"> Represents a range of selected text between two points.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"> <span class="nam">start_point</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"> <span class="nam">end_point</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t"> <span class="nam">results</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">QueryResult</span><span class="op">]</span> <span class="com"># All query results in the range</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"> <span class="key">def</span> <span class="nam">text</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">str</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t"> <span class="str">"""Get concatenated text from all results"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t"> <span class="key">return</span> <span class="str">" "</span><span class="op">.</span><span class="nam">join</span><span class="op">(</span><span class="nam">r</span><span class="op">.</span><span class="nam">text</span> <span class="key">for</span> <span class="nam">r</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">results</span> <span class="key">if</span> <span class="nam">r</span><span class="op">.</span><span class="nam">text</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t"> <span class="key">def</span> <span class="nam">bounds_list</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"> <span class="str">"""Get list of all bounding boxes for highlighting"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t"> <span class="key">return</span> <span class="op">[</span><span class="nam">r</span><span class="op">.</span><span class="nam">bounds</span> <span class="key">for</span> <span class="nam">r</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">results</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"> <span class="key">def</span> <span class="nam">to_dict</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">dict</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t"> <span class="str">"""Convert to dictionary for serialization"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t"> <span class="key">return</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t"> <span class="str">'start'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">start_point</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t"> <span class="str">'end'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">end_point</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t"> <span class="str">'text'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">text</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"> <span class="str">'word_count'</span><span class="op">:</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">results</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t"> <span class="str">'bounds'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">bounds_list</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_40407af872b0cf37_highlight_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_fc521de9aff00981___init___py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,110 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/layout/__init__.py: 100%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/layout/__init__.py</b>:
<span class="pc_cov">100%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">0 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">0<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">0<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">1<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">0<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_263f2e628cef8c50_html_extraction_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_427cc3035faf7633_document_layouter_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">Typesetting module for the pyWebLayout library.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">This package handles the organization and arrangement of elements for rendering, including:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">- Flow layout algorithms</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="str">- Container management</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="str">- Element positioning and sizing</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="str">- Content wrapping and overflow</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="str">- Coordinate systems and transformations</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="str">- Pagination for book-like content</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_263f2e628cef8c50_html_extraction_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_427cc3035faf7633_document_layouter_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,822 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/layout/document_layouter.py: 77%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/layout/document_layouter.py</b>:
<span class="pc_cov">77%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">216 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">174<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">42<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">16<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">15<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_427cc3035faf7633___init___py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_427cc3035faf7633_ereader_layout_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="run"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="key">from</span> <span class="nam">__future__</span> <span class="key">import</span> <span class="nam">annotations</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">List</span><span class="op">,</span> <span class="nam">Tuple</span><span class="op">,</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">Union</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="key">import</span> <span class="nam">numpy</span> <span class="key">as</span> <span class="nam">np</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span> <span class="key">import</span> <span class="nam">Page</span><span class="op">,</span> <span class="nam">Line</span><span class="op">,</span> <span class="nam">Text</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span><span class="op">.</span><span class="nam">image</span> <span class="key">import</span> <span class="nam">RenderableImage</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span><span class="op">.</span><span class="nam">functional</span> <span class="key">import</span> <span class="nam">ButtonText</span><span class="op">,</span> <span class="nam">FormFieldText</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span><span class="op">.</span><span class="nam">table</span> <span class="key">import</span> <span class="nam">TableRenderer</span><span class="op">,</span> <span class="nam">TableStyle</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span> <span class="key">import</span> <span class="nam">Paragraph</span><span class="op">,</span> <span class="nam">Word</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">block</span> <span class="key">import</span> <span class="nam">Image</span> <span class="key">as</span> <span class="nam">AbstractImage</span><span class="op">,</span> <span class="nam">PageBreak</span><span class="op">,</span> <span class="nam">Table</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">functional</span> <span class="key">import</span> <span class="nam">Button</span><span class="op">,</span> <span class="nam">Form</span><span class="op">,</span> <span class="nam">FormField</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">concrete_style</span> <span class="key">import</span> <span class="nam">ConcreteStyleRegistry</span><span class="op">,</span> <span class="nam">RenderingContext</span><span class="op">,</span> <span class="nam">StyleResolver</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span> <span class="key">import</span> <span class="nam">Font</span><span class="op">,</span> <span class="nam">Alignment</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"><span class="key">def</span> <span class="nam">paragraph_layouter</span><span class="op">(</span><span class="nam">paragraph</span><span class="op">:</span> <span class="nam">Paragraph</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"> <span class="nam">page</span><span class="op">:</span> <span class="nam">Page</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"> <span class="nam">start_word</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">0</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"> <span class="nam">pretext</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Text</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"> <span class="nam">alignment_override</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="str">'Alignment'</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">bool</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Text</span><span class="op">]</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"><span class="str"> Layout a paragraph of text within a given page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"><span class="str"> This function extracts word spacing constraints from the style system</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t"><span class="str"> and uses them to create properly spaced lines of text.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"><span class="str"> paragraph: The paragraph to layout</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"><span class="str"> page: The page to layout the paragraph on</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"><span class="str"> start_word: Index of the first word to process (for continuation)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"><span class="str"> pretext: Optional pretext from a previous hyphenated word</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"><span class="str"> alignment_override: Optional alignment to override the paragraph's default alignment</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t"><span class="str"> Tuple of:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"><span class="str"> - bool: True if paragraph was completely laid out, False if page ran out of space</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"><span class="str"> - Optional[int]: Index of first word that didn't fit (if any)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t"><span class="str"> - Optional[Text]: Remaining pretext if word was hyphenated (if any)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">paragraph</span><span class="op">.</span><span class="nam">words</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span><span class="op">,</span> <span class="key">None</span><span class="op">,</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"> <span class="com"># Validate inputs</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"> <span class="key">if</span> <span class="nam">start_word</span> <span class="op">>=</span> <span class="nam">len</span><span class="op">(</span><span class="nam">paragraph</span><span class="op">.</span><span class="nam">words</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span><span class="op">,</span> <span class="key">None</span><span class="op">,</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"> <span class="com"># paragraph.style is already a Font object (concrete), not AbstractStyle</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t"> <span class="com"># We need to get word spacing constraints from the Font's abstract style if available</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t"> <span class="com"># For now, use reasonable defaults based on font size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">paragraph</span><span class="op">.</span><span class="nam">style</span><span class="op">,</span> <span class="nam">Font</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"> <span class="com"># paragraph.style is already a Font (concrete style)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t"> <span class="nam">font</span> <span class="op">=</span> <span class="nam">paragraph</span><span class="op">.</span><span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t"> <span class="com"># Use default word spacing constraints based on font size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t"> <span class="com"># Minimum spacing should be proportional to font size for better readability</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"> <span class="nam">min_spacing</span> <span class="op">=</span> <span class="nam">float</span><span class="op">(</span><span class="nam">font</span><span class="op">.</span><span class="nam">font_size</span><span class="op">)</span> <span class="op">*</span> <span class="num">0.25</span> <span class="com"># 25% of font size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"> <span class="nam">max_spacing</span> <span class="op">=</span> <span class="nam">float</span><span class="op">(</span><span class="nam">font</span><span class="op">.</span><span class="nam">font_size</span><span class="op">)</span> <span class="op">*</span> <span class="num">0.5</span> <span class="com"># 50% of font size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"> <span class="nam">word_spacing_constraints</span> <span class="op">=</span> <span class="op">(</span><span class="nam">int</span><span class="op">(</span><span class="nam">min_spacing</span><span class="op">)</span><span class="op">,</span> <span class="nam">int</span><span class="op">(</span><span class="nam">max_spacing</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t"> <span class="nam">text_align</span> <span class="op">=</span> <span class="nam">Alignment</span><span class="op">.</span><span class="nam">LEFT</span> <span class="com"># Default alignment</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"> <span class="com"># paragraph.style is an AbstractStyle, resolve it</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"> <span class="com"># Ensure font_size is an int (it could be a FontSize enum)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">abstract_style</span> <span class="key">import</span> <span class="nam">FontSize</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">paragraph</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">font_size</span><span class="op">,</span> <span class="nam">FontSize</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">67&#x202F;&#x219B;&#x202F;71</span><span class="annotate long">line 67 didn't jump to line 71 because the condition on line 67 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"> <span class="com"># Use a default base font size, the resolver will handle the semantic size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"> <span class="nam">base_font_size</span> <span class="op">=</span> <span class="num">16</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t"> <span class="nam">base_font_size</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">paragraph</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">font_size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"> <span class="nam">rendering_context</span> <span class="op">=</span> <span class="nam">RenderingContext</span><span class="op">(</span><span class="nam">base_font_size</span><span class="op">=</span><span class="nam">base_font_size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t"> <span class="nam">style_resolver</span> <span class="op">=</span> <span class="nam">StyleResolver</span><span class="op">(</span><span class="nam">rendering_context</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"> <span class="nam">style_registry</span> <span class="op">=</span> <span class="nam">ConcreteStyleRegistry</span><span class="op">(</span><span class="nam">style_resolver</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t"> <span class="nam">concrete_style</span> <span class="op">=</span> <span class="nam">style_registry</span><span class="op">.</span><span class="nam">get_concrete_style</span><span class="op">(</span><span class="nam">paragraph</span><span class="op">.</span><span class="nam">style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t"> <span class="nam">font</span> <span class="op">=</span> <span class="nam">concrete_style</span><span class="op">.</span><span class="nam">create_font</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"> <span class="nam">word_spacing_constraints</span> <span class="op">=</span> <span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t"> <span class="nam">int</span><span class="op">(</span><span class="nam">concrete_style</span><span class="op">.</span><span class="nam">word_spacing_min</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t"> <span class="nam">int</span><span class="op">(</span><span class="nam">concrete_style</span><span class="op">.</span><span class="nam">word_spacing_max</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t"> <span class="nam">text_align</span> <span class="op">=</span> <span class="nam">concrete_style</span><span class="op">.</span><span class="nam">text_align</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"> <span class="com"># Apply page-level word spacing override if specified</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span>&nbsp;</span><span class="r"><span class="annotate short">85&#x202F;&#x219B;&#x202F;91</span><span class="annotate long">line 85 didn't jump to line 91 because the condition on line 85 was never true</span></span></p>
<p class="par par2 ru2 show_par"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t"> <span class="nam">page</span><span class="op">.</span><span class="nam">style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="par par2 ru2 show_par"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t"> <span class="str">'word_spacing'</span><span class="op">)</span> <span class="key">and</span> <span class="nam">isinstance</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="par par2 ru2 show_par"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t"> <span class="nam">page</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">word_spacing</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="par par2 ru2 show_par"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"> <span class="nam">int</span><span class="op">)</span> <span class="key">and</span> <span class="nam">page</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">word_spacing</span> <span class="op">></span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t"> <span class="com"># Add the page-level word spacing to both min and max constraints</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t"> <span class="nam">min_ws</span><span class="op">,</span> <span class="nam">max_ws</span> <span class="op">=</span> <span class="nam">word_spacing_constraints</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t"> <span class="nam">word_spacing_constraints</span> <span class="op">=</span> <span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t"> <span class="nam">min_ws</span> <span class="op">+</span> <span class="nam">page</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">word_spacing</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t"> <span class="nam">max_ws</span> <span class="op">+</span> <span class="nam">page</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">word_spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t"> <span class="com"># Apply alignment override if provided</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t"> <span class="key">if</span> <span class="nam">alignment_override</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">98&#x202F;&#x219B;&#x202F;99</span><span class="annotate long">line 98 didn't jump to line 99 because the condition on line 98 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"> <span class="nam">text_align</span> <span class="op">=</span> <span class="nam">alignment_override</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"> <span class="com"># Cap font size to page maximum if needed</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"> <span class="key">if</span> <span class="nam">font</span><span class="op">.</span><span class="nam">font_size</span> <span class="op">></span> <span class="nam">page</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">max_font_size</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">102&#x202F;&#x219B;&#x202F;104</span><span class="annotate long">line 102 didn't jump to line 104 because the condition on line 102 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t"> <span class="com"># Use paragraph's font registry to create the capped font</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">paragraph</span><span class="op">,</span> <span class="str">'get_or_create_font'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t"> <span class="nam">font</span> <span class="op">=</span> <span class="nam">paragraph</span><span class="op">.</span><span class="nam">get_or_create_font</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t"> <span class="nam">font_path</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">_font_path</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t"> <span class="nam">font_size</span><span class="op">=</span><span class="nam">page</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">max_font_size</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t"> <span class="nam">colour</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">colour</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t"> <span class="nam">weight</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">weight</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"> <span class="nam">style</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t"> <span class="nam">decoration</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">decoration</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"> <span class="nam">background</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">background</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t"> <span class="com"># Fallback to direct creation (will still use global cache)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"> <span class="nam">font</span> <span class="op">=</span> <span class="nam">Font</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t"> <span class="nam">font_path</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">_font_path</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t"> <span class="nam">font_size</span><span class="op">=</span><span class="nam">page</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">max_font_size</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"> <span class="nam">colour</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">colour</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t"> <span class="nam">weight</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">weight</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t"> <span class="nam">style</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t"> <span class="nam">decoration</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">decoration</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"> <span class="nam">background</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">background</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t"> <span class="com"># Calculate baseline-to-baseline spacing: font size + additional line spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t"> <span class="com"># This is the vertical distance between baselines of consecutive lines</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t"> <span class="com"># Formula: baseline_spacing = font_size + line_spacing (absolute pixels)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t"> <span class="nam">line_spacing_value</span> <span class="op">=</span> <span class="nam">getattr</span><span class="op">(</span><span class="nam">page</span><span class="op">.</span><span class="nam">style</span><span class="op">,</span> <span class="str">'line_spacing'</span><span class="op">,</span> <span class="num">5</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t"> <span class="com"># Ensure line_spacing is an int (could be Mock in tests)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">line_spacing_value</span><span class="op">,</span> <span class="nam">int</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t"> <span class="nam">line_spacing_value</span> <span class="op">=</span> <span class="num">5</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t"> <span class="nam">baseline_spacing</span> <span class="op">=</span> <span class="nam">font</span><span class="op">.</span><span class="nam">font_size</span> <span class="op">+</span> <span class="nam">line_spacing_value</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t"> <span class="com"># Get font metrics for boundary checking</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"> <span class="nam">ascent</span><span class="op">,</span> <span class="nam">descent</span> <span class="op">=</span> <span class="nam">font</span><span class="op">.</span><span class="nam">font</span><span class="op">.</span><span class="nam">getmetrics</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"> <span class="key">def</span> <span class="nam">create_new_line</span><span class="op">(</span><span class="nam">word</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Union</span><span class="op">[</span><span class="nam">Word</span><span class="op">,</span> <span class="nam">Text</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t"> <span class="nam">is_first_line</span><span class="op">:</span> <span class="nam">bool</span> <span class="op">=</span> <span class="key">False</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Line</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t"> <span class="str">"""Helper function to create a new line, returns None if page is full."""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t"> <span class="com"># Check if this line's baseline and descenders would fit on the page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">page</span><span class="op">.</span><span class="nam">can_fit_line</span><span class="op">(</span><span class="nam">baseline_spacing</span><span class="op">,</span> <span class="nam">ascent</span><span class="op">,</span> <span class="nam">descent</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t"> <span class="com"># For the first line, position it so text starts at the top boundary</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t"> <span class="com"># For subsequent lines, use current y_offset which tracks</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"> <span class="com"># baseline-to-baseline spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"> <span class="key">if</span> <span class="nam">is_first_line</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">148&#x202F;&#x219B;&#x202F;151</span><span class="annotate long">line 148 didn't jump to line 151 because the condition on line 148 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t"> <span class="com"># Position line origin so that baseline (origin + ascent) is close to top</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t"> <span class="com"># We want minimal space above the text, so origin should be at boundary</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t"> <span class="nam">y_cursor</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">_current_y_offset</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t"> <span class="nam">y_cursor</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">_current_y_offset</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t"> <span class="nam">x_cursor</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">border_size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t"> <span class="com"># Create a temporary Text object to calculate word width</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t"> <span class="key">if</span> <span class="nam">word</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t"> <span class="nam">temp_text</span> <span class="op">=</span> <span class="nam">Text</span><span class="op">.</span><span class="nam">from_word</span><span class="op">(</span><span class="nam">word</span><span class="op">,</span> <span class="nam">page</span><span class="op">.</span><span class="nam">draw</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t"> <span class="nam">temp_text</span><span class="op">.</span><span class="nam">width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t"> <span class="key">pass</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"> <span class="key">return</span> <span class="nam">Line</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t"> <span class="nam">spacing</span><span class="op">=</span><span class="nam">word_spacing_constraints</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t"> <span class="nam">origin</span><span class="op">=</span><span class="op">(</span><span class="nam">x_cursor</span><span class="op">,</span> <span class="nam">y_cursor</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"> <span class="nam">size</span><span class="op">=</span><span class="op">(</span><span class="nam">page</span><span class="op">.</span><span class="nam">available_width</span><span class="op">,</span> <span class="nam">baseline_spacing</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t"> <span class="nam">draw</span><span class="op">=</span><span class="nam">page</span><span class="op">.</span><span class="nam">draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t"> <span class="nam">font</span><span class="op">=</span><span class="nam">font</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t"> <span class="nam">halign</span><span class="op">=</span><span class="nam">text_align</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t"> <span class="com"># Create initial line</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t"> <span class="nam">current_line</span> <span class="op">=</span> <span class="nam">create_new_line</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">current_line</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span><span class="op">,</span> <span class="nam">start_word</span><span class="op">,</span> <span class="nam">pretext</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t"> <span class="nam">page</span><span class="op">.</span><span class="nam">add_child</span><span class="op">(</span><span class="nam">current_line</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t"> <span class="com"># Note: add_child already updates _current_y_offset based on child's origin and size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t"> <span class="com"># No need to manually increment it here</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t"> <span class="com"># Track current position in paragraph</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t"> <span class="nam">current_pretext</span> <span class="op">=</span> <span class="nam">pretext</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t"> <span class="com"># Process words starting from start_word</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t"> <span class="key">for</span> <span class="nam">i</span><span class="op">,</span> <span class="nam">word</span> <span class="key">in</span> <span class="nam">enumerate</span><span class="op">(</span><span class="nam">paragraph</span><span class="op">.</span><span class="nam">words</span><span class="op">[</span><span class="nam">start_word</span><span class="op">:</span><span class="op">]</span><span class="op">,</span> <span class="nam">start</span><span class="op">=</span><span class="nam">start_word</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t"> <span class="com"># Check if this is a LinkedWord and needs special handling in concrete layer</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t"> <span class="com"># Note: The Line.add_word method will create Text objects internally,</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t"> <span class="com"># but we may want to create LinkText for LinkedWord instances in future</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t"> <span class="com"># For now, the abstract layer (LinkedWord) carries the link info,</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t"> <span class="com"># and the concrete layer (LinkText) would be created during rendering</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t"> <span class="nam">success</span><span class="op">,</span> <span class="nam">overflow_text</span> <span class="op">=</span> <span class="nam">current_line</span><span class="op">.</span><span class="nam">add_word</span><span class="op">(</span><span class="nam">word</span><span class="op">,</span> <span class="nam">current_pretext</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t"> <span class="key">if</span> <span class="nam">success</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t"> <span class="com"># Word fit successfully</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t"> <span class="key">if</span> <span class="nam">overflow_text</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"> <span class="com"># If there's overflow text, we need to start a new line with it</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t"> <span class="nam">current_pretext</span> <span class="op">=</span> <span class="nam">overflow_text</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t"> <span class="nam">current_line</span> <span class="op">=</span> <span class="nam">create_new_line</span><span class="op">(</span><span class="nam">overflow_text</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">current_line</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t"> <span class="com"># If we can't create a new line, return with the current state</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span><span class="op">,</span> <span class="nam">i</span><span class="op">,</span> <span class="nam">overflow_text</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t"> <span class="nam">page</span><span class="op">.</span><span class="nam">add_child</span><span class="op">(</span><span class="nam">current_line</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t"> <span class="com"># Note: add_child already updates _current_y_offset</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t"> <span class="com"># Continue to the next word</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t"> <span class="key">continue</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"> <span class="com"># No overflow, clear pretext</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t"> <span class="nam">current_pretext</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t"> <span class="com"># Word didn't fit, need a new line</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t"> <span class="nam">current_line</span> <span class="op">=</span> <span class="nam">create_new_line</span><span class="op">(</span><span class="nam">word</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">current_line</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t"> <span class="com"># Page is full, return current position</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span><span class="op">,</span> <span class="nam">i</span><span class="op">,</span> <span class="nam">overflow_text</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t"> <span class="com"># Check if the word will fit on the new line before adding it</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t"> <span class="nam">temp_text</span> <span class="op">=</span> <span class="nam">Text</span><span class="op">.</span><span class="nam">from_word</span><span class="op">(</span><span class="nam">word</span><span class="op">,</span> <span class="nam">page</span><span class="op">.</span><span class="nam">draw</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t"> <span class="key">if</span> <span class="nam">temp_text</span><span class="op">.</span><span class="nam">width</span> <span class="op">></span> <span class="nam">current_line</span><span class="op">.</span><span class="nam">size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t"> <span class="com"># Word is too wide for the line, we need to hyphenate it</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t"> <span class="key">if</span> <span class="nam">len</span><span class="op">(</span><span class="nam">word</span><span class="op">.</span><span class="nam">text</span><span class="op">)</span> <span class="op">>=</span> <span class="num">6</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">221&#x202F;&#x219B;&#x202F;243</span><span class="annotate long">line 221 didn't jump to line 243 because the condition on line 221 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"> <span class="com"># Try to hyphenate the word</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t"> <span class="nam">splits</span> <span class="op">=</span> <span class="op">[</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t"> <span class="op">(</span><span class="nam">Text</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t"> <span class="nam">pair</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t"> <span class="nam">word</span><span class="op">.</span><span class="nam">style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t"> <span class="nam">page</span><span class="op">.</span><span class="nam">draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t"> <span class="nam">line</span><span class="op">=</span><span class="nam">current_line</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t"> <span class="nam">source</span><span class="op">=</span><span class="nam">word</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t"> <span class="nam">Text</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t"> <span class="nam">pair</span><span class="op">[</span><span class="num">1</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t"> <span class="nam">word</span><span class="op">.</span><span class="nam">style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t"> <span class="nam">page</span><span class="op">.</span><span class="nam">draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t"> <span class="nam">line</span><span class="op">=</span><span class="nam">current_line</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t"> <span class="nam">source</span><span class="op">=</span><span class="nam">word</span><span class="op">)</span><span class="op">)</span> <span class="key">for</span> <span class="nam">pair</span> <span class="key">in</span> <span class="nam">word</span><span class="op">.</span><span class="nam">possible_hyphenation</span><span class="op">(</span><span class="op">)</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t"> <span class="key">if</span> <span class="nam">len</span><span class="op">(</span><span class="nam">splits</span><span class="op">)</span> <span class="op">></span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">236&#x202F;&#x219B;&#x202F;243</span><span class="annotate long">line 236 didn't jump to line 243 because the condition on line 236 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t"> <span class="com"># Use the first hyphenation point</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t"> <span class="nam">first_part</span><span class="op">,</span> <span class="nam">second_part</span> <span class="op">=</span> <span class="nam">splits</span><span class="op">[</span><span class="num">0</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t"> <span class="nam">current_line</span><span class="op">.</span><span class="nam">add_word</span><span class="op">(</span><span class="nam">word</span><span class="op">,</span> <span class="nam">first_part</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t"> <span class="nam">current_pretext</span> <span class="op">=</span> <span class="nam">second_part</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t"> <span class="key">continue</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t"> <span class="nam">page</span><span class="op">.</span><span class="nam">add_child</span><span class="op">(</span><span class="nam">current_line</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t"> <span class="com"># Note: add_child already updates _current_y_offset</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t"> <span class="com"># Try to add the word to the new line</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t"> <span class="nam">success</span><span class="op">,</span> <span class="nam">overflow_text</span> <span class="op">=</span> <span class="nam">current_line</span><span class="op">.</span><span class="nam">add_word</span><span class="op">(</span><span class="nam">word</span><span class="op">,</span> <span class="nam">current_pretext</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">success</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">249&#x202F;&#x219B;&#x202F;252</span><span class="annotate long">line 249 didn't jump to line 252 because the condition on line 249 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t"> <span class="com"># Word still doesn't fit even on a new line</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t"> <span class="com"># This might happen with very long words or narrow pages</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t"> <span class="key">if</span> <span class="nam">overflow_text</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t"> <span class="com"># Word was hyphenated, continue with the overflow</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t"> <span class="nam">current_pretext</span> <span class="op">=</span> <span class="nam">overflow_text</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t"> <span class="key">continue</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t"> <span class="com"># Word cannot be broken, skip it or handle as error</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t"> <span class="com"># For now, we'll return indicating we couldn't process this word</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span><span class="op">,</span> <span class="nam">i</span><span class="op">,</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t"> <span class="nam">current_pretext</span> <span class="op">=</span> <span class="nam">overflow_text</span> <span class="com"># May be None or hyphenated remainder</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t"> <span class="com"># All words processed successfully</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span><span class="op">,</span> <span class="key">None</span><span class="op">,</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t"><span class="key">def</span> <span class="nam">pagebreak_layouter</span><span class="op">(</span><span class="nam">page_break</span><span class="op">:</span> <span class="nam">PageBreak</span><span class="op">,</span> <span class="nam">page</span><span class="op">:</span> <span class="nam">Page</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t"><span class="str"> Handle a page break element.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t"><span class="str"> A page break signals that all subsequent content should start on a new page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t"><span class="str"> This function always returns False to indicate that the current page is complete</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t"><span class="str"> and a new page should be created for subsequent content.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t"><span class="str"> page_break: The PageBreak block</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t"><span class="str"> page: The current page (not used, but kept for consistency)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t279" href="#t279">279</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t280" href="#t280">280</a></span><span class="t"><span class="str"> bool: Always False to force creation of a new page</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t281" href="#t281">281</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t282" href="#t282">282</a></span><span class="t"> <span class="com"># Page break always forces a new page</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t283" href="#t283">283</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t284" href="#t284">284</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t285" href="#t285">285</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t286" href="#t286">286</a></span><span class="t"><span class="key">def</span> <span class="nam">image_layouter</span><span class="op">(</span><span class="nam">image</span><span class="op">:</span> <span class="nam">AbstractImage</span><span class="op">,</span> <span class="nam">page</span><span class="op">:</span> <span class="nam">Page</span><span class="op">,</span> <span class="nam">max_width</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t287" href="#t287">287</a></span><span class="t"> <span class="nam">max_height</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t288" href="#t288">288</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t289" href="#t289">289</a></span><span class="t"><span class="str"> Layout an image within a given page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t290" href="#t290">290</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t291" href="#t291">291</a></span><span class="t"><span class="str"> This function places an image on the page, respecting size constraints</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t292" href="#t292">292</a></span><span class="t"><span class="str"> and available space. Images are centered horizontally by default.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t293" href="#t293">293</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t294" href="#t294">294</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t295" href="#t295">295</a></span><span class="t"><span class="str"> image: The abstract Image object to layout</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t296" href="#t296">296</a></span><span class="t"><span class="str"> page: The page to layout the image on</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t297" href="#t297">297</a></span><span class="t"><span class="str"> max_width: Maximum width constraint (defaults to page available width)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t298" href="#t298">298</a></span><span class="t"><span class="str"> max_height: Maximum height constraint (defaults to remaining page height)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t299" href="#t299">299</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t300" href="#t300">300</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t301" href="#t301">301</a></span><span class="t"><span class="str"> bool: True if image was successfully laid out, False if page ran out of space</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t302" href="#t302">302</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t303" href="#t303">303</a></span><span class="t"> <span class="com"># Use page available width if max_width not specified</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t304" href="#t304">304</a></span><span class="t"> <span class="key">if</span> <span class="nam">max_width</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t305" href="#t305">305</a></span><span class="t"> <span class="nam">max_width</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">available_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t306" href="#t306">306</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t307" href="#t307">307</a></span><span class="t"> <span class="com"># Calculate available height on page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t308" href="#t308">308</a></span><span class="t"> <span class="nam">available_height</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">-</span> <span class="nam">page</span><span class="op">.</span><span class="nam">_current_y_offset</span> <span class="op">-</span> <span class="nam">page</span><span class="op">.</span><span class="nam">border_size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t309" href="#t309">309</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t310" href="#t310">310</a></span><span class="t"> <span class="com"># If no space available, image doesn't fit</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t311" href="#t311">311</a></span><span class="t"> <span class="key">if</span> <span class="nam">available_height</span> <span class="op">&lt;=</span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">311&#x202F;&#x219B;&#x202F;312</span><span class="annotate long">line 311 didn't jump to line 312 because the condition on line 311 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t312" href="#t312">312</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t313" href="#t313">313</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t314" href="#t314">314</a></span><span class="t"> <span class="key">if</span> <span class="nam">max_height</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t315" href="#t315">315</a></span><span class="t"> <span class="nam">max_height</span> <span class="op">=</span> <span class="nam">available_height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t316" href="#t316">316</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t317" href="#t317">317</a></span><span class="t"> <span class="nam">max_height</span> <span class="op">=</span> <span class="nam">min</span><span class="op">(</span><span class="nam">max_height</span><span class="op">,</span> <span class="nam">available_height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t318" href="#t318">318</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t319" href="#t319">319</a></span><span class="t"> <span class="com"># Calculate scaled dimensions</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t320" href="#t320">320</a></span><span class="t"> <span class="nam">scaled_width</span><span class="op">,</span> <span class="nam">scaled_height</span> <span class="op">=</span> <span class="nam">image</span><span class="op">.</span><span class="nam">calculate_scaled_dimensions</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t321" href="#t321">321</a></span><span class="t"> <span class="nam">max_width</span><span class="op">,</span> <span class="nam">max_height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t322" href="#t322">322</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t323" href="#t323">323</a></span><span class="t"> <span class="com"># Check if image fits on current page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t324" href="#t324">324</a></span><span class="t"> <span class="key">if</span> <span class="nam">scaled_height</span> <span class="key">is</span> <span class="key">None</span> <span class="key">or</span> <span class="nam">scaled_height</span> <span class="op">></span> <span class="nam">available_height</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t325" href="#t325">325</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t326" href="#t326">326</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t327" href="#t327">327</a></span><span class="t"> <span class="com"># Create renderable image</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t328" href="#t328">328</a></span><span class="t"> <span class="nam">x_offset</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">border_size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t329" href="#t329">329</a></span><span class="t"> <span class="nam">y_offset</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">_current_y_offset</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t330" href="#t330">330</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t331" href="#t331">331</a></span><span class="t"> <span class="com"># Access page.draw to ensure canvas is initialized</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t332" href="#t332">332</a></span><span class="t"> <span class="nam">_</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">draw</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t333" href="#t333">333</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t334" href="#t334">334</a></span><span class="t"> <span class="nam">renderable_image</span> <span class="op">=</span> <span class="nam">RenderableImage</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t335" href="#t335">335</a></span><span class="t"> <span class="nam">image</span><span class="op">=</span><span class="nam">image</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t336" href="#t336">336</a></span><span class="t"> <span class="nam">canvas</span><span class="op">=</span><span class="nam">page</span><span class="op">.</span><span class="nam">_canvas</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t337" href="#t337">337</a></span><span class="t"> <span class="nam">max_width</span><span class="op">=</span><span class="nam">max_width</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t338" href="#t338">338</a></span><span class="t"> <span class="nam">max_height</span><span class="op">=</span><span class="nam">max_height</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t339" href="#t339">339</a></span><span class="t"> <span class="nam">origin</span><span class="op">=</span><span class="op">(</span><span class="nam">x_offset</span><span class="op">,</span> <span class="nam">y_offset</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t340" href="#t340">340</a></span><span class="t"> <span class="nam">size</span><span class="op">=</span><span class="op">(</span><span class="nam">scaled_width</span> <span class="key">or</span> <span class="nam">max_width</span><span class="op">,</span> <span class="nam">scaled_height</span> <span class="key">or</span> <span class="nam">max_height</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t341" href="#t341">341</a></span><span class="t"> <span class="nam">halign</span><span class="op">=</span><span class="nam">Alignment</span><span class="op">.</span><span class="nam">CENTER</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t342" href="#t342">342</a></span><span class="t"> <span class="nam">valign</span><span class="op">=</span><span class="nam">Alignment</span><span class="op">.</span><span class="nam">TOP</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t343" href="#t343">343</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t344" href="#t344">344</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t345" href="#t345">345</a></span><span class="t"> <span class="com"># Add to page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t346" href="#t346">346</a></span><span class="t"> <span class="nam">page</span><span class="op">.</span><span class="nam">add_child</span><span class="op">(</span><span class="nam">renderable_image</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t347" href="#t347">347</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t348" href="#t348">348</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t349" href="#t349">349</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t350" href="#t350">350</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t351" href="#t351">351</a></span><span class="t"><span class="key">def</span> <span class="nam">table_layouter</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t352" href="#t352">352</a></span><span class="t"> <span class="nam">table</span><span class="op">:</span> <span class="nam">Table</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t353" href="#t353">353</a></span><span class="t"> <span class="nam">page</span><span class="op">:</span> <span class="nam">Page</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t354" href="#t354">354</a></span><span class="t"> <span class="nam">style</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">TableStyle</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t355" href="#t355">355</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t356" href="#t356">356</a></span><span class="t"><span class="str"> Layout a table within a given page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t357" href="#t357">357</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t358" href="#t358">358</a></span><span class="t"><span class="str"> This function uses the TableRenderer to render the table at the current</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t359" href="#t359">359</a></span><span class="t"><span class="str"> page position, advancing the page's y-offset after successful rendering.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t360" href="#t360">360</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t361" href="#t361">361</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t362" href="#t362">362</a></span><span class="t"><span class="str"> table: The abstract Table object to layout</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t363" href="#t363">363</a></span><span class="t"><span class="str"> page: The page to layout the table on</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t364" href="#t364">364</a></span><span class="t"><span class="str"> style: Optional table styling configuration</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t365" href="#t365">365</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t366" href="#t366">366</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t367" href="#t367">367</a></span><span class="t"><span class="str"> bool: True if table was successfully laid out, False if page ran out of space</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t368" href="#t368">368</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t369" href="#t369">369</a></span><span class="t"> <span class="com"># Calculate available space</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t370" href="#t370">370</a></span><span class="t"> <span class="nam">available_width</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">available_width</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t371" href="#t371">371</a></span><span class="t"> <span class="nam">x_offset</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">border_size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t372" href="#t372">372</a></span><span class="t"> <span class="nam">y_offset</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">_current_y_offset</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t373" href="#t373">373</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t374" href="#t374">374</a></span><span class="t"> <span class="com"># Access page.draw to ensure canvas is initialized</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t375" href="#t375">375</a></span><span class="t"> <span class="nam">draw</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">draw</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t376" href="#t376">376</a></span><span class="t"> <span class="nam">canvas</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">_canvas</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t377" href="#t377">377</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t378" href="#t378">378</a></span><span class="t"> <span class="com"># Create table renderer</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t379" href="#t379">379</a></span><span class="t"> <span class="nam">origin</span> <span class="op">=</span> <span class="op">(</span><span class="nam">x_offset</span><span class="op">,</span> <span class="nam">y_offset</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t380" href="#t380">380</a></span><span class="t"> <span class="nam">renderer</span> <span class="op">=</span> <span class="nam">TableRenderer</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t381" href="#t381">381</a></span><span class="t"> <span class="nam">table</span><span class="op">=</span><span class="nam">table</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t382" href="#t382">382</a></span><span class="t"> <span class="nam">origin</span><span class="op">=</span><span class="nam">origin</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t383" href="#t383">383</a></span><span class="t"> <span class="nam">available_width</span><span class="op">=</span><span class="nam">available_width</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t384" href="#t384">384</a></span><span class="t"> <span class="nam">draw</span><span class="op">=</span><span class="nam">draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t385" href="#t385">385</a></span><span class="t"> <span class="nam">style</span><span class="op">=</span><span class="nam">style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t386" href="#t386">386</a></span><span class="t"> <span class="nam">canvas</span><span class="op">=</span><span class="nam">canvas</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t387" href="#t387">387</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t388" href="#t388">388</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t389" href="#t389">389</a></span><span class="t"> <span class="com"># Check if table fits on current page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t390" href="#t390">390</a></span><span class="t"> <span class="nam">table_height</span> <span class="op">=</span> <span class="nam">renderer</span><span class="op">.</span><span class="nam">size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t391" href="#t391">391</a></span><span class="t"> <span class="nam">available_height</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">-</span> <span class="nam">y_offset</span> <span class="op">-</span> <span class="nam">page</span><span class="op">.</span><span class="nam">border_size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t392" href="#t392">392</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t393" href="#t393">393</a></span><span class="t"> <span class="key">if</span> <span class="nam">table_height</span> <span class="op">></span> <span class="nam">available_height</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t394" href="#t394">394</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t395" href="#t395">395</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t396" href="#t396">396</a></span><span class="t"> <span class="com"># Render the table</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t397" href="#t397">397</a></span><span class="t"> <span class="nam">renderer</span><span class="op">.</span><span class="nam">render</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t398" href="#t398">398</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t399" href="#t399">399</a></span><span class="t"> <span class="com"># Update page y-offset</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t400" href="#t400">400</a></span><span class="t"> <span class="nam">page</span><span class="op">.</span><span class="nam">_current_y_offset</span> <span class="op">=</span> <span class="nam">y_offset</span> <span class="op">+</span> <span class="nam">table_height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t401" href="#t401">401</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t402" href="#t402">402</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t403" href="#t403">403</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t404" href="#t404">404</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t405" href="#t405">405</a></span><span class="t"><span class="key">def</span> <span class="nam">button_layouter</span><span class="op">(</span><span class="nam">button</span><span class="op">:</span> <span class="nam">Button</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t406" href="#t406">406</a></span><span class="t"> <span class="nam">page</span><span class="op">:</span> <span class="nam">Page</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t407" href="#t407">407</a></span><span class="t"> <span class="nam">font</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Font</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t408" href="#t408">408</a></span><span class="t"> <span class="nam">padding</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t409" href="#t409">409</a></span><span class="t"> <span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t410" href="#t410">410</a></span><span class="t"> <span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t411" href="#t411">411</a></span><span class="t"> <span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="op">(</span><span class="num">4</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t412" href="#t412">412</a></span><span class="t"> <span class="num">8</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t413" href="#t413">413</a></span><span class="t"> <span class="num">4</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t414" href="#t414">414</a></span><span class="t"> <span class="num">8</span><span class="op">)</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">bool</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t415" href="#t415">415</a></span><span class="t"> <span class="nam">str</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t416" href="#t416">416</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t417" href="#t417">417</a></span><span class="t"><span class="str"> Layout a button within a given page and register it for callback binding.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t418" href="#t418">418</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t419" href="#t419">419</a></span><span class="t"><span class="str"> This function creates a ButtonText renderable, positions it on the page,</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t420" href="#t420">420</a></span><span class="t"><span class="str"> and registers it in the page's callback registry using the button's html_id</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t421" href="#t421">421</a></span><span class="t"><span class="str"> (if available) or an auto-generated id.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t422" href="#t422">422</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t423" href="#t423">423</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t424" href="#t424">424</a></span><span class="t"><span class="str"> button: The abstract Button object to layout</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t425" href="#t425">425</a></span><span class="t"><span class="str"> page: The page to layout the button on</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t426" href="#t426">426</a></span><span class="t"><span class="str"> font: Optional font for button text (defaults to page default)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t427" href="#t427">427</a></span><span class="t"><span class="str"> padding: Padding around button text (top, right, bottom, left)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t428" href="#t428">428</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t429" href="#t429">429</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t430" href="#t430">430</a></span><span class="t"><span class="str"> Tuple of:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t431" href="#t431">431</a></span><span class="t"><span class="str"> - bool: True if button was successfully laid out, False if page ran out of space</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t432" href="#t432">432</a></span><span class="t"><span class="str"> - str: The id used to register the button in the callback registry</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t433" href="#t433">433</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t434" href="#t434">434</a></span><span class="t"> <span class="com"># Use provided font or create a default one</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t435" href="#t435">435</a></span><span class="t"> <span class="key">if</span> <span class="nam">font</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t436" href="#t436">436</a></span><span class="t"> <span class="nam">font</span> <span class="op">=</span> <span class="nam">Font</span><span class="op">(</span><span class="nam">font_size</span><span class="op">=</span><span class="num">14</span><span class="op">,</span> <span class="nam">colour</span><span class="op">=</span><span class="op">(</span><span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t437" href="#t437">437</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t438" href="#t438">438</a></span><span class="t"> <span class="com"># Calculate available space</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t439" href="#t439">439</a></span><span class="t"> <span class="nam">available_height</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">-</span> <span class="nam">page</span><span class="op">.</span><span class="nam">_current_y_offset</span> <span class="op">-</span> <span class="nam">page</span><span class="op">.</span><span class="nam">border_size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t440" href="#t440">440</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t441" href="#t441">441</a></span><span class="t"> <span class="com"># Create ButtonText renderable</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t442" href="#t442">442</a></span><span class="t"> <span class="nam">button_text</span> <span class="op">=</span> <span class="nam">ButtonText</span><span class="op">(</span><span class="nam">button</span><span class="op">,</span> <span class="nam">font</span><span class="op">,</span> <span class="nam">page</span><span class="op">.</span><span class="nam">draw</span><span class="op">,</span> <span class="nam">padding</span><span class="op">=</span><span class="nam">padding</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t443" href="#t443">443</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t444" href="#t444">444</a></span><span class="t"> <span class="com"># Check if button fits on current page</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t445" href="#t445">445</a></span><span class="t"> <span class="nam">button_height</span> <span class="op">=</span> <span class="nam">button_text</span><span class="op">.</span><span class="nam">size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t446" href="#t446">446</a></span><span class="t"> <span class="key">if</span> <span class="nam">button_height</span> <span class="op">></span> <span class="nam">available_height</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t447" href="#t447">447</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span><span class="op">,</span> <span class="str">""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t448" href="#t448">448</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t449" href="#t449">449</a></span><span class="t"> <span class="com"># Position the button</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t450" href="#t450">450</a></span><span class="t"> <span class="nam">x_offset</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">border_size</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t451" href="#t451">451</a></span><span class="t"> <span class="nam">y_offset</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">_current_y_offset</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t452" href="#t452">452</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t453" href="#t453">453</a></span><span class="t"> <span class="nam">button_text</span><span class="op">.</span><span class="nam">set_origin</span><span class="op">(</span><span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="op">[</span><span class="nam">x_offset</span><span class="op">,</span> <span class="nam">y_offset</span><span class="op">]</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t454" href="#t454">454</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t455" href="#t455">455</a></span><span class="t"> <span class="com"># Register in callback registry</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t456" href="#t456">456</a></span><span class="t"> <span class="nam">html_id</span> <span class="op">=</span> <span class="nam">button</span><span class="op">.</span><span class="nam">html_id</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t457" href="#t457">457</a></span><span class="t"> <span class="nam">registered_id</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">callbacks</span><span class="op">.</span><span class="nam">register</span><span class="op">(</span><span class="nam">button_text</span><span class="op">,</span> <span class="nam">html_id</span><span class="op">=</span><span class="nam">html_id</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t458" href="#t458">458</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t459" href="#t459">459</a></span><span class="t"> <span class="com"># Add to page</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t460" href="#t460">460</a></span><span class="t"> <span class="nam">page</span><span class="op">.</span><span class="nam">add_child</span><span class="op">(</span><span class="nam">button_text</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t461" href="#t461">461</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t462" href="#t462">462</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span><span class="op">,</span> <span class="nam">registered_id</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t463" href="#t463">463</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t464" href="#t464">464</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t465" href="#t465">465</a></span><span class="t"><span class="key">def</span> <span class="nam">form_field_layouter</span><span class="op">(</span><span class="nam">field</span><span class="op">:</span> <span class="nam">FormField</span><span class="op">,</span> <span class="nam">page</span><span class="op">:</span> <span class="nam">Page</span><span class="op">,</span> <span class="nam">font</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Font</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t466" href="#t466">466</a></span><span class="t"> <span class="nam">field_height</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">24</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">bool</span><span class="op">,</span> <span class="nam">str</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t467" href="#t467">467</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t468" href="#t468">468</a></span><span class="t"><span class="str"> Layout a form field within a given page and register it for callback binding.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t469" href="#t469">469</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t470" href="#t470">470</a></span><span class="t"><span class="str"> This function creates a FormFieldText renderable, positions it on the page,</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t471" href="#t471">471</a></span><span class="t"><span class="str"> and registers it in the page's callback registry.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t472" href="#t472">472</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t473" href="#t473">473</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t474" href="#t474">474</a></span><span class="t"><span class="str"> field: The abstract FormField object to layout</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t475" href="#t475">475</a></span><span class="t"><span class="str"> page: The page to layout the field on</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t476" href="#t476">476</a></span><span class="t"><span class="str"> font: Optional font for field label (defaults to page default)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t477" href="#t477">477</a></span><span class="t"><span class="str"> field_height: Height of the input field area</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t478" href="#t478">478</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t479" href="#t479">479</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t480" href="#t480">480</a></span><span class="t"><span class="str"> Tuple of:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t481" href="#t481">481</a></span><span class="t"><span class="str"> - bool: True if field was successfully laid out, False if page ran out of space</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t482" href="#t482">482</a></span><span class="t"><span class="str"> - str: The id used to register the field in the callback registry</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t483" href="#t483">483</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t484" href="#t484">484</a></span><span class="t"> <span class="com"># Use provided font or create a default one</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t485" href="#t485">485</a></span><span class="t"> <span class="key">if</span> <span class="nam">font</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">485&#x202F;&#x219B;&#x202F;486</span><span class="annotate long">line 485 didn't jump to line 486 because the condition on line 485 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t486" href="#t486">486</a></span><span class="t"> <span class="nam">font</span> <span class="op">=</span> <span class="nam">Font</span><span class="op">(</span><span class="nam">font_size</span><span class="op">=</span><span class="num">12</span><span class="op">,</span> <span class="nam">colour</span><span class="op">=</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t487" href="#t487">487</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t488" href="#t488">488</a></span><span class="t"> <span class="com"># Calculate available space</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t489" href="#t489">489</a></span><span class="t"> <span class="nam">available_height</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">-</span> <span class="nam">page</span><span class="op">.</span><span class="nam">_current_y_offset</span> <span class="op">-</span> <span class="nam">page</span><span class="op">.</span><span class="nam">border_size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t490" href="#t490">490</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t491" href="#t491">491</a></span><span class="t"> <span class="com"># Create FormFieldText renderable</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t492" href="#t492">492</a></span><span class="t"> <span class="nam">field_text</span> <span class="op">=</span> <span class="nam">FormFieldText</span><span class="op">(</span><span class="nam">field</span><span class="op">,</span> <span class="nam">font</span><span class="op">,</span> <span class="nam">page</span><span class="op">.</span><span class="nam">draw</span><span class="op">,</span> <span class="nam">field_height</span><span class="op">=</span><span class="nam">field_height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t493" href="#t493">493</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t494" href="#t494">494</a></span><span class="t"> <span class="com"># Check if field fits on current page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t495" href="#t495">495</a></span><span class="t"> <span class="nam">total_field_height</span> <span class="op">=</span> <span class="nam">field_text</span><span class="op">.</span><span class="nam">size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t496" href="#t496">496</a></span><span class="t"> <span class="key">if</span> <span class="nam">total_field_height</span> <span class="op">></span> <span class="nam">available_height</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">496&#x202F;&#x219B;&#x202F;497</span><span class="annotate long">line 496 didn't jump to line 497 because the condition on line 496 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t497" href="#t497">497</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span><span class="op">,</span> <span class="str">""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t498" href="#t498">498</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t499" href="#t499">499</a></span><span class="t"> <span class="com"># Position the field</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t500" href="#t500">500</a></span><span class="t"> <span class="nam">x_offset</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">border_size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t501" href="#t501">501</a></span><span class="t"> <span class="nam">y_offset</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">_current_y_offset</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t502" href="#t502">502</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t503" href="#t503">503</a></span><span class="t"> <span class="nam">field_text</span><span class="op">.</span><span class="nam">set_origin</span><span class="op">(</span><span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="op">[</span><span class="nam">x_offset</span><span class="op">,</span> <span class="nam">y_offset</span><span class="op">]</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t504" href="#t504">504</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t505" href="#t505">505</a></span><span class="t"> <span class="com"># Register in callback registry (use field name as html_id fallback)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t506" href="#t506">506</a></span><span class="t"> <span class="nam">html_id</span> <span class="op">=</span> <span class="nam">getattr</span><span class="op">(</span><span class="nam">field</span><span class="op">,</span> <span class="str">'_html_id'</span><span class="op">,</span> <span class="key">None</span><span class="op">)</span> <span class="key">or</span> <span class="nam">field</span><span class="op">.</span><span class="nam">name</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t507" href="#t507">507</a></span><span class="t"> <span class="nam">registered_id</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">callbacks</span><span class="op">.</span><span class="nam">register</span><span class="op">(</span><span class="nam">field_text</span><span class="op">,</span> <span class="nam">html_id</span><span class="op">=</span><span class="nam">html_id</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t508" href="#t508">508</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t509" href="#t509">509</a></span><span class="t"> <span class="com"># Add to page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t510" href="#t510">510</a></span><span class="t"> <span class="nam">page</span><span class="op">.</span><span class="nam">add_child</span><span class="op">(</span><span class="nam">field_text</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t511" href="#t511">511</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t512" href="#t512">512</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span><span class="op">,</span> <span class="nam">registered_id</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t513" href="#t513">513</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t514" href="#t514">514</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t515" href="#t515">515</a></span><span class="t"><span class="key">def</span> <span class="nam">form_layouter</span><span class="op">(</span><span class="nam">form</span><span class="op">:</span> <span class="nam">Form</span><span class="op">,</span> <span class="nam">page</span><span class="op">:</span> <span class="nam">Page</span><span class="op">,</span> <span class="nam">font</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Font</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t516" href="#t516">516</a></span><span class="t"> <span class="nam">field_spacing</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">10</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">bool</span><span class="op">,</span> <span class="nam">List</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t517" href="#t517">517</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t518" href="#t518">518</a></span><span class="t"><span class="str"> Layout a complete form with all its fields within a given page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t519" href="#t519">519</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t520" href="#t520">520</a></span><span class="t"><span class="str"> This function creates FormFieldText renderables for all fields in the form,</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t521" href="#t521">521</a></span><span class="t"><span class="str"> positions them vertically, and registers both the form and its fields in</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t522" href="#t522">522</a></span><span class="t"><span class="str"> the page's callback registry.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t523" href="#t523">523</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t524" href="#t524">524</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t525" href="#t525">525</a></span><span class="t"><span class="str"> form: The abstract Form object to layout</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t526" href="#t526">526</a></span><span class="t"><span class="str"> page: The page to layout the form on</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t527" href="#t527">527</a></span><span class="t"><span class="str"> font: Optional font for field labels (defaults to page default)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t528" href="#t528">528</a></span><span class="t"><span class="str"> field_spacing: Vertical spacing between fields in pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t529" href="#t529">529</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t530" href="#t530">530</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t531" href="#t531">531</a></span><span class="t"><span class="str"> Tuple of:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t532" href="#t532">532</a></span><span class="t"><span class="str"> - bool: True if form was successfully laid out, False if page ran out of space</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t533" href="#t533">533</a></span><span class="t"><span class="str"> - List[str]: List of registered ids for all fields (empty if layout failed)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t534" href="#t534">534</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t535" href="#t535">535</a></span><span class="t"> <span class="com"># Use provided font or create a default one</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t536" href="#t536">536</a></span><span class="t"> <span class="key">if</span> <span class="nam">font</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">536&#x202F;&#x219B;&#x202F;537</span><span class="annotate long">line 536 didn't jump to line 537 because the condition on line 536 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t537" href="#t537">537</a></span><span class="t"> <span class="nam">font</span> <span class="op">=</span> <span class="nam">Font</span><span class="op">(</span><span class="nam">font_size</span><span class="op">=</span><span class="num">12</span><span class="op">,</span> <span class="nam">colour</span><span class="op">=</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t538" href="#t538">538</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t539" href="#t539">539</a></span><span class="t"> <span class="com"># Track registered field ids</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t540" href="#t540">540</a></span><span class="t"> <span class="nam">field_ids</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t541" href="#t541">541</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t542" href="#t542">542</a></span><span class="t"> <span class="com"># Layout each field in the form</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t543" href="#t543">543</a></span><span class="t"> <span class="key">for</span> <span class="nam">field_name</span><span class="op">,</span> <span class="nam">field</span> <span class="key">in</span> <span class="nam">form</span><span class="op">.</span><span class="nam">_fields</span><span class="op">.</span><span class="nam">items</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t544" href="#t544">544</a></span><span class="t"> <span class="com"># Add spacing before each field (except the first)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t545" href="#t545">545</a></span><span class="t"> <span class="key">if</span> <span class="nam">field_ids</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t546" href="#t546">546</a></span><span class="t"> <span class="nam">page</span><span class="op">.</span><span class="nam">_current_y_offset</span> <span class="op">+=</span> <span class="nam">field_spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t547" href="#t547">547</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t548" href="#t548">548</a></span><span class="t"> <span class="com"># Layout the field</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t549" href="#t549">549</a></span><span class="t"> <span class="nam">success</span><span class="op">,</span> <span class="nam">field_id</span> <span class="op">=</span> <span class="nam">form_field_layouter</span><span class="op">(</span><span class="nam">field</span><span class="op">,</span> <span class="nam">page</span><span class="op">,</span> <span class="nam">font</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t550" href="#t550">550</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t551" href="#t551">551</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">success</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">551&#x202F;&#x219B;&#x202F;553</span><span class="annotate long">line 551 didn't jump to line 553 because the condition on line 551 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t552" href="#t552">552</a></span><span class="t"> <span class="com"># Couldn't fit this field, return failure</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t553" href="#t553">553</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span><span class="op">,</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t554" href="#t554">554</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t555" href="#t555">555</a></span><span class="t"> <span class="nam">field_ids</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">field_id</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t556" href="#t556">556</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t557" href="#t557">557</a></span><span class="t"> <span class="com"># Register the form itself (optional, for form submission)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t558" href="#t558">558</a></span><span class="t"> <span class="com"># Note: The form doesn't have a visual representation, but we can track it</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t559" href="#t559">559</a></span><span class="t"> <span class="com"># for submission callbacks</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t560" href="#t560">560</a></span><span class="t"> <span class="com"># form_id = page.callbacks.register(form, html_id=form.html_id)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t561" href="#t561">561</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t562" href="#t562">562</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span><span class="op">,</span> <span class="nam">field_ids</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t563" href="#t563">563</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t564" href="#t564">564</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t565" href="#t565">565</a></span><span class="t"><span class="key">class</span> <span class="nam">DocumentLayouter</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t566" href="#t566">566</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t567" href="#t567">567</a></span><span class="t"><span class="str"> Document layouter that orchestrates layout of various abstract elements.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t568" href="#t568">568</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t569" href="#t569">569</a></span><span class="t"><span class="str"> Delegates to specialized layouters for different content types:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t570" href="#t570">570</a></span><span class="t"><span class="str"> - paragraph_layouter for text paragraphs</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t571" href="#t571">571</a></span><span class="t"><span class="str"> - image_layouter for images</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t572" href="#t572">572</a></span><span class="t"><span class="str"> - table_layouter for tables</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t573" href="#t573">573</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t574" href="#t574">574</a></span><span class="t"><span class="str"> This class acts as a coordinator, managing the overall document flow</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t575" href="#t575">575</a></span><span class="t"><span class="str"> and page context while delegating specific layout tasks to specialized</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t576" href="#t576">576</a></span><span class="t"><span class="str"> layouter functions.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t577" href="#t577">577</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t578" href="#t578">578</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t579" href="#t579">579</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">page</span><span class="op">:</span> <span class="nam">Page</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t580" href="#t580">580</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t581" href="#t581">581</a></span><span class="t"><span class="str"> Initialize the document layouter with a page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t582" href="#t582">582</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t583" href="#t583">583</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t584" href="#t584">584</a></span><span class="t"><span class="str"> page: The page to layout content on</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t585" href="#t585">585</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t586" href="#t586">586</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">page</span> <span class="op">=</span> <span class="nam">page</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t587" href="#t587">587</a></span><span class="t"> <span class="com"># Create a style resolver if page doesn't have one</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t588" href="#t588">588</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">page</span><span class="op">,</span> <span class="str">'style_resolver'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t589" href="#t589">589</a></span><span class="t"> <span class="nam">style_resolver</span> <span class="op">=</span> <span class="nam">page</span><span class="op">.</span><span class="nam">style_resolver</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t590" href="#t590">590</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t591" href="#t591">591</a></span><span class="t"> <span class="com"># Create a default rendering context and style resolver</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t592" href="#t592">592</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">concrete_style</span> <span class="key">import</span> <span class="nam">RenderingContext</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t593" href="#t593">593</a></span><span class="t"> <span class="nam">context</span> <span class="op">=</span> <span class="nam">RenderingContext</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t594" href="#t594">594</a></span><span class="t"> <span class="nam">style_resolver</span> <span class="op">=</span> <span class="nam">StyleResolver</span><span class="op">(</span><span class="nam">context</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t595" href="#t595">595</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">style_registry</span> <span class="op">=</span> <span class="nam">ConcreteStyleRegistry</span><span class="op">(</span><span class="nam">style_resolver</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t596" href="#t596">596</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t597" href="#t597">597</a></span><span class="t"> <span class="key">def</span> <span class="nam">layout_paragraph</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t598" href="#t598">598</a></span><span class="t"> <span class="nam">paragraph</span><span class="op">:</span> <span class="nam">Paragraph</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t599" href="#t599">599</a></span><span class="t"> <span class="nam">start_word</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">0</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t600" href="#t600">600</a></span><span class="t"> <span class="nam">pretext</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Text</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">bool</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t601" href="#t601">601</a></span><span class="t"> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t602" href="#t602">602</a></span><span class="t"> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Text</span><span class="op">]</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t603" href="#t603">603</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t604" href="#t604">604</a></span><span class="t"><span class="str"> Layout a paragraph using the paragraph_layouter.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t605" href="#t605">605</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t606" href="#t606">606</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t607" href="#t607">607</a></span><span class="t"><span class="str"> paragraph: The paragraph to layout</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t608" href="#t608">608</a></span><span class="t"><span class="str"> start_word: Index of the first word to process (for continuation)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t609" href="#t609">609</a></span><span class="t"><span class="str"> pretext: Optional pretext from a previous hyphenated word</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t610" href="#t610">610</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t611" href="#t611">611</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t612" href="#t612">612</a></span><span class="t"><span class="str"> Tuple of (success, failed_word_index, remaining_pretext)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t613" href="#t613">613</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t614" href="#t614">614</a></span><span class="t"> <span class="key">return</span> <span class="nam">paragraph_layouter</span><span class="op">(</span><span class="nam">paragraph</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page</span><span class="op">,</span> <span class="nam">start_word</span><span class="op">,</span> <span class="nam">pretext</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t615" href="#t615">615</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t616" href="#t616">616</a></span><span class="t"> <span class="key">def</span> <span class="nam">layout_image</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">image</span><span class="op">:</span> <span class="nam">AbstractImage</span><span class="op">,</span> <span class="nam">max_width</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t617" href="#t617">617</a></span><span class="t"> <span class="nam">max_height</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t618" href="#t618">618</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t619" href="#t619">619</a></span><span class="t"><span class="str"> Layout an image using the image_layouter.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t620" href="#t620">620</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t621" href="#t621">621</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t622" href="#t622">622</a></span><span class="t"><span class="str"> image: The abstract Image object to layout</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t623" href="#t623">623</a></span><span class="t"><span class="str"> max_width: Maximum width constraint (defaults to page available width)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t624" href="#t624">624</a></span><span class="t"><span class="str"> max_height: Maximum height constraint (defaults to remaining page height)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t625" href="#t625">625</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t626" href="#t626">626</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t627" href="#t627">627</a></span><span class="t"><span class="str"> bool: True if image was successfully laid out, False if page ran out of space</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t628" href="#t628">628</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t629" href="#t629">629</a></span><span class="t"> <span class="key">return</span> <span class="nam">image_layouter</span><span class="op">(</span><span class="nam">image</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page</span><span class="op">,</span> <span class="nam">max_width</span><span class="op">,</span> <span class="nam">max_height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t630" href="#t630">630</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t631" href="#t631">631</a></span><span class="t"> <span class="key">def</span> <span class="nam">layout_table</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">table</span><span class="op">:</span> <span class="nam">Table</span><span class="op">,</span> <span class="nam">style</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">TableStyle</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t632" href="#t632">632</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t633" href="#t633">633</a></span><span class="t"><span class="str"> Layout a table using the table_layouter.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t634" href="#t634">634</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t635" href="#t635">635</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t636" href="#t636">636</a></span><span class="t"><span class="str"> table: The abstract Table object to layout</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t637" href="#t637">637</a></span><span class="t"><span class="str"> style: Optional table styling configuration</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t638" href="#t638">638</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t639" href="#t639">639</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t640" href="#t640">640</a></span><span class="t"><span class="str"> bool: True if table was successfully laid out, False if page ran out of space</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t641" href="#t641">641</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t642" href="#t642">642</a></span><span class="t"> <span class="key">return</span> <span class="nam">table_layouter</span><span class="op">(</span><span class="nam">table</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page</span><span class="op">,</span> <span class="nam">style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t643" href="#t643">643</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t644" href="#t644">644</a></span><span class="t"> <span class="key">def</span> <span class="nam">layout_button</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t645" href="#t645">645</a></span><span class="t"> <span class="nam">button</span><span class="op">:</span> <span class="nam">Button</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t646" href="#t646">646</a></span><span class="t"> <span class="nam">font</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Font</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t647" href="#t647">647</a></span><span class="t"> <span class="nam">padding</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t648" href="#t648">648</a></span><span class="t"> <span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t649" href="#t649">649</a></span><span class="t"> <span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t650" href="#t650">650</a></span><span class="t"> <span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="op">(</span><span class="num">4</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t651" href="#t651">651</a></span><span class="t"> <span class="num">8</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t652" href="#t652">652</a></span><span class="t"> <span class="num">4</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t653" href="#t653">653</a></span><span class="t"> <span class="num">8</span><span class="op">)</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">bool</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t654" href="#t654">654</a></span><span class="t"> <span class="nam">str</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t655" href="#t655">655</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t656" href="#t656">656</a></span><span class="t"><span class="str"> Layout a button using the button_layouter.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t657" href="#t657">657</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t658" href="#t658">658</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t659" href="#t659">659</a></span><span class="t"><span class="str"> button: The abstract Button object to layout</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t660" href="#t660">660</a></span><span class="t"><span class="str"> font: Optional font for button text</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t661" href="#t661">661</a></span><span class="t"><span class="str"> padding: Padding around button text</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t662" href="#t662">662</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t663" href="#t663">663</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t664" href="#t664">664</a></span><span class="t"><span class="str"> Tuple of (success, registered_id)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t665" href="#t665">665</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t666" href="#t666">666</a></span><span class="t"> <span class="key">return</span> <span class="nam">button_layouter</span><span class="op">(</span><span class="nam">button</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page</span><span class="op">,</span> <span class="nam">font</span><span class="op">,</span> <span class="nam">padding</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t667" href="#t667">667</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t668" href="#t668">668</a></span><span class="t"> <span class="key">def</span> <span class="nam">layout_form</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">form</span><span class="op">:</span> <span class="nam">Form</span><span class="op">,</span> <span class="nam">font</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Font</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t669" href="#t669">669</a></span><span class="t"> <span class="nam">field_spacing</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">10</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">bool</span><span class="op">,</span> <span class="nam">List</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t670" href="#t670">670</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t671" href="#t671">671</a></span><span class="t"><span class="str"> Layout a form using the form_layouter.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t672" href="#t672">672</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t673" href="#t673">673</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t674" href="#t674">674</a></span><span class="t"><span class="str"> form: The abstract Form object to layout</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t675" href="#t675">675</a></span><span class="t"><span class="str"> font: Optional font for field labels</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t676" href="#t676">676</a></span><span class="t"><span class="str"> field_spacing: Vertical spacing between fields</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t677" href="#t677">677</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t678" href="#t678">678</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t679" href="#t679">679</a></span><span class="t"><span class="str"> Tuple of (success, list_of_field_ids)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t680" href="#t680">680</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t681" href="#t681">681</a></span><span class="t"> <span class="key">return</span> <span class="nam">form_layouter</span><span class="op">(</span><span class="nam">form</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page</span><span class="op">,</span> <span class="nam">font</span><span class="op">,</span> <span class="nam">field_spacing</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t682" href="#t682">682</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t683" href="#t683">683</a></span><span class="t"> <span class="key">def</span> <span class="nam">layout_document</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t684" href="#t684">684</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span> <span class="nam">elements</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">Union</span><span class="op">[</span><span class="nam">Paragraph</span><span class="op">,</span> <span class="nam">AbstractImage</span><span class="op">,</span> <span class="nam">Table</span><span class="op">,</span> <span class="nam">Button</span><span class="op">,</span> <span class="nam">Form</span><span class="op">]</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t685" href="#t685">685</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t686" href="#t686">686</a></span><span class="t"><span class="str"> Layout a list of abstract elements (paragraphs, images, tables, buttons, and forms).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t687" href="#t687">687</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t688" href="#t688">688</a></span><span class="t"><span class="str"> This method delegates to specialized layouters based on element type:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t689" href="#t689">689</a></span><span class="t"><span class="str"> - Paragraphs are handled by layout_paragraph</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t690" href="#t690">690</a></span><span class="t"><span class="str"> - Images are handled by layout_image</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t691" href="#t691">691</a></span><span class="t"><span class="str"> - Tables are handled by layout_table</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t692" href="#t692">692</a></span><span class="t"><span class="str"> - Buttons are handled by layout_button</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t693" href="#t693">693</a></span><span class="t"><span class="str"> - Forms are handled by layout_form</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t694" href="#t694">694</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t695" href="#t695">695</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t696" href="#t696">696</a></span><span class="t"><span class="str"> elements: List of abstract elements to layout</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t697" href="#t697">697</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t698" href="#t698">698</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t699" href="#t699">699</a></span><span class="t"><span class="str"> True if all elements were successfully laid out, False otherwise</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t700" href="#t700">700</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t701" href="#t701">701</a></span><span class="t"> <span class="key">for</span> <span class="nam">element</span> <span class="key">in</span> <span class="nam">elements</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t702" href="#t702">702</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">element</span><span class="op">,</span> <span class="nam">Paragraph</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t703" href="#t703">703</a></span><span class="t"> <span class="nam">success</span><span class="op">,</span> <span class="nam">_</span><span class="op">,</span> <span class="nam">_</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">layout_paragraph</span><span class="op">(</span><span class="nam">element</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t704" href="#t704">704</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">success</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t705" href="#t705">705</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t706" href="#t706">706</a></span><span class="t"> <span class="key">elif</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">element</span><span class="op">,</span> <span class="nam">AbstractImage</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t707" href="#t707">707</a></span><span class="t"> <span class="nam">success</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">layout_image</span><span class="op">(</span><span class="nam">element</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t708" href="#t708">708</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">success</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">708&#x202F;&#x219B;&#x202F;709</span><span class="annotate long">line 708 didn't jump to line 709 because the condition on line 708 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t709" href="#t709">709</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t710" href="#t710">710</a></span><span class="t"> <span class="key">elif</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">element</span><span class="op">,</span> <span class="nam">Table</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">710&#x202F;&#x219B;&#x202F;714</span><span class="annotate long">line 710 didn't jump to line 714 because the condition on line 710 was always true</span></span></p>
<p class="run"><span class="n"><a id="t711" href="#t711">711</a></span><span class="t"> <span class="nam">success</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">layout_table</span><span class="op">(</span><span class="nam">element</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t712" href="#t712">712</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">success</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t713" href="#t713">713</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t714" href="#t714">714</a></span><span class="t"> <span class="key">elif</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">element</span><span class="op">,</span> <span class="nam">Button</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t715" href="#t715">715</a></span><span class="t"> <span class="nam">success</span><span class="op">,</span> <span class="nam">_</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">layout_button</span><span class="op">(</span><span class="nam">element</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t716" href="#t716">716</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">success</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t717" href="#t717">717</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t718" href="#t718">718</a></span><span class="t"> <span class="key">elif</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">element</span><span class="op">,</span> <span class="nam">Form</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t719" href="#t719">719</a></span><span class="t"> <span class="nam">success</span><span class="op">,</span> <span class="nam">_</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">layout_form</span><span class="op">(</span><span class="nam">element</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t720" href="#t720">720</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">success</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t721" href="#t721">721</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t722" href="#t722">722</a></span><span class="t"> <span class="com"># Future: elif isinstance(element, CodeBlock): use code_layouter</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t723" href="#t723">723</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_427cc3035faf7633___init___py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_427cc3035faf7633_ereader_layout_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,853 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/layout/ereader_layout.py: 83%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/layout/ereader_layout.py</b>:
<span class="pc_cov">83%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">279 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">241<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">38<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">36<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">18<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_427cc3035faf7633_document_layouter_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_427cc3035faf7633_ereader_manager_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">Enhanced ereader layout system with position tracking, font scaling, and multi-page support.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">This module provides the core infrastructure for building high-performance ereader applications</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">with features like:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="str">- Precise position tracking tied to abstract document structure</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="str">- Font scaling support</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="str">- Bidirectional page rendering (forward/backward)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="str">- Chapter navigation based on HTML headings</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="str">- Multi-process page buffering</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="str">- Sub-second page rendering performance</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t"><span class="key">from</span> <span class="nam">__future__</span> <span class="key">import</span> <span class="nam">annotations</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"><span class="key">from</span> <span class="nam">dataclasses</span> <span class="key">import</span> <span class="nam">dataclass</span><span class="op">,</span> <span class="nam">asdict</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">List</span><span class="op">,</span> <span class="nam">Dict</span><span class="op">,</span> <span class="nam">Tuple</span><span class="op">,</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">Any</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">block</span> <span class="key">import</span> <span class="nam">Block</span><span class="op">,</span> <span class="nam">Paragraph</span><span class="op">,</span> <span class="nam">Heading</span><span class="op">,</span> <span class="nam">HeadingLevel</span><span class="op">,</span> <span class="nam">Table</span><span class="op">,</span> <span class="nam">HList</span><span class="op">,</span> <span class="nam">Image</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">inline</span> <span class="key">import</span> <span class="nam">Word</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span><span class="op">.</span><span class="nam">page</span> <span class="key">import</span> <span class="nam">Page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span><span class="op">.</span><span class="nam">text</span> <span class="key">import</span> <span class="nam">Text</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">page_style</span> <span class="key">import</span> <span class="nam">PageStyle</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span> <span class="key">import</span> <span class="nam">Font</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">fonts</span> <span class="key">import</span> <span class="nam">BundledFont</span><span class="op">,</span> <span class="nam">get_bundled_font_path</span><span class="op">,</span> <span class="nam">FontWeight</span><span class="op">,</span> <span class="nam">FontStyle</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">layout</span><span class="op">.</span><span class="nam">document_layouter</span> <span class="key">import</span> <span class="nam">paragraph_layouter</span><span class="op">,</span> <span class="nam">image_layouter</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t"><span class="op">@</span><span class="nam">dataclass</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"><span class="key">class</span> <span class="nam">RenderingPosition</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"><span class="str"> Complete state for resuming rendering at any point in a document.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"><span class="str"> Position is tied to abstract document structure for stability across font changes.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"> <span class="nam">chapter_index</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">0</span> <span class="com"># Which chapter (based on headings)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"> <span class="nam">block_index</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">0</span> <span class="com"># Which block within chapter</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"> <span class="com"># Which word within block (for paragraphs)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"> <span class="nam">word_index</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t"> <span class="nam">table_row</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">0</span> <span class="com"># Which row for tables</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"> <span class="nam">table_col</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">0</span> <span class="com"># Which column for tables</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"> <span class="nam">list_item_index</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">0</span> <span class="com"># Which item for lists</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t"> <span class="nam">remaining_pretext</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span> <span class="com"># Hyphenated word continuation</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t"> <span class="nam">page_y_offset</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">0</span> <span class="com"># Vertical position on page</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"> <span class="key">def</span> <span class="nam">to_dict</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t"> <span class="str">"""Serialize position for saving to file/database"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"> <span class="key">return</span> <span class="nam">asdict</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"> <span class="op">@</span><span class="nam">classmethod</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t"> <span class="key">def</span> <span class="nam">from_dict</span><span class="op">(</span><span class="nam">cls</span><span class="op">,</span> <span class="nam">data</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="str">'RenderingPosition'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"> <span class="str">"""Deserialize position from saved state"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t"> <span class="key">return</span> <span class="nam">cls</span><span class="op">(</span><span class="op">**</span><span class="nam">data</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"> <span class="key">def</span> <span class="nam">copy</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="str">'RenderingPosition'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t"> <span class="str">"""Create a copy of this position"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"> <span class="key">return</span> <span class="nam">RenderingPosition</span><span class="op">(</span><span class="op">**</span><span class="nam">asdict</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t"> <span class="key">def</span> <span class="nam">__eq__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">other</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t"> <span class="str">"""Check if two positions are equal"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">other</span><span class="op">,</span> <span class="nam">RenderingPosition</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"> <span class="key">return</span> <span class="nam">asdict</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">==</span> <span class="nam">asdict</span><span class="op">(</span><span class="nam">other</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t"> <span class="key">def</span> <span class="nam">__hash__</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"> <span class="str">"""Make position hashable for use as dict key"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"> <span class="key">return</span> <span class="nam">hash</span><span class="op">(</span><span class="nam">tuple</span><span class="op">(</span><span class="nam">asdict</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">.</span><span class="nam">values</span><span class="op">(</span><span class="op">)</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"><span class="key">class</span> <span class="nam">ChapterInfo</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"> <span class="str">"""Information about a chapter/section in the document"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"> <span class="nam">title</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t"> <span class="nam">level</span><span class="op">:</span> <span class="nam">HeadingLevel</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"> <span class="nam">position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t"> <span class="nam">block_index</span><span class="op">:</span> <span class="nam">int</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">title</span> <span class="op">=</span> <span class="nam">title</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">level</span> <span class="op">=</span> <span class="nam">level</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">position</span> <span class="op">=</span> <span class="nam">position</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">=</span> <span class="nam">block_index</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t"><span class="key">class</span> <span class="nam">ChapterNavigator</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t"><span class="str"> Handles chapter/section navigation based on HTML heading structure (H1-H6).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t"><span class="str"> Builds a table of contents and provides navigation capabilities.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">blocks</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">Block</span><span class="op">]</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span> <span class="op">=</span> <span class="nam">blocks</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">chapters</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">ChapterInfo</span><span class="op">]</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_build_chapter_map</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t"> <span class="key">def</span> <span class="nam">_build_chapter_map</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t"> <span class="str">"""Scan blocks for headings and build chapter navigation map"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t"> <span class="nam">current_chapter_index</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t"> <span class="com"># Check if first block is a cover image and add it to TOC</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span> <span class="key">and</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">,</span> <span class="nam">Image</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t"> <span class="nam">cover_position</span> <span class="op">=</span> <span class="nam">RenderingPosition</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"> <span class="nam">chapter_index</span><span class="op">=</span><span class="num">0</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"> <span class="nam">block_index</span><span class="op">=</span><span class="num">0</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t"> <span class="nam">word_index</span><span class="op">=</span><span class="num">0</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t"> <span class="nam">table_row</span><span class="op">=</span><span class="num">0</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t"> <span class="nam">table_col</span><span class="op">=</span><span class="num">0</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t"> <span class="nam">list_item_index</span><span class="op">=</span><span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t"> <span class="nam">cover_info</span> <span class="op">=</span> <span class="nam">ChapterInfo</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"> <span class="nam">title</span><span class="op">=</span><span class="str">"Cover"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t"> <span class="nam">level</span><span class="op">=</span><span class="nam">HeadingLevel</span><span class="op">.</span><span class="nam">H1</span><span class="op">,</span> <span class="com"># Treat as top-level entry</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"> <span class="nam">position</span><span class="op">=</span><span class="nam">cover_position</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t"> <span class="nam">block_index</span><span class="op">=</span><span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">chapters</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">cover_info</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t"> <span class="key">for</span> <span class="nam">block_index</span><span class="op">,</span> <span class="nam">block</span> <span class="key">in</span> <span class="nam">enumerate</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="nam">Heading</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t"> <span class="com"># Create position for this heading</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t"> <span class="nam">position</span> <span class="op">=</span> <span class="nam">RenderingPosition</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t"> <span class="nam">chapter_index</span><span class="op">=</span><span class="nam">current_chapter_index</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"> <span class="nam">block_index</span><span class="op">=</span><span class="nam">block_index</span><span class="op">,</span> <span class="com"># Use actual block index</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t"> <span class="nam">word_index</span><span class="op">=</span><span class="num">0</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t"> <span class="nam">table_row</span><span class="op">=</span><span class="num">0</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t"> <span class="nam">table_col</span><span class="op">=</span><span class="num">0</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t"> <span class="nam">list_item_index</span><span class="op">=</span><span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t"> <span class="com"># Extract heading text</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t"> <span class="nam">heading_text</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_extract_heading_text</span><span class="op">(</span><span class="nam">block</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t"> <span class="nam">chapter_info</span> <span class="op">=</span> <span class="nam">ChapterInfo</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t"> <span class="nam">title</span><span class="op">=</span><span class="nam">heading_text</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t"> <span class="nam">level</span><span class="op">=</span><span class="nam">block</span><span class="op">.</span><span class="nam">level</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"> <span class="nam">position</span><span class="op">=</span><span class="nam">position</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t"> <span class="nam">block_index</span><span class="op">=</span><span class="nam">block_index</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">chapters</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">chapter_info</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t"> <span class="com"># Only increment chapter index for top-level headings (H1)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t"> <span class="key">if</span> <span class="nam">block</span><span class="op">.</span><span class="nam">level</span> <span class="op">==</span> <span class="nam">HeadingLevel</span><span class="op">.</span><span class="nam">H1</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"> <span class="nam">current_chapter_index</span> <span class="op">+=</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t"> <span class="key">def</span> <span class="nam">_extract_heading_text</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">heading</span><span class="op">:</span> <span class="nam">Heading</span><span class="op">)</span> <span class="op">-></span> <span class="nam">str</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"> <span class="str">"""Extract text content from a heading block"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"> <span class="nam">words</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t"> <span class="key">for</span> <span class="nam">position</span><span class="op">,</span> <span class="nam">word</span> <span class="key">in</span> <span class="nam">heading</span><span class="op">.</span><span class="nam">words_iter</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">word</span><span class="op">,</span> <span class="nam">Word</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">150&#x202F;&#x219B;&#x202F;149</span><span class="annotate long">line 150 didn't jump to line 149 because the condition on line 150 was always true</span></span></p>
<p class="run"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t"> <span class="nam">words</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">word</span><span class="op">.</span><span class="nam">text</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t"> <span class="key">return</span> <span class="str">" "</span><span class="op">.</span><span class="nam">join</span><span class="op">(</span><span class="nam">words</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_table_of_contents</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t"> <span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">Tuple</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">HeadingLevel</span><span class="op">,</span> <span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t"> <span class="str">"""Generate table of contents from heading structure"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t"> <span class="key">return</span> <span class="op">[</span><span class="op">(</span><span class="nam">chapter</span><span class="op">.</span><span class="nam">title</span><span class="op">,</span> <span class="nam">chapter</span><span class="op">.</span><span class="nam">level</span><span class="op">,</span> <span class="nam">chapter</span><span class="op">.</span><span class="nam">position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t"> <span class="key">for</span> <span class="nam">chapter</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">chapters</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_chapter_position</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">chapter_title</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t"> <span class="str">"""Get rendering position for a chapter by title"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t"> <span class="key">for</span> <span class="nam">chapter</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">chapters</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"> <span class="key">if</span> <span class="nam">chapter</span><span class="op">.</span><span class="nam">title</span><span class="op">.</span><span class="nam">lower</span><span class="op">(</span><span class="op">)</span> <span class="op">==</span> <span class="nam">chapter_title</span><span class="op">.</span><span class="nam">lower</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t"> <span class="key">return</span> <span class="nam">chapter</span><span class="op">.</span><span class="nam">position</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_current_chapter</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">ChapterInfo</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t"> <span class="str">"""Determine which chapter contains the current position"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">self</span><span class="op">.</span><span class="nam">chapters</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t"> <span class="com"># Find the chapter that contains this position</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t"> <span class="key">for</span> <span class="nam">i</span><span class="op">,</span> <span class="nam">chapter</span> <span class="key">in</span> <span class="nam">enumerate</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">chapters</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">173&#x202F;&#x219B;&#x202F;182</span><span class="annotate long">line 173 didn't jump to line 182 because the loop on line 173 didn't complete</span></span></p>
<p class="pln"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t"> <span class="com"># Check if this is the last chapter or if position is before next chapter</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t"> <span class="key">if</span> <span class="nam">i</span> <span class="op">==</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">chapters</span><span class="op">)</span> <span class="op">-</span> <span class="num">1</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t"> <span class="key">return</span> <span class="nam">chapter</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t"> <span class="nam">next_chapter</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">chapters</span><span class="op">[</span><span class="nam">i</span> <span class="op">+</span> <span class="num">1</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t"> <span class="key">if</span> <span class="nam">position</span><span class="op">.</span><span class="nam">chapter_index</span> <span class="op">&lt;</span> <span class="nam">next_chapter</span><span class="op">.</span><span class="nam">position</span><span class="op">.</span><span class="nam">chapter_index</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t"> <span class="key">return</span> <span class="nam">chapter</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">chapters</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">chapters</span> <span class="key">else</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t"><span class="key">class</span> <span class="nam">FontFamilyOverride</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t"><span class="str"> Manages font family preferences for ereader rendering.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t"><span class="str"> Allows dynamic font family switching without modifying source blocks.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">preferred_family</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">BundledFont</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t"><span class="str"> Initialize font family override.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t"><span class="str"> preferred_family: Preferred bundled font family (None = use original fonts)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">preferred_family</span> <span class="op">=</span> <span class="nam">preferred_family</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t"> <span class="key">def</span> <span class="nam">override_font</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">font</span><span class="op">:</span> <span class="nam">Font</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Font</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t"><span class="str"> Create a new font with the preferred family while preserving other attributes.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t"><span class="str"> font: Original font object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"><span class="str"> Font with overridden family, or original if no override is set</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">preferred_family</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t"> <span class="key">return</span> <span class="nam">font</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"> <span class="com"># Get the appropriate font path for the preferred family</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t"> <span class="com"># preserving the original font's weight and style</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t"> <span class="nam">new_font_path</span> <span class="op">=</span> <span class="nam">get_bundled_font_path</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t"> <span class="nam">family</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">preferred_family</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t"> <span class="nam">weight</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">weight</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t"> <span class="nam">style</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t"> <span class="com"># If we couldn't find a matching font, fall back to original</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"> <span class="key">if</span> <span class="nam">new_font_path</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t"> <span class="key">return</span> <span class="nam">font</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t"> <span class="com"># Create a new font with the overridden path</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t"> <span class="key">return</span> <span class="nam">Font</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t"> <span class="nam">font_path</span><span class="op">=</span><span class="nam">new_font_path</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t"> <span class="nam">font_size</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">font_size</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t"> <span class="nam">colour</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">colour</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t"> <span class="nam">weight</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">weight</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t"> <span class="nam">style</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t"> <span class="nam">decoration</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">decoration</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t"> <span class="nam">background</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">background</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t"> <span class="nam">language</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">language</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t"> <span class="nam">min_hyphenation_width</span><span class="op">=</span><span class="nam">font</span><span class="op">.</span><span class="nam">min_hyphenation_width</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t"><span class="key">class</span> <span class="nam">FontScaler</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t"><span class="str"> Handles font scaling operations for ereader font size adjustments.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t"><span class="str"> Applies scaling at layout/render time while preserving original font objects.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t"> <span class="op">@</span><span class="nam">staticmethod</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t"> <span class="key">def</span> <span class="nam">scale_font</span><span class="op">(</span><span class="nam">font</span><span class="op">:</span> <span class="nam">Font</span><span class="op">,</span> <span class="nam">scale_factor</span><span class="op">:</span> <span class="nam">float</span><span class="op">,</span> <span class="nam">family_override</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">FontFamilyOverride</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Font</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t"><span class="str"> Create a scaled version of a font for layout calculations.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t"><span class="str"> font: Original font object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t"><span class="str"> scale_factor: Scaling factor (1.0 = no change, 2.0 = double size, etc.)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t"><span class="str"> family_override: Optional font family override</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t"><span class="str"> New Font object with scaled size and optional family override</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t"> <span class="com"># Apply family override first if specified</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t"> <span class="nam">working_font</span> <span class="op">=</span> <span class="nam">font</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t"> <span class="key">if</span> <span class="nam">family_override</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">260&#x202F;&#x219B;&#x202F;261</span><span class="annotate long">line 260 didn't jump to line 261 because the condition on line 260 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t"> <span class="nam">working_font</span> <span class="op">=</span> <span class="nam">family_override</span><span class="op">.</span><span class="nam">override_font</span><span class="op">(</span><span class="nam">font</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t"> <span class="com"># Then apply scaling</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t"> <span class="key">if</span> <span class="nam">scale_factor</span> <span class="op">==</span> <span class="num">1.0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t"> <span class="key">return</span> <span class="nam">working_font</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t"> <span class="nam">scaled_size</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="num">1</span><span class="op">,</span> <span class="nam">int</span><span class="op">(</span><span class="nam">working_font</span><span class="op">.</span><span class="nam">font_size</span> <span class="op">*</span> <span class="nam">scale_factor</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t"> <span class="key">return</span> <span class="nam">Font</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t"> <span class="nam">font_path</span><span class="op">=</span><span class="nam">working_font</span><span class="op">.</span><span class="nam">_font_path</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t"> <span class="nam">font_size</span><span class="op">=</span><span class="nam">scaled_size</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t"> <span class="nam">colour</span><span class="op">=</span><span class="nam">working_font</span><span class="op">.</span><span class="nam">colour</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t"> <span class="nam">weight</span><span class="op">=</span><span class="nam">working_font</span><span class="op">.</span><span class="nam">weight</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t"> <span class="nam">style</span><span class="op">=</span><span class="nam">working_font</span><span class="op">.</span><span class="nam">style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t"> <span class="nam">decoration</span><span class="op">=</span><span class="nam">working_font</span><span class="op">.</span><span class="nam">decoration</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t"> <span class="nam">background</span><span class="op">=</span><span class="nam">working_font</span><span class="op">.</span><span class="nam">background</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t"> <span class="nam">language</span><span class="op">=</span><span class="nam">working_font</span><span class="op">.</span><span class="nam">language</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t"> <span class="nam">min_hyphenation_width</span><span class="op">=</span><span class="nam">working_font</span><span class="op">.</span><span class="nam">min_hyphenation_width</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t279" href="#t279">279</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t280" href="#t280">280</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t281" href="#t281">281</a></span><span class="t"> <span class="op">@</span><span class="nam">staticmethod</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t282" href="#t282">282</a></span><span class="t"> <span class="key">def</span> <span class="nam">scale_word_spacing</span><span class="op">(</span><span class="nam">spacing</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t283" href="#t283">283</a></span><span class="t"> <span class="nam">scale_factor</span><span class="op">:</span> <span class="nam">float</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t284" href="#t284">284</a></span><span class="t"> <span class="str">"""Scale word spacing constraints proportionally"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t285" href="#t285">285</a></span><span class="t"> <span class="key">if</span> <span class="nam">scale_factor</span> <span class="op">==</span> <span class="num">1.0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t286" href="#t286">286</a></span><span class="t"> <span class="key">return</span> <span class="nam">spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t287" href="#t287">287</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t288" href="#t288">288</a></span><span class="t"> <span class="nam">min_spacing</span><span class="op">,</span> <span class="nam">max_spacing</span> <span class="op">=</span> <span class="nam">spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t289" href="#t289">289</a></span><span class="t"> <span class="key">return</span> <span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t290" href="#t290">290</a></span><span class="t"> <span class="nam">max</span><span class="op">(</span><span class="num">1</span><span class="op">,</span> <span class="nam">int</span><span class="op">(</span><span class="nam">min_spacing</span> <span class="op">*</span> <span class="nam">scale_factor</span><span class="op">)</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t291" href="#t291">291</a></span><span class="t"> <span class="nam">max</span><span class="op">(</span><span class="num">2</span><span class="op">,</span> <span class="nam">int</span><span class="op">(</span><span class="nam">max_spacing</span> <span class="op">*</span> <span class="nam">scale_factor</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t292" href="#t292">292</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t293" href="#t293">293</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t294" href="#t294">294</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t295" href="#t295">295</a></span><span class="t"><span class="key">class</span> <span class="nam">BidirectionalLayouter</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t296" href="#t296">296</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t297" href="#t297">297</a></span><span class="t"><span class="str"> Core layout engine supporting both forward and backward page rendering.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t298" href="#t298">298</a></span><span class="t"><span class="str"> Handles font scaling and maintains position state.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t299" href="#t299">299</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t300" href="#t300">300</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t301" href="#t301">301</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t302" href="#t302">302</a></span><span class="t"> <span class="nam">blocks</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">Block</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t303" href="#t303">303</a></span><span class="t"> <span class="nam">page_style</span><span class="op">:</span> <span class="nam">PageStyle</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t304" href="#t304">304</a></span><span class="t"> <span class="nam">page_size</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t305" href="#t305">305</a></span><span class="t"> <span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="op">(</span><span class="num">800</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t306" href="#t306">306</a></span><span class="t"> <span class="num">600</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t307" href="#t307">307</a></span><span class="t"> <span class="nam">alignment_override</span><span class="op">=</span><span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t308" href="#t308">308</a></span><span class="t"> <span class="nam">font_family_override</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">FontFamilyOverride</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t309" href="#t309">309</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span> <span class="op">=</span> <span class="nam">blocks</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t310" href="#t310">310</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span> <span class="op">=</span> <span class="nam">page_style</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t311" href="#t311">311</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">page_size</span> <span class="op">=</span> <span class="nam">page_size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t312" href="#t312">312</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">chapter_navigator</span> <span class="op">=</span> <span class="nam">ChapterNavigator</span><span class="op">(</span><span class="nam">blocks</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t313" href="#t313">313</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">alignment_override</span> <span class="op">=</span> <span class="nam">alignment_override</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t314" href="#t314">314</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">font_family_override</span> <span class="op">=</span> <span class="nam">font_family_override</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t315" href="#t315">315</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t316" href="#t316">316</a></span><span class="t"> <span class="key">def</span> <span class="nam">render_page_forward</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t317" href="#t317">317</a></span><span class="t"> <span class="nam">font_scale</span><span class="op">:</span> <span class="nam">float</span> <span class="op">=</span> <span class="num">1.0</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">Page</span><span class="op">,</span> <span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t318" href="#t318">318</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t319" href="#t319">319</a></span><span class="t"><span class="str"> Render a page starting from the given position, moving forward through the document.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t320" href="#t320">320</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t321" href="#t321">321</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t322" href="#t322">322</a></span><span class="t"><span class="str"> position: Starting position in document</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t323" href="#t323">323</a></span><span class="t"><span class="str"> font_scale: Font scaling factor</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t324" href="#t324">324</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t325" href="#t325">325</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t326" href="#t326">326</a></span><span class="t"><span class="str"> Tuple of (rendered_page, next_position)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t327" href="#t327">327</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t328" href="#t328">328</a></span><span class="t"> <span class="nam">page</span> <span class="op">=</span> <span class="nam">Page</span><span class="op">(</span><span class="nam">size</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">page_size</span><span class="op">,</span> <span class="nam">style</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t329" href="#t329">329</a></span><span class="t"> <span class="nam">current_pos</span> <span class="op">=</span> <span class="nam">position</span><span class="op">.</span><span class="nam">copy</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t330" href="#t330">330</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t331" href="#t331">331</a></span><span class="t"> <span class="com"># Start laying out blocks from the current position</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t332" href="#t332">332</a></span><span class="t"> <span class="key">while</span> <span class="nam">current_pos</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">&lt;</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">)</span> <span class="key">and</span> <span class="nam">page</span><span class="op">.</span><span class="nam">free_space</span><span class="op">(</span><span class="op">)</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">></span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t333" href="#t333">333</a></span><span class="t"> <span class="com"># Additional bounds check to prevent IndexError</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t334" href="#t334">334</a></span><span class="t"> <span class="key">if</span> <span class="nam">current_pos</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">>=</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">334&#x202F;&#x219B;&#x202F;335</span><span class="annotate long">line 334 didn't jump to line 335 because the condition on line 334 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t335" href="#t335">335</a></span><span class="t"> <span class="key">break</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t336" href="#t336">336</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t337" href="#t337">337</a></span><span class="t"> <span class="nam">block</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">[</span><span class="nam">current_pos</span><span class="op">.</span><span class="nam">block_index</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t338" href="#t338">338</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t339" href="#t339">339</a></span><span class="t"> <span class="com"># Apply font scaling to the block</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t340" href="#t340">340</a></span><span class="t"> <span class="nam">scaled_block</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_scale_block_fonts</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t341" href="#t341">341</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t342" href="#t342">342</a></span><span class="t"> <span class="com"># Try to fit the block on the current page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t343" href="#t343">343</a></span><span class="t"> <span class="nam">success</span><span class="op">,</span> <span class="nam">new_pos</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_layout_block_on_page</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t344" href="#t344">344</a></span><span class="t"> <span class="nam">scaled_block</span><span class="op">,</span> <span class="nam">page</span><span class="op">,</span> <span class="nam">current_pos</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t345" href="#t345">345</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t346" href="#t346">346</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">success</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t347" href="#t347">347</a></span><span class="t"> <span class="com"># Block doesn't fit, we're done with this page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t348" href="#t348">348</a></span><span class="t"> <span class="key">break</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t349" href="#t349">349</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t350" href="#t350">350</a></span><span class="t"> <span class="com"># Add inter-block spacing after successfully laying out a block</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t351" href="#t351">351</a></span><span class="t"> <span class="com"># Only add if we're not at the end of the document and there's space</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t352" href="#t352">352</a></span><span class="t"> <span class="key">if</span> <span class="nam">new_pos</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">&lt;</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t353" href="#t353">353</a></span><span class="t"> <span class="nam">page</span><span class="op">.</span><span class="nam">_current_y_offset</span> <span class="op">+=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span><span class="op">.</span><span class="nam">inter_block_spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t354" href="#t354">354</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t355" href="#t355">355</a></span><span class="t"> <span class="com"># Ensure new position doesn't go beyond bounds</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t356" href="#t356">356</a></span><span class="t"> <span class="key">if</span> <span class="nam">new_pos</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">>=</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t357" href="#t357">357</a></span><span class="t"> <span class="com"># We've reached the end of the document</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t358" href="#t358">358</a></span><span class="t"> <span class="nam">current_pos</span> <span class="op">=</span> <span class="nam">new_pos</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t359" href="#t359">359</a></span><span class="t"> <span class="key">break</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t360" href="#t360">360</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t361" href="#t361">361</a></span><span class="t"> <span class="nam">current_pos</span> <span class="op">=</span> <span class="nam">new_pos</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t362" href="#t362">362</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t363" href="#t363">363</a></span><span class="t"> <span class="key">return</span> <span class="nam">page</span><span class="op">,</span> <span class="nam">current_pos</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t364" href="#t364">364</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t365" href="#t365">365</a></span><span class="t"> <span class="key">def</span> <span class="nam">render_page_backward</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t366" href="#t366">366</a></span><span class="t"> <span class="nam">end_position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t367" href="#t367">367</a></span><span class="t"> <span class="nam">font_scale</span><span class="op">:</span> <span class="nam">float</span> <span class="op">=</span> <span class="num">1.0</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">Page</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t368" href="#t368">368</a></span><span class="t"> <span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t369" href="#t369">369</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t370" href="#t370">370</a></span><span class="t"><span class="str"> Render a page that ends at the given position, filling backward.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t371" href="#t371">371</a></span><span class="t"><span class="str"> Critical for "previous page" navigation.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t372" href="#t372">372</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t373" href="#t373">373</a></span><span class="t"><span class="str"> Uses iterative refinement to find the correct start position that</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t374" href="#t374">374</a></span><span class="t"><span class="str"> results in a page ending at (or very close to) the target position.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t375" href="#t375">375</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t376" href="#t376">376</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t377" href="#t377">377</a></span><span class="t"><span class="str"> end_position: Position where page should end</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t378" href="#t378">378</a></span><span class="t"><span class="str"> font_scale: Font scaling factor</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t379" href="#t379">379</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t380" href="#t380">380</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t381" href="#t381">381</a></span><span class="t"><span class="str"> Tuple of (rendered_page, start_position)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t382" href="#t382">382</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t383" href="#t383">383</a></span><span class="t"> <span class="com"># Handle edge case: already at beginning</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t384" href="#t384">384</a></span><span class="t"> <span class="key">if</span> <span class="nam">end_position</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">==</span> <span class="num">0</span> <span class="key">and</span> <span class="nam">end_position</span><span class="op">.</span><span class="nam">word_index</span> <span class="op">==</span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">384&#x202F;&#x219B;&#x202F;385</span><span class="annotate long">line 384 didn't jump to line 385 because the condition on line 384 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t385" href="#t385">385</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">render_page_forward</span><span class="op">(</span><span class="nam">end_position</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t386" href="#t386">386</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t387" href="#t387">387</a></span><span class="t"> <span class="com"># Start with initial estimate</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t388" href="#t388">388</a></span><span class="t"> <span class="nam">estimated_start</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_estimate_page_start</span><span class="op">(</span><span class="nam">end_position</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t389" href="#t389">389</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t390" href="#t390">390</a></span><span class="t"> <span class="com"># Iterative refinement: keep adjusting until we converge or hit max iterations</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t391" href="#t391">391</a></span><span class="t"> <span class="nam">max_iterations</span> <span class="op">=</span> <span class="num">10</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t392" href="#t392">392</a></span><span class="t"> <span class="nam">best_page</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t393" href="#t393">393</a></span><span class="t"> <span class="nam">best_start</span> <span class="op">=</span> <span class="nam">estimated_start</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t394" href="#t394">394</a></span><span class="t"> <span class="nam">best_distance</span> <span class="op">=</span> <span class="nam">float</span><span class="op">(</span><span class="str">'inf'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t395" href="#t395">395</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t396" href="#t396">396</a></span><span class="t"> <span class="key">for</span> <span class="nam">iteration</span> <span class="key">in</span> <span class="nam">range</span><span class="op">(</span><span class="nam">max_iterations</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t397" href="#t397">397</a></span><span class="t"> <span class="com"># Render forward from current estimate</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t398" href="#t398">398</a></span><span class="t"> <span class="nam">page</span><span class="op">,</span> <span class="nam">actual_end</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">render_page_forward</span><span class="op">(</span><span class="nam">estimated_start</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t399" href="#t399">399</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t400" href="#t400">400</a></span><span class="t"> <span class="com"># Calculate how far we are from target</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t401" href="#t401">401</a></span><span class="t"> <span class="nam">comparison</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_position_compare</span><span class="op">(</span><span class="nam">actual_end</span><span class="op">,</span> <span class="nam">end_position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t402" href="#t402">402</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t403" href="#t403">403</a></span><span class="t"> <span class="com"># Perfect match or close enough (within same block)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t404" href="#t404">404</a></span><span class="t"> <span class="com"># BUT: ensure we actually moved backward (estimated_start &lt; end_position)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t405" href="#t405">405</a></span><span class="t"> <span class="key">if</span> <span class="nam">comparison</span> <span class="op">==</span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t406" href="#t406">406</a></span><span class="t"> <span class="com"># Check if we actually found a valid previous page</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t407" href="#t407">407</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_position_compare</span><span class="op">(</span><span class="nam">estimated_start</span><span class="op">,</span> <span class="nam">end_position</span><span class="op">)</span> <span class="op">&lt;</span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">407&#x202F;&#x219B;&#x202F;411</span><span class="annotate long">line 407 didn't jump to line 411 because the condition on line 407 was always true</span></span></p>
<p class="run"><span class="n"><a id="t408" href="#t408">408</a></span><span class="t"> <span class="key">return</span> <span class="nam">page</span><span class="op">,</span> <span class="nam">estimated_start</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t409" href="#t409">409</a></span><span class="t"> <span class="com"># If estimated_start >= end_position, we haven't moved backward</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t410" href="#t410">410</a></span><span class="t"> <span class="com"># Continue iterating to find a better position</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t411" href="#t411">411</a></span><span class="t"> <span class="key">elif</span> <span class="nam">iteration</span> <span class="op">==</span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t412" href="#t412">412</a></span><span class="t"> <span class="com"># On first iteration, if we can't find a previous position,</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t413" href="#t413">413</a></span><span class="t"> <span class="com"># we're likely at or near the beginning</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t414" href="#t414">414</a></span><span class="t"> <span class="key">break</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t415" href="#t415">415</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t416" href="#t416">416</a></span><span class="t"> <span class="com"># Track best result so far</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t417" href="#t417">417</a></span><span class="t"> <span class="nam">distance</span> <span class="op">=</span> <span class="nam">abs</span><span class="op">(</span><span class="nam">actual_end</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">-</span> <span class="nam">end_position</span><span class="op">.</span><span class="nam">block_index</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t418" href="#t418">418</a></span><span class="t"> <span class="key">if</span> <span class="nam">distance</span> <span class="op">&lt;</span> <span class="nam">best_distance</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t419" href="#t419">419</a></span><span class="t"> <span class="nam">best_distance</span> <span class="op">=</span> <span class="nam">distance</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t420" href="#t420">420</a></span><span class="t"> <span class="nam">best_page</span> <span class="op">=</span> <span class="nam">page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t421" href="#t421">421</a></span><span class="t"> <span class="nam">best_start</span> <span class="op">=</span> <span class="nam">estimated_start</span><span class="op">.</span><span class="nam">copy</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t422" href="#t422">422</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t423" href="#t423">423</a></span><span class="t"> <span class="com"># Adjust estimate for next iteration</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t424" href="#t424">424</a></span><span class="t"> <span class="nam">estimated_start</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_adjust_start_estimate</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t425" href="#t425">425</a></span><span class="t"> <span class="nam">estimated_start</span><span class="op">,</span> <span class="nam">end_position</span><span class="op">,</span> <span class="nam">actual_end</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t426" href="#t426">426</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t427" href="#t427">427</a></span><span class="t"> <span class="com"># Safety: don't go before document start</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t428" href="#t428">428</a></span><span class="t"> <span class="key">if</span> <span class="nam">estimated_start</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">&lt;</span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">428&#x202F;&#x219B;&#x202F;429</span><span class="annotate long">line 428 didn't jump to line 429 because the condition on line 428 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t429" href="#t429">429</a></span><span class="t"> <span class="nam">estimated_start</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t430" href="#t430">430</a></span><span class="t"> <span class="nam">estimated_start</span><span class="op">.</span><span class="nam">word_index</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t431" href="#t431">431</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t432" href="#t432">432</a></span><span class="t"> <span class="com"># If we exhausted iterations, return best result found</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t433" href="#t433">433</a></span><span class="t"> <span class="com"># BUT: ensure we didn't return the same position (no backward progress)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t434" href="#t434">434</a></span><span class="t"> <span class="nam">final_page</span> <span class="op">=</span> <span class="nam">best_page</span> <span class="key">if</span> <span class="nam">best_page</span> <span class="key">else</span> <span class="nam">page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t435" href="#t435">435</a></span><span class="t"> <span class="nam">final_start</span> <span class="op">=</span> <span class="nam">best_start</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t436" href="#t436">436</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t437" href="#t437">437</a></span><span class="t"> <span class="com"># Safety check: if final_start >= end_position, we failed to move backward</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t438" href="#t438">438</a></span><span class="t"> <span class="com"># This can happen at the beginning of the document or when estimation failed</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t439" href="#t439">439</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_position_compare</span><span class="op">(</span><span class="nam">final_start</span><span class="op">,</span> <span class="nam">end_position</span><span class="op">)</span> <span class="op">>=</span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">439&#x202F;&#x219B;&#x202F;441</span><span class="annotate long">line 439 didn't jump to line 441 because the condition on line 439 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t440" href="#t440">440</a></span><span class="t"> <span class="com"># Can't go further back - check if we're at the absolute beginning</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t441" href="#t441">441</a></span><span class="t"> <span class="key">if</span> <span class="nam">end_position</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">==</span> <span class="num">0</span> <span class="key">and</span> <span class="nam">end_position</span><span class="op">.</span><span class="nam">word_index</span> <span class="op">==</span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t442" href="#t442">442</a></span><span class="t"> <span class="com"># Already at beginning, return as-is</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t443" href="#t443">443</a></span><span class="t"> <span class="key">return</span> <span class="nam">final_page</span><span class="op">,</span> <span class="nam">final_start</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t444" href="#t444">444</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t445" href="#t445">445</a></span><span class="t"> <span class="com"># Fallback strategy: try a more aggressive backward jump</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t446" href="#t446">446</a></span><span class="t"> <span class="com"># Start from several blocks before the current position</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t447" href="#t447">447</a></span><span class="t"> <span class="nam">blocks_to_jump</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="num">1</span><span class="op">,</span> <span class="nam">min</span><span class="op">(</span><span class="num">5</span><span class="op">,</span> <span class="nam">end_position</span><span class="op">.</span><span class="nam">block_index</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t448" href="#t448">448</a></span><span class="t"> <span class="nam">fallback_pos</span> <span class="op">=</span> <span class="nam">RenderingPosition</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t449" href="#t449">449</a></span><span class="t"> <span class="nam">chapter_index</span><span class="op">=</span><span class="nam">end_position</span><span class="op">.</span><span class="nam">chapter_index</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t450" href="#t450">450</a></span><span class="t"> <span class="nam">block_index</span><span class="op">=</span><span class="nam">max</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="nam">end_position</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">-</span> <span class="nam">blocks_to_jump</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t451" href="#t451">451</a></span><span class="t"> <span class="nam">word_index</span><span class="op">=</span><span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t452" href="#t452">452</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t453" href="#t453">453</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t454" href="#t454">454</a></span><span class="t"> <span class="com"># Render forward from the fallback position</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t455" href="#t455">455</a></span><span class="t"> <span class="nam">fallback_page</span><span class="op">,</span> <span class="nam">fallback_end</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">render_page_forward</span><span class="op">(</span><span class="nam">fallback_pos</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t456" href="#t456">456</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t457" href="#t457">457</a></span><span class="t"> <span class="com"># Verify the fallback actually moved us backward</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t458" href="#t458">458</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_position_compare</span><span class="op">(</span><span class="nam">fallback_pos</span><span class="op">,</span> <span class="nam">end_position</span><span class="op">)</span> <span class="op">&lt;</span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t459" href="#t459">459</a></span><span class="t"> <span class="key">return</span> <span class="nam">fallback_page</span><span class="op">,</span> <span class="nam">fallback_pos</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t460" href="#t460">460</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t461" href="#t461">461</a></span><span class="t"> <span class="com"># If even the fallback didn't work, we're likely at the beginning</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t462" href="#t462">462</a></span><span class="t"> <span class="com"># Return a page starting from the beginning</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t463" href="#t463">463</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">render_page_forward</span><span class="op">(</span><span class="nam">RenderingPosition</span><span class="op">(</span><span class="op">)</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t464" href="#t464">464</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t465" href="#t465">465</a></span><span class="t"> <span class="key">return</span> <span class="nam">final_page</span><span class="op">,</span> <span class="nam">final_start</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t466" href="#t466">466</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t467" href="#t467">467</a></span><span class="t"> <span class="key">def</span> <span class="nam">_scale_block_fonts</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">block</span><span class="op">:</span> <span class="nam">Block</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">:</span> <span class="nam">float</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Block</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t468" href="#t468">468</a></span><span class="t"> <span class="str">"""Apply font scaling and font family override to all fonts in a block"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t469" href="#t469">469</a></span><span class="t"> <span class="com"># Check if we need to do any transformation</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t470" href="#t470">470</a></span><span class="t"> <span class="key">if</span> <span class="nam">font_scale</span> <span class="op">==</span> <span class="num">1.0</span> <span class="key">and</span> <span class="nam">self</span><span class="op">.</span><span class="nam">font_family_override</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t471" href="#t471">471</a></span><span class="t"> <span class="key">return</span> <span class="nam">block</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t472" href="#t472">472</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t473" href="#t473">473</a></span><span class="t"> <span class="com"># This is a simplified implementation</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t474" href="#t474">474</a></span><span class="t"> <span class="com"># In practice, we'd need to handle each block type appropriately</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t475" href="#t475">475</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="op">(</span><span class="nam">Paragraph</span><span class="op">,</span> <span class="nam">Heading</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">475&#x202F;&#x219B;&#x202F;491</span><span class="annotate long">line 475 didn't jump to line 491 because the condition on line 475 was always true</span></span></p>
<p class="run"><span class="n"><a id="t476" href="#t476">476</a></span><span class="t"> <span class="nam">scaled_block_style</span> <span class="op">=</span> <span class="nam">FontScaler</span><span class="op">.</span><span class="nam">scale_font</span><span class="op">(</span><span class="nam">block</span><span class="op">.</span><span class="nam">style</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">font_family_override</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t477" href="#t477">477</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="nam">Heading</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t478" href="#t478">478</a></span><span class="t"> <span class="nam">scaled_block</span> <span class="op">=</span> <span class="nam">Heading</span><span class="op">(</span><span class="nam">block</span><span class="op">.</span><span class="nam">level</span><span class="op">,</span> <span class="nam">scaled_block_style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t479" href="#t479">479</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t480" href="#t480">480</a></span><span class="t"> <span class="nam">scaled_block</span> <span class="op">=</span> <span class="nam">Paragraph</span><span class="op">(</span><span class="nam">scaled_block_style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t481" href="#t481">481</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t482" href="#t482">482</a></span><span class="t"> <span class="com"># words_iter() returns tuples of (position, word)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t483" href="#t483">483</a></span><span class="t"> <span class="key">for</span> <span class="nam">position</span><span class="op">,</span> <span class="nam">word</span> <span class="key">in</span> <span class="nam">block</span><span class="op">.</span><span class="nam">words_iter</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t484" href="#t484">484</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">word</span><span class="op">,</span> <span class="nam">Word</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">484&#x202F;&#x219B;&#x202F;483</span><span class="annotate long">line 484 didn't jump to line 483 because the condition on line 484 was always true</span></span></p>
<p class="run"><span class="n"><a id="t485" href="#t485">485</a></span><span class="t"> <span class="nam">scaled_word</span> <span class="op">=</span> <span class="nam">Word</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t486" href="#t486">486</a></span><span class="t"> <span class="nam">word</span><span class="op">.</span><span class="nam">text</span><span class="op">,</span> <span class="nam">FontScaler</span><span class="op">.</span><span class="nam">scale_font</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t487" href="#t487">487</a></span><span class="t"> <span class="nam">word</span><span class="op">.</span><span class="nam">style</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">font_family_override</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t488" href="#t488">488</a></span><span class="t"> <span class="nam">scaled_block</span><span class="op">.</span><span class="nam">add_word</span><span class="op">(</span><span class="nam">scaled_word</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t489" href="#t489">489</a></span><span class="t"> <span class="key">return</span> <span class="nam">scaled_block</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t490" href="#t490">490</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t491" href="#t491">491</a></span><span class="t"> <span class="key">return</span> <span class="nam">block</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t492" href="#t492">492</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t493" href="#t493">493</a></span><span class="t"> <span class="key">def</span> <span class="nam">_layout_block_on_page</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t494" href="#t494">494</a></span><span class="t"> <span class="nam">block</span><span class="op">:</span> <span class="nam">Block</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t495" href="#t495">495</a></span><span class="t"> <span class="nam">page</span><span class="op">:</span> <span class="nam">Page</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t496" href="#t496">496</a></span><span class="t"> <span class="nam">position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t497" href="#t497">497</a></span><span class="t"> <span class="nam">font_scale</span><span class="op">:</span> <span class="nam">float</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">bool</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t498" href="#t498">498</a></span><span class="t"> <span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t499" href="#t499">499</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t500" href="#t500">500</a></span><span class="t"><span class="str"> Try to layout a block on the page starting from the given position.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t501" href="#t501">501</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t502" href="#t502">502</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t503" href="#t503">503</a></span><span class="t"><span class="str"> Tuple of (success, new_position)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t504" href="#t504">504</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t505" href="#t505">505</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="nam">Paragraph</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t506" href="#t506">506</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_layout_paragraph_on_page</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="nam">page</span><span class="op">,</span> <span class="nam">position</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t507" href="#t507">507</a></span><span class="t"> <span class="key">elif</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="nam">Heading</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">507&#x202F;&#x219B;&#x202F;508</span><span class="annotate long">line 507 didn't jump to line 508 because the condition on line 507 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t508" href="#t508">508</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_layout_heading_on_page</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="nam">page</span><span class="op">,</span> <span class="nam">position</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t509" href="#t509">509</a></span><span class="t"> <span class="key">elif</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="nam">Table</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">509&#x202F;&#x219B;&#x202F;510</span><span class="annotate long">line 509 didn't jump to line 510 because the condition on line 509 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t510" href="#t510">510</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_layout_table_on_page</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="nam">page</span><span class="op">,</span> <span class="nam">position</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t511" href="#t511">511</a></span><span class="t"> <span class="key">elif</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="nam">HList</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">511&#x202F;&#x219B;&#x202F;512</span><span class="annotate long">line 511 didn't jump to line 512 because the condition on line 511 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t512" href="#t512">512</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_layout_list_on_page</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="nam">page</span><span class="op">,</span> <span class="nam">position</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t513" href="#t513">513</a></span><span class="t"> <span class="key">elif</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="nam">Image</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t514" href="#t514">514</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_layout_image_on_page</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="nam">page</span><span class="op">,</span> <span class="nam">position</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t515" href="#t515">515</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t516" href="#t516">516</a></span><span class="t"> <span class="com"># Skip unknown block types</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t517" href="#t517">517</a></span><span class="t"> <span class="nam">new_pos</span> <span class="op">=</span> <span class="nam">position</span><span class="op">.</span><span class="nam">copy</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t518" href="#t518">518</a></span><span class="t"> <span class="nam">new_pos</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">+=</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t519" href="#t519">519</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span><span class="op">,</span> <span class="nam">new_pos</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t520" href="#t520">520</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t521" href="#t521">521</a></span><span class="t"> <span class="key">def</span> <span class="nam">_layout_paragraph_on_page</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t522" href="#t522">522</a></span><span class="t"> <span class="nam">paragraph</span><span class="op">:</span> <span class="nam">Paragraph</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t523" href="#t523">523</a></span><span class="t"> <span class="nam">page</span><span class="op">:</span> <span class="nam">Page</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t524" href="#t524">524</a></span><span class="t"> <span class="nam">position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t525" href="#t525">525</a></span><span class="t"> <span class="nam">font_scale</span><span class="op">:</span> <span class="nam">float</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">bool</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t526" href="#t526">526</a></span><span class="t"> <span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t527" href="#t527">527</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t528" href="#t528">528</a></span><span class="t"><span class="str"> Layout a paragraph on the page using the core paragraph_layouter.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t529" href="#t529">529</a></span><span class="t"><span class="str"> Integrates font scaling and position tracking with the proven layout logic.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t530" href="#t530">530</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t531" href="#t531">531</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t532" href="#t532">532</a></span><span class="t"><span class="str"> paragraph: The paragraph to layout (already scaled if font_scale != 1.0)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t533" href="#t533">533</a></span><span class="t"><span class="str"> page: The page to layout on</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t534" href="#t534">534</a></span><span class="t"><span class="str"> position: Current rendering position</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t535" href="#t535">535</a></span><span class="t"><span class="str"> font_scale: Font scaling factor (used for context, paragraph should already be scaled)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t536" href="#t536">536</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t537" href="#t537">537</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t538" href="#t538">538</a></span><span class="t"><span class="str"> Tuple of (success, new_position)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t539" href="#t539">539</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t540" href="#t540">540</a></span><span class="t"> <span class="com"># Convert remaining_pretext from string to Text object if needed</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t541" href="#t541">541</a></span><span class="t"> <span class="nam">pretext_obj</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t542" href="#t542">542</a></span><span class="t"> <span class="key">if</span> <span class="nam">position</span><span class="op">.</span><span class="nam">remaining_pretext</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t543" href="#t543">543</a></span><span class="t"> <span class="com"># Create a Text object from the pretext string</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t544" href="#t544">544</a></span><span class="t"> <span class="nam">pretext_obj</span> <span class="op">=</span> <span class="nam">Text</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t545" href="#t545">545</a></span><span class="t"> <span class="nam">position</span><span class="op">.</span><span class="nam">remaining_pretext</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t546" href="#t546">546</a></span><span class="t"> <span class="nam">paragraph</span><span class="op">.</span><span class="nam">style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t547" href="#t547">547</a></span><span class="t"> <span class="nam">page</span><span class="op">.</span><span class="nam">draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t548" href="#t548">548</a></span><span class="t"> <span class="nam">line</span><span class="op">=</span><span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t549" href="#t549">549</a></span><span class="t"> <span class="nam">source</span><span class="op">=</span><span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t550" href="#t550">550</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t551" href="#t551">551</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t552" href="#t552">552</a></span><span class="t"> <span class="com"># Call the core paragraph layouter with alignment override if set</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t553" href="#t553">553</a></span><span class="t"> <span class="nam">success</span><span class="op">,</span> <span class="nam">failed_word_index</span><span class="op">,</span> <span class="nam">remaining_pretext</span> <span class="op">=</span> <span class="nam">paragraph_layouter</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t554" href="#t554">554</a></span><span class="t"> <span class="nam">paragraph</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t555" href="#t555">555</a></span><span class="t"> <span class="nam">page</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t556" href="#t556">556</a></span><span class="t"> <span class="nam">start_word</span><span class="op">=</span><span class="nam">position</span><span class="op">.</span><span class="nam">word_index</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t557" href="#t557">557</a></span><span class="t"> <span class="nam">pretext</span><span class="op">=</span><span class="nam">pretext_obj</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t558" href="#t558">558</a></span><span class="t"> <span class="nam">alignment_override</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">alignment_override</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t559" href="#t559">559</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t560" href="#t560">560</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t561" href="#t561">561</a></span><span class="t"> <span class="com"># Create new position based on the result</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t562" href="#t562">562</a></span><span class="t"> <span class="nam">new_pos</span> <span class="op">=</span> <span class="nam">position</span><span class="op">.</span><span class="nam">copy</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t563" href="#t563">563</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t564" href="#t564">564</a></span><span class="t"> <span class="key">if</span> <span class="nam">success</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t565" href="#t565">565</a></span><span class="t"> <span class="com"># Paragraph was fully laid out, move to next block</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t566" href="#t566">566</a></span><span class="t"> <span class="nam">new_pos</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">+=</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t567" href="#t567">567</a></span><span class="t"> <span class="nam">new_pos</span><span class="op">.</span><span class="nam">word_index</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t568" href="#t568">568</a></span><span class="t"> <span class="nam">new_pos</span><span class="op">.</span><span class="nam">remaining_pretext</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t569" href="#t569">569</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span><span class="op">,</span> <span class="nam">new_pos</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t570" href="#t570">570</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t571" href="#t571">571</a></span><span class="t"> <span class="com"># Paragraph was not fully laid out</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t572" href="#t572">572</a></span><span class="t"> <span class="key">if</span> <span class="nam">failed_word_index</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">572&#x202F;&#x219B;&#x202F;586</span><span class="annotate long">line 572 didn't jump to line 586 because the condition on line 572 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t573" href="#t573">573</a></span><span class="t"> <span class="com"># Update position to the word that didn't fit</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t574" href="#t574">574</a></span><span class="t"> <span class="nam">new_pos</span><span class="op">.</span><span class="nam">word_index</span> <span class="op">=</span> <span class="nam">failed_word_index</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t575" href="#t575">575</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t576" href="#t576">576</a></span><span class="t"> <span class="com"># Convert Text object back to string if there's remaining pretext</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t577" href="#t577">577</a></span><span class="t"> <span class="key">if</span> <span class="nam">remaining_pretext</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span> <span class="key">and</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">remaining_pretext</span><span class="op">,</span> <span class="str">'text'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">577&#x202F;&#x219B;&#x202F;578</span><span class="annotate long">line 577 didn't jump to line 578 because the condition on line 577 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t578" href="#t578">578</a></span><span class="t"> <span class="nam">new_pos</span><span class="op">.</span><span class="nam">remaining_pretext</span> <span class="op">=</span> <span class="nam">remaining_pretext</span><span class="op">.</span><span class="nam">text</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t579" href="#t579">579</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t580" href="#t580">580</a></span><span class="t"> <span class="nam">new_pos</span><span class="op">.</span><span class="nam">remaining_pretext</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t581" href="#t581">581</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t582" href="#t582">582</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span><span class="op">,</span> <span class="nam">new_pos</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t583" href="#t583">583</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t584" href="#t584">584</a></span><span class="t"> <span class="com"># No specific word failed, but layout wasn't successful</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t585" href="#t585">585</a></span><span class="t"> <span class="com"># This shouldn't normally happen, but handle it gracefully</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t586" href="#t586">586</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span><span class="op">,</span> <span class="nam">position</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t587" href="#t587">587</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t588" href="#t588">588</a></span><span class="t"> <span class="key">def</span> <span class="nam">_layout_heading_on_page</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t589" href="#t589">589</a></span><span class="t"> <span class="nam">heading</span><span class="op">:</span> <span class="nam">Heading</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t590" href="#t590">590</a></span><span class="t"> <span class="nam">page</span><span class="op">:</span> <span class="nam">Page</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t591" href="#t591">591</a></span><span class="t"> <span class="nam">position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t592" href="#t592">592</a></span><span class="t"> <span class="nam">font_scale</span><span class="op">:</span> <span class="nam">float</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">bool</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t593" href="#t593">593</a></span><span class="t"> <span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t594" href="#t594">594</a></span><span class="t"> <span class="str">"""Layout a heading on the page"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t595" href="#t595">595</a></span><span class="t"> <span class="com"># Similar to paragraph but with heading-specific styling</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t596" href="#t596">596</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_layout_paragraph_on_page</span><span class="op">(</span><span class="nam">heading</span><span class="op">,</span> <span class="nam">page</span><span class="op">,</span> <span class="nam">position</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t597" href="#t597">597</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t598" href="#t598">598</a></span><span class="t"> <span class="key">def</span> <span class="nam">_layout_table_on_page</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t599" href="#t599">599</a></span><span class="t"> <span class="nam">table</span><span class="op">:</span> <span class="nam">Table</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t600" href="#t600">600</a></span><span class="t"> <span class="nam">page</span><span class="op">:</span> <span class="nam">Page</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t601" href="#t601">601</a></span><span class="t"> <span class="nam">position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t602" href="#t602">602</a></span><span class="t"> <span class="nam">font_scale</span><span class="op">:</span> <span class="nam">float</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">bool</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t603" href="#t603">603</a></span><span class="t"> <span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t604" href="#t604">604</a></span><span class="t"> <span class="str">"""Layout a table on the page with column fitting and row continuation"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t605" href="#t605">605</a></span><span class="t"> <span class="com"># This is a complex operation that would need full table layout logic</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t606" href="#t606">606</a></span><span class="t"> <span class="com"># For now, skip tables</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t607" href="#t607">607</a></span><span class="t"> <span class="nam">new_pos</span> <span class="op">=</span> <span class="nam">position</span><span class="op">.</span><span class="nam">copy</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t608" href="#t608">608</a></span><span class="t"> <span class="nam">new_pos</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">+=</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t609" href="#t609">609</a></span><span class="t"> <span class="nam">new_pos</span><span class="op">.</span><span class="nam">table_row</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t610" href="#t610">610</a></span><span class="t"> <span class="nam">new_pos</span><span class="op">.</span><span class="nam">table_col</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t611" href="#t611">611</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span><span class="op">,</span> <span class="nam">new_pos</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t612" href="#t612">612</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t613" href="#t613">613</a></span><span class="t"> <span class="key">def</span> <span class="nam">_layout_list_on_page</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t614" href="#t614">614</a></span><span class="t"> <span class="nam">hlist</span><span class="op">:</span> <span class="nam">HList</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t615" href="#t615">615</a></span><span class="t"> <span class="nam">page</span><span class="op">:</span> <span class="nam">Page</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t616" href="#t616">616</a></span><span class="t"> <span class="nam">position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t617" href="#t617">617</a></span><span class="t"> <span class="nam">font_scale</span><span class="op">:</span> <span class="nam">float</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">bool</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t618" href="#t618">618</a></span><span class="t"> <span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t619" href="#t619">619</a></span><span class="t"> <span class="str">"""Layout a list on the page"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t620" href="#t620">620</a></span><span class="t"> <span class="com"># This would need list-specific layout logic</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t621" href="#t621">621</a></span><span class="t"> <span class="com"># For now, skip lists</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t622" href="#t622">622</a></span><span class="t"> <span class="nam">new_pos</span> <span class="op">=</span> <span class="nam">position</span><span class="op">.</span><span class="nam">copy</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t623" href="#t623">623</a></span><span class="t"> <span class="nam">new_pos</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">+=</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t624" href="#t624">624</a></span><span class="t"> <span class="nam">new_pos</span><span class="op">.</span><span class="nam">list_item_index</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t625" href="#t625">625</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span><span class="op">,</span> <span class="nam">new_pos</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t626" href="#t626">626</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t627" href="#t627">627</a></span><span class="t"> <span class="key">def</span> <span class="nam">_layout_image_on_page</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t628" href="#t628">628</a></span><span class="t"> <span class="nam">image</span><span class="op">:</span> <span class="nam">Image</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t629" href="#t629">629</a></span><span class="t"> <span class="nam">page</span><span class="op">:</span> <span class="nam">Page</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t630" href="#t630">630</a></span><span class="t"> <span class="nam">position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t631" href="#t631">631</a></span><span class="t"> <span class="nam">font_scale</span><span class="op">:</span> <span class="nam">float</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">bool</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t632" href="#t632">632</a></span><span class="t"> <span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t633" href="#t633">633</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t634" href="#t634">634</a></span><span class="t"><span class="str"> Layout an image on the page using the image_layouter.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t635" href="#t635">635</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t636" href="#t636">636</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t637" href="#t637">637</a></span><span class="t"><span class="str"> image: The Image block to layout</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t638" href="#t638">638</a></span><span class="t"><span class="str"> page: The page to layout on</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t639" href="#t639">639</a></span><span class="t"><span class="str"> position: Current rendering position (should be at the start of this image block)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t640" href="#t640">640</a></span><span class="t"><span class="str"> font_scale: Font scaling factor (not used for images, but kept for consistency)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t641" href="#t641">641</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t642" href="#t642">642</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t643" href="#t643">643</a></span><span class="t"><span class="str"> Tuple of (success, new_position)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t644" href="#t644">644</a></span><span class="t"><span class="str"> - success: True if image was laid out, False if page ran out of space</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t645" href="#t645">645</a></span><span class="t"><span class="str"> - new_position: Updated position (next block if success, same block if failed)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t646" href="#t646">646</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t647" href="#t647">647</a></span><span class="t"> <span class="com"># Try to layout the image on the current page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t648" href="#t648">648</a></span><span class="t"> <span class="nam">success</span> <span class="op">=</span> <span class="nam">image_layouter</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t649" href="#t649">649</a></span><span class="t"> <span class="nam">image</span><span class="op">=</span><span class="nam">image</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t650" href="#t650">650</a></span><span class="t"> <span class="nam">page</span><span class="op">=</span><span class="nam">page</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t651" href="#t651">651</a></span><span class="t"> <span class="nam">max_width</span><span class="op">=</span><span class="key">None</span><span class="op">,</span> <span class="com"># Use page available width</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t652" href="#t652">652</a></span><span class="t"> <span class="nam">max_height</span><span class="op">=</span><span class="key">None</span> <span class="com"># Use page available height</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t653" href="#t653">653</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t654" href="#t654">654</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t655" href="#t655">655</a></span><span class="t"> <span class="nam">new_pos</span> <span class="op">=</span> <span class="nam">position</span><span class="op">.</span><span class="nam">copy</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t656" href="#t656">656</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t657" href="#t657">657</a></span><span class="t"> <span class="key">if</span> <span class="nam">success</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t658" href="#t658">658</a></span><span class="t"> <span class="com"># Image was successfully laid out, move to next block</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t659" href="#t659">659</a></span><span class="t"> <span class="nam">new_pos</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">+=</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t660" href="#t660">660</a></span><span class="t"> <span class="nam">new_pos</span><span class="op">.</span><span class="nam">word_index</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t661" href="#t661">661</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span><span class="op">,</span> <span class="nam">new_pos</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t662" href="#t662">662</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t663" href="#t663">663</a></span><span class="t"> <span class="com"># Image didn't fit on current page, signal to continue on next page</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t664" href="#t664">664</a></span><span class="t"> <span class="com"># Keep same position so it will be attempted on the next page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t665" href="#t665">665</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span><span class="op">,</span> <span class="nam">position</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t666" href="#t666">666</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t667" href="#t667">667</a></span><span class="t"> <span class="key">def</span> <span class="nam">_estimate_page_start</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t668" href="#t668">668</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t669" href="#t669">669</a></span><span class="t"> <span class="nam">end_position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t670" href="#t670">670</a></span><span class="t"> <span class="nam">font_scale</span><span class="op">:</span> <span class="nam">float</span><span class="op">)</span> <span class="op">-></span> <span class="nam">RenderingPosition</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t671" href="#t671">671</a></span><span class="t"> <span class="str">"""Estimate where a page should start to end at the given position"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t672" href="#t672">672</a></span><span class="t"> <span class="com"># This is a simplified heuristic - a full implementation would be more</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t673" href="#t673">673</a></span><span class="t"> <span class="com"># sophisticated</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t674" href="#t674">674</a></span><span class="t"> <span class="nam">estimated_start</span> <span class="op">=</span> <span class="nam">end_position</span><span class="op">.</span><span class="nam">copy</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t675" href="#t675">675</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t676" href="#t676">676</a></span><span class="t"> <span class="com"># Move back by an estimated number of blocks that would fit on a page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t677" href="#t677">677</a></span><span class="t"> <span class="nam">estimated_blocks_per_page</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="num">1</span><span class="op">,</span> <span class="nam">int</span><span class="op">(</span><span class="num">10</span> <span class="op">/</span> <span class="nam">font_scale</span><span class="op">)</span><span class="op">)</span> <span class="com"># Rough estimate</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t678" href="#t678">678</a></span><span class="t"> <span class="nam">estimated_start</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t679" href="#t679">679</a></span><span class="t"> <span class="num">0</span><span class="op">,</span> <span class="nam">end_position</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">-</span> <span class="nam">estimated_blocks_per_page</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t680" href="#t680">680</a></span><span class="t"> <span class="nam">estimated_start</span><span class="op">.</span><span class="nam">word_index</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t681" href="#t681">681</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t682" href="#t682">682</a></span><span class="t"> <span class="key">return</span> <span class="nam">estimated_start</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t683" href="#t683">683</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t684" href="#t684">684</a></span><span class="t"> <span class="key">def</span> <span class="nam">_adjust_start_estimate</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t685" href="#t685">685</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t686" href="#t686">686</a></span><span class="t"> <span class="nam">current_start</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t687" href="#t687">687</a></span><span class="t"> <span class="nam">target_end</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t688" href="#t688">688</a></span><span class="t"> <span class="nam">actual_end</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">)</span> <span class="op">-></span> <span class="nam">RenderingPosition</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t689" href="#t689">689</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t690" href="#t690">690</a></span><span class="t"><span class="str"> Adjust start position estimate based on overshoot/undershoot.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t691" href="#t691">691</a></span><span class="t"><span class="str"> Uses proportional adjustment to converge faster.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t692" href="#t692">692</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t693" href="#t693">693</a></span><span class="t"> <span class="nam">adjusted</span> <span class="op">=</span> <span class="nam">current_start</span><span class="op">.</span><span class="nam">copy</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t694" href="#t694">694</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t695" href="#t695">695</a></span><span class="t"> <span class="com"># Calculate the difference between actual and target end positions</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t696" href="#t696">696</a></span><span class="t"> <span class="nam">block_diff</span> <span class="op">=</span> <span class="nam">actual_end</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">-</span> <span class="nam">target_end</span><span class="op">.</span><span class="nam">block_index</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t697" href="#t697">697</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t698" href="#t698">698</a></span><span class="t"> <span class="nam">comparison</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_position_compare</span><span class="op">(</span><span class="nam">actual_end</span><span class="op">,</span> <span class="nam">target_end</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t699" href="#t699">699</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t700" href="#t700">700</a></span><span class="t"> <span class="key">if</span> <span class="nam">comparison</span> <span class="op">&lt;</span> <span class="num">0</span><span class="op">:</span> <span class="com"># Undershot - rendered to block X but need to reach block Y where X &lt; Y</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t701" href="#t701">701</a></span><span class="t"> <span class="com"># We didn't render far enough forward</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t702" href="#t702">702</a></span><span class="t"> <span class="com"># Need to start at a LATER block (higher index) so the page includes more content</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t703" href="#t703">703</a></span><span class="t"> <span class="nam">adjustment</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="num">1</span><span class="op">,</span> <span class="nam">abs</span><span class="op">(</span><span class="nam">block_diff</span><span class="op">)</span> <span class="op">//</span> <span class="num">2</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t704" href="#t704">704</a></span><span class="t"> <span class="nam">new_index</span> <span class="op">=</span> <span class="nam">adjusted</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">+</span> <span class="nam">adjustment</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t705" href="#t705">705</a></span><span class="t"> <span class="com"># Clamp to valid range</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t706" href="#t706">706</a></span><span class="t"> <span class="key">if</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">)</span> <span class="op">></span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">706&#x202F;&#x219B;&#x202F;707</span><span class="annotate long">line 706 didn't jump to line 707 because the condition on line 706 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t707" href="#t707">707</a></span><span class="t"> <span class="nam">adjusted</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">=</span> <span class="nam">min</span><span class="op">(</span><span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">)</span> <span class="op">-</span> <span class="num">1</span><span class="op">,</span> <span class="nam">max</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="nam">new_index</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t708" href="#t708">708</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t709" href="#t709">709</a></span><span class="t"> <span class="nam">adjusted</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="nam">new_index</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t710" href="#t710">710</a></span><span class="t"> <span class="key">elif</span> <span class="nam">comparison</span> <span class="op">></span> <span class="num">0</span><span class="op">:</span> <span class="com"># Overshot - rendered past the target</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t711" href="#t711">711</a></span><span class="t"> <span class="com"># We rendered too far forward</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t712" href="#t712">712</a></span><span class="t"> <span class="com"># Need to start at an EARLIER block (lower index) so the page doesn't go as far</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t713" href="#t713">713</a></span><span class="t"> <span class="nam">adjustment</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="num">1</span><span class="op">,</span> <span class="nam">abs</span><span class="op">(</span><span class="nam">block_diff</span><span class="op">)</span> <span class="op">//</span> <span class="num">2</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t714" href="#t714">714</a></span><span class="t"> <span class="nam">adjusted</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="nam">adjusted</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">-</span> <span class="nam">adjustment</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t715" href="#t715">715</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t716" href="#t716">716</a></span><span class="t"> <span class="com"># Reset word index when adjusting blocks</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t717" href="#t717">717</a></span><span class="t"> <span class="nam">adjusted</span><span class="op">.</span><span class="nam">word_index</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t718" href="#t718">718</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t719" href="#t719">719</a></span><span class="t"> <span class="key">return</span> <span class="nam">adjusted</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t720" href="#t720">720</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t721" href="#t721">721</a></span><span class="t"> <span class="key">def</span> <span class="nam">_position_compare</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">pos1</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t722" href="#t722">722</a></span><span class="t"> <span class="nam">pos2</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t723" href="#t723">723</a></span><span class="t"> <span class="str">"""Compare two positions (-1: pos1 &lt; pos2, 0: equal, 1: pos1 > pos2)"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t724" href="#t724">724</a></span><span class="t"> <span class="key">if</span> <span class="nam">pos1</span><span class="op">.</span><span class="nam">chapter_index</span> <span class="op">!=</span> <span class="nam">pos2</span><span class="op">.</span><span class="nam">chapter_index</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t725" href="#t725">725</a></span><span class="t"> <span class="key">return</span> <span class="num">1</span> <span class="key">if</span> <span class="nam">pos1</span><span class="op">.</span><span class="nam">chapter_index</span> <span class="op">></span> <span class="nam">pos2</span><span class="op">.</span><span class="nam">chapter_index</span> <span class="key">else</span> <span class="op">-</span><span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t726" href="#t726">726</a></span><span class="t"> <span class="key">if</span> <span class="nam">pos1</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">!=</span> <span class="nam">pos2</span><span class="op">.</span><span class="nam">block_index</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t727" href="#t727">727</a></span><span class="t"> <span class="key">return</span> <span class="num">1</span> <span class="key">if</span> <span class="nam">pos1</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">></span> <span class="nam">pos2</span><span class="op">.</span><span class="nam">block_index</span> <span class="key">else</span> <span class="op">-</span><span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t728" href="#t728">728</a></span><span class="t"> <span class="key">if</span> <span class="nam">pos1</span><span class="op">.</span><span class="nam">word_index</span> <span class="op">!=</span> <span class="nam">pos2</span><span class="op">.</span><span class="nam">word_index</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t729" href="#t729">729</a></span><span class="t"> <span class="key">return</span> <span class="num">1</span> <span class="key">if</span> <span class="nam">pos1</span><span class="op">.</span><span class="nam">word_index</span> <span class="op">></span> <span class="nam">pos2</span><span class="op">.</span><span class="nam">word_index</span> <span class="key">else</span> <span class="op">-</span><span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t730" href="#t730">730</a></span><span class="t"> <span class="key">return</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t731" href="#t731">731</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t732" href="#t732">732</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t733" href="#t733">733</a></span><span class="t"><span class="com"># Add can_fit_line method to Page class if it doesn't exist</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t734" href="#t734">734</a></span><span class="t"><span class="key">def</span> <span class="nam">_add_page_methods</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t735" href="#t735">735</a></span><span class="t"> <span class="str">"""Add missing methods to Page class"""</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t736" href="#t736">736</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">Page</span><span class="op">,</span> <span class="str">'can_fit_line'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">736&#x202F;&#x219B;&#x202F;737</span><span class="annotate long">line 736 didn't jump to line 737 because the condition on line 736 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t737" href="#t737">737</a></span><span class="t"> <span class="key">def</span> <span class="nam">can_fit_line</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">line_height</span><span class="op">:</span> <span class="nam">int</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t738" href="#t738">738</a></span><span class="t"> <span class="str">"""Check if a line of given height can fit on the page"""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t739" href="#t739">739</a></span><span class="t"> <span class="nam">available_height</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">content_size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">-</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_current_y_offset</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t740" href="#t740">740</a></span><span class="t"> <span class="key">return</span> <span class="nam">available_height</span> <span class="op">>=</span> <span class="nam">line_height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t741" href="#t741">741</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t742" href="#t742">742</a></span><span class="t"> <span class="nam">Page</span><span class="op">.</span><span class="nam">can_fit_line</span> <span class="op">=</span> <span class="nam">can_fit_line</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t743" href="#t743">743</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t744" href="#t744">744</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">Page</span><span class="op">,</span> <span class="str">'available_width'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">744&#x202F;&#x219B;&#x202F;745</span><span class="annotate long">line 744 didn't jump to line 745 because the condition on line 744 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t745" href="#t745">745</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t746" href="#t746">746</a></span><span class="t"> <span class="key">def</span> <span class="nam">available_width</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t747" href="#t747">747</a></span><span class="t"> <span class="str">"""Get available width for content"""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t748" href="#t748">748</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">content_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t749" href="#t749">749</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t750" href="#t750">750</a></span><span class="t"> <span class="nam">Page</span><span class="op">.</span><span class="nam">available_width</span> <span class="op">=</span> <span class="nam">available_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t751" href="#t751">751</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t752" href="#t752">752</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t753" href="#t753">753</a></span><span class="t"><span class="com"># Apply the page methods</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t754" href="#t754">754</a></span><span class="t"><span class="nam">_add_page_methods</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_427cc3035faf7633_document_layouter_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_427cc3035faf7633_ereader_manager_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,987 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/layout/ereader_manager.py: 84%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/layout/ereader_manager.py</b>:
<span class="pc_cov">84%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">292 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">244<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">48<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">53<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">8<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_427cc3035faf7633_ereader_layout_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_427cc3035faf7633_page_buffer_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">High-performance ereader layout manager with sub-second page rendering.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">This module provides the main interface for ereader applications, combining</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">position tracking, font scaling, chapter navigation, and intelligent page buffering</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="str">into a unified, easy-to-use API.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="key">from</span> <span class="nam">__future__</span> <span class="key">import</span> <span class="nam">annotations</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">List</span><span class="op">,</span> <span class="nam">Dict</span><span class="op">,</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">Tuple</span><span class="op">,</span> <span class="nam">Any</span><span class="op">,</span> <span class="nam">Callable</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="key">import</span> <span class="nam">json</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="key">from</span> <span class="nam">pathlib</span> <span class="key">import</span> <span class="nam">Path</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">ereader_layout</span> <span class="key">import</span> <span class="nam">RenderingPosition</span><span class="op">,</span> <span class="nam">ChapterNavigator</span><span class="op">,</span> <span class="nam">ChapterInfo</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">page_buffer</span> <span class="key">import</span> <span class="nam">BufferedPageRenderer</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">block</span> <span class="key">import</span> <span class="nam">Block</span><span class="op">,</span> <span class="nam">HeadingLevel</span><span class="op">,</span> <span class="nam">Image</span><span class="op">,</span> <span class="nam">BlockType</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span><span class="op">.</span><span class="nam">page</span> <span class="key">import</span> <span class="nam">Page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span><span class="op">.</span><span class="nam">image</span> <span class="key">import</span> <span class="nam">RenderableImage</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">page_style</span> <span class="key">import</span> <span class="nam">PageStyle</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">fonts</span> <span class="key">import</span> <span class="nam">BundledFont</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">layout</span><span class="op">.</span><span class="nam">document_layouter</span> <span class="key">import</span> <span class="nam">image_layouter</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"><span class="key">class</span> <span class="nam">BookmarkManager</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"><span class="str"> Manages bookmarks and reading position persistence for ereader applications.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">document_id</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span> <span class="nam">bookmarks_dir</span><span class="op">:</span> <span class="nam">str</span> <span class="op">=</span> <span class="str">"bookmarks"</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"><span class="str"> Initialize bookmark manager.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"><span class="str"> document_id: Unique identifier for the document</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"><span class="str"> bookmarks_dir: Directory to store bookmark files</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">document_id</span> <span class="op">=</span> <span class="nam">document_id</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">bookmarks_dir</span> <span class="op">=</span> <span class="nam">Path</span><span class="op">(</span><span class="nam">bookmarks_dir</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">bookmarks_dir</span><span class="op">.</span><span class="nam">mkdir</span><span class="op">(</span><span class="nam">exist_ok</span><span class="op">=</span><span class="key">True</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">bookmarks_file</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">bookmarks_dir</span> <span class="op">/</span> <span class="fst">f"</span><span class="op">{</span><span class="nam">document_id</span><span class="op">}</span><span class="fst">_bookmarks.json</span><span class="fst">"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">position_file</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">bookmarks_dir</span> <span class="op">/</span> <span class="fst">f"</span><span class="op">{</span><span class="nam">document_id</span><span class="op">}</span><span class="fst">_position.json</span><span class="fst">"</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_bookmarks</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">RenderingPosition</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_load_bookmarks</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"> <span class="key">def</span> <span class="nam">_load_bookmarks</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"> <span class="str">"""Load bookmarks from file"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">bookmarks_file</span><span class="op">.</span><span class="nam">exists</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t"> <span class="key">with</span> <span class="nam">open</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">bookmarks_file</span><span class="op">,</span> <span class="str">'r'</span><span class="op">)</span> <span class="key">as</span> <span class="nam">f</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t"> <span class="nam">data</span> <span class="op">=</span> <span class="nam">json</span><span class="op">.</span><span class="nam">load</span><span class="op">(</span><span class="nam">f</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_bookmarks</span> <span class="op">=</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t"> <span class="nam">name</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">.</span><span class="nam">from_dict</span><span class="op">(</span><span class="nam">pos_data</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"> <span class="key">for</span> <span class="nam">name</span><span class="op">,</span> <span class="nam">pos_data</span> <span class="key">in</span> <span class="nam">data</span><span class="op">.</span><span class="nam">items</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t"> <span class="key">except</span> <span class="nam">Exception</span> <span class="key">as</span> <span class="nam">e</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t"> <span class="nam">print</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Failed to load bookmarks: </span><span class="op">{</span><span class="nam">e</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_bookmarks</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"> <span class="key">def</span> <span class="nam">_save_bookmarks</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t"> <span class="str">"""Save bookmarks to file"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"> <span class="nam">data</span> <span class="op">=</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"> <span class="nam">name</span><span class="op">:</span> <span class="nam">position</span><span class="op">.</span><span class="nam">to_dict</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t"> <span class="key">for</span> <span class="nam">name</span><span class="op">,</span> <span class="nam">position</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_bookmarks</span><span class="op">.</span><span class="nam">items</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"> <span class="key">with</span> <span class="nam">open</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">bookmarks_file</span><span class="op">,</span> <span class="str">'w'</span><span class="op">)</span> <span class="key">as</span> <span class="nam">f</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"> <span class="nam">json</span><span class="op">.</span><span class="nam">dump</span><span class="op">(</span><span class="nam">data</span><span class="op">,</span> <span class="nam">f</span><span class="op">,</span> <span class="nam">indent</span><span class="op">=</span><span class="num">2</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t"> <span class="key">except</span> <span class="nam">Exception</span> <span class="key">as</span> <span class="nam">e</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t"> <span class="nam">print</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Failed to save bookmarks: </span><span class="op">{</span><span class="nam">e</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"> <span class="key">def</span> <span class="nam">add_bookmark</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">name</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span> <span class="nam">position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"><span class="str"> Add a bookmark at the given position.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"><span class="str"> name: Bookmark name</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t"><span class="str"> position: Position to bookmark</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_bookmarks</span><span class="op">[</span><span class="nam">name</span><span class="op">]</span> <span class="op">=</span> <span class="nam">position</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_save_bookmarks</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"> <span class="key">def</span> <span class="nam">remove_bookmark</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">name</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t"><span class="str"> Remove a bookmark.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"><span class="str"> name: Bookmark name to remove</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t"><span class="str"> True if bookmark was removed, False if not found</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t"> <span class="key">if</span> <span class="nam">name</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_bookmarks</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t"> <span class="key">del</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_bookmarks</span><span class="op">[</span><span class="nam">name</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_save_bookmarks</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_bookmark</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">name</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"><span class="str"> Get a bookmark position.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t"><span class="str"> name: Bookmark name</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t"><span class="str"> Bookmark position or None if not found</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_bookmarks</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="nam">name</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"> <span class="key">def</span> <span class="nam">list_bookmarks</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">Tuple</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t"><span class="str"> Get all bookmarks.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t"><span class="str"> List of (name, position) tuples</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"> <span class="key">return</span> <span class="nam">list</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_bookmarks</span><span class="op">.</span><span class="nam">items</span><span class="op">(</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t"> <span class="key">def</span> <span class="nam">save_reading_position</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"><span class="str"> Save the current reading position.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t"><span class="str"> position: Current reading position</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t"> <span class="key">with</span> <span class="nam">open</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">position_file</span><span class="op">,</span> <span class="str">'w'</span><span class="op">)</span> <span class="key">as</span> <span class="nam">f</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t"> <span class="nam">json</span><span class="op">.</span><span class="nam">dump</span><span class="op">(</span><span class="nam">position</span><span class="op">.</span><span class="nam">to_dict</span><span class="op">(</span><span class="op">)</span><span class="op">,</span> <span class="nam">f</span><span class="op">,</span> <span class="nam">indent</span><span class="op">=</span><span class="num">2</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t"> <span class="key">except</span> <span class="nam">Exception</span> <span class="key">as</span> <span class="nam">e</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t"> <span class="nam">print</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Failed to save reading position: </span><span class="op">{</span><span class="nam">e</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t"> <span class="key">def</span> <span class="nam">load_reading_position</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"><span class="str"> Load the last reading position.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t"><span class="str"> Last reading position or None if not found</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">position_file</span><span class="op">.</span><span class="nam">exists</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t"> <span class="key">with</span> <span class="nam">open</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">position_file</span><span class="op">,</span> <span class="str">'r'</span><span class="op">)</span> <span class="key">as</span> <span class="nam">f</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"> <span class="nam">data</span> <span class="op">=</span> <span class="nam">json</span><span class="op">.</span><span class="nam">load</span><span class="op">(</span><span class="nam">f</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t"> <span class="key">return</span> <span class="nam">RenderingPosition</span><span class="op">.</span><span class="nam">from_dict</span><span class="op">(</span><span class="nam">data</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t"> <span class="key">except</span> <span class="nam">Exception</span> <span class="key">as</span> <span class="nam">e</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"> <span class="nam">print</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Failed to load reading position: </span><span class="op">{</span><span class="nam">e</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t"><span class="key">class</span> <span class="nam">EreaderLayoutManager</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t"><span class="str"> High-level ereader layout manager providing a complete interface for ereader applications.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t"><span class="str"> Features:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t"><span class="str"> - Sub-second page rendering with intelligent buffering</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t"><span class="str"> - Font scaling support</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t"><span class="str"> - Dynamic font family switching (Sans, Serif, Monospace)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t"><span class="str"> - Chapter navigation</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"><span class="str"> - Bookmark management</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t"><span class="str"> - Position persistence</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t"><span class="str"> - Progress tracking</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"> <span class="nam">blocks</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">Block</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t"> <span class="nam">page_size</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t"> <span class="nam">document_id</span><span class="op">:</span> <span class="nam">str</span> <span class="op">=</span> <span class="str">"default"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t"> <span class="nam">buffer_size</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">5</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"> <span class="nam">page_style</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">PageStyle</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t"> <span class="nam">bookmarks_dir</span><span class="op">:</span> <span class="nam">str</span> <span class="op">=</span> <span class="str">"bookmarks"</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t"><span class="str"> Initialize the ereader layout manager.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t"><span class="str"> blocks: Document blocks to render</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t"><span class="str"> page_size: Page size (width, height) in pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t"><span class="str"> document_id: Unique identifier for the document (for bookmarks/position)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t"><span class="str"> buffer_size: Number of pages to cache in each direction</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t"><span class="str"> page_style: Custom page styling (uses default if None)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t"><span class="str"> bookmarks_dir: Directory to store bookmark files</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span> <span class="op">=</span> <span class="nam">blocks</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">page_size</span> <span class="op">=</span> <span class="nam">page_size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">document_id</span> <span class="op">=</span> <span class="nam">document_id</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t"> <span class="com"># Initialize page style</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t"> <span class="key">if</span> <span class="nam">page_style</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t"> <span class="nam">page_style</span> <span class="op">=</span> <span class="nam">PageStyle</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span> <span class="op">=</span> <span class="nam">page_style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t"> <span class="com"># Initialize core components</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">renderer</span> <span class="op">=</span> <span class="nam">BufferedPageRenderer</span><span class="op">(</span><span class="nam">blocks</span><span class="op">,</span> <span class="nam">page_style</span><span class="op">,</span> <span class="nam">buffer_size</span><span class="op">,</span> <span class="nam">page_size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">chapter_navigator</span> <span class="op">=</span> <span class="nam">ChapterNavigator</span><span class="op">(</span><span class="nam">blocks</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">bookmark_manager</span> <span class="op">=</span> <span class="nam">BookmarkManager</span><span class="op">(</span><span class="nam">document_id</span><span class="op">,</span> <span class="nam">bookmarks_dir</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"> <span class="com"># Current state</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span> <span class="op">=</span> <span class="nam">RenderingPosition</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">font_scale</span> <span class="op">=</span> <span class="num">1.0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t"> <span class="com"># Cover page handling</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_has_cover</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_detect_cover</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_on_cover_page</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_has_cover</span> <span class="com"># Start on cover if one exists</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t"> <span class="com"># Page position history for fast backward navigation</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t"> <span class="com"># List of (position, font_scale) tuples representing the start of each page visited</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_page_history</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">Tuple</span><span class="op">[</span><span class="nam">RenderingPosition</span><span class="op">,</span> <span class="nam">float</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_max_history_size</span> <span class="op">=</span> <span class="num">50</span> <span class="com"># Keep last 50 page positions</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t"> <span class="com"># Load last reading position if available</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t"> <span class="nam">saved_position</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">bookmark_manager</span><span class="op">.</span><span class="nam">load_reading_position</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t"> <span class="key">if</span> <span class="nam">saved_position</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span> <span class="op">=</span> <span class="nam">saved_position</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_on_cover_page</span> <span class="op">=</span> <span class="key">False</span> <span class="com"># If we have a saved position, we're past the cover</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t"> <span class="com"># Callbacks for UI updates</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">position_changed_callback</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Callable</span><span class="op">[</span><span class="op">[</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t"> <span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">,</span> <span class="key">None</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">chapter_changed_callback</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Callable</span><span class="op">[</span><span class="op">[</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t"> <span class="nam">Optional</span><span class="op">[</span><span class="nam">ChapterInfo</span><span class="op">]</span><span class="op">]</span><span class="op">,</span> <span class="key">None</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_position_changed_callback</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span> <span class="nam">callback</span><span class="op">:</span> <span class="nam">Callable</span><span class="op">[</span><span class="op">[</span><span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">,</span> <span class="key">None</span><span class="op">]</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t"> <span class="str">"""Set callback for position changes"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">position_changed_callback</span> <span class="op">=</span> <span class="nam">callback</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_chapter_changed_callback</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span> <span class="nam">callback</span><span class="op">:</span> <span class="nam">Callable</span><span class="op">[</span><span class="op">[</span><span class="nam">Optional</span><span class="op">[</span><span class="nam">ChapterInfo</span><span class="op">]</span><span class="op">]</span><span class="op">,</span> <span class="key">None</span><span class="op">]</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t"> <span class="str">"""Set callback for chapter changes"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">chapter_changed_callback</span> <span class="op">=</span> <span class="nam">callback</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t"> <span class="key">def</span> <span class="nam">_detect_cover</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t"><span class="str"> Detect if the document has a cover page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t"><span class="str"> A cover is detected if:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t"><span class="str"> 1. The first block is an Image block, OR</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t"><span class="str"> 2. The document has cover metadata (future enhancement)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t"><span class="str"> True if a cover page should be rendered</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t"> <span class="com"># Check if first block is an image - treat it as a cover</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t"> <span class="nam">first_block</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">[</span><span class="num">0</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">first_block</span><span class="op">,</span> <span class="nam">Image</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t"> <span class="key">def</span> <span class="nam">_render_cover_page</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Page</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t"><span class="str"> Render a dedicated cover page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t"><span class="str"> The cover page displays the first image block (if it exists)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t"><span class="str"> using the standard image layouter with maximum dimensions to fill the page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t"><span class="str"> Rendered cover page</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t"> <span class="com"># Create a new page for the cover</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t"> <span class="nam">page</span> <span class="op">=</span> <span class="nam">Page</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">page_size</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span> <span class="key">or</span> <span class="key">not</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">,</span> <span class="nam">Image</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">266&#x202F;&#x219B;&#x202F;268</span><span class="annotate long">line 266 didn't jump to line 268 because the condition on line 266 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t"> <span class="com"># No cover image, return blank page</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t"> <span class="key">return</span> <span class="nam">page</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t"> <span class="nam">cover_image_block</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">[</span><span class="num">0</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t"> <span class="com"># Use the image layouter to render the cover image</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t"> <span class="com"># Use full page dimensions (minus borders/padding) for cover</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t"> <span class="nam">max_width</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">-</span> <span class="num">2</span> <span class="op">*</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span><span class="op">.</span><span class="nam">border_width</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t"> <span class="nam">max_height</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page_size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">-</span> <span class="num">2</span> <span class="op">*</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span><span class="op">.</span><span class="nam">border_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t"> <span class="com"># Layout the image on the page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t279" href="#t279">279</a></span><span class="t"> <span class="nam">success</span> <span class="op">=</span> <span class="nam">image_layouter</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t280" href="#t280">280</a></span><span class="t"> <span class="nam">image</span><span class="op">=</span><span class="nam">cover_image_block</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t281" href="#t281">281</a></span><span class="t"> <span class="nam">page</span><span class="op">=</span><span class="nam">page</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t282" href="#t282">282</a></span><span class="t"> <span class="nam">max_width</span><span class="op">=</span><span class="nam">max_width</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t283" href="#t283">283</a></span><span class="t"> <span class="nam">max_height</span><span class="op">=</span><span class="nam">max_height</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t284" href="#t284">284</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t285" href="#t285">285</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t286" href="#t286">286</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">success</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">286&#x202F;&#x219B;&#x202F;293</span><span class="annotate long">line 286 didn't jump to line 293 because the condition on line 286 was always true</span></span></p>
<p class="run"><span class="n"><a id="t287" href="#t287">287</a></span><span class="t"> <span class="nam">print</span><span class="op">(</span><span class="str">"Warning: Failed to layout cover image"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t288" href="#t288">288</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t289" href="#t289">289</a></span><span class="t"> <span class="key">except</span> <span class="nam">Exception</span> <span class="key">as</span> <span class="nam">e</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t290" href="#t290">290</a></span><span class="t"> <span class="com"># If image loading fails, just return the blank page</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t291" href="#t291">291</a></span><span class="t"> <span class="nam">print</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Warning: Failed to load cover image: </span><span class="op">{</span><span class="nam">e</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t292" href="#t292">292</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t293" href="#t293">293</a></span><span class="t"> <span class="key">return</span> <span class="nam">page</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t294" href="#t294">294</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t295" href="#t295">295</a></span><span class="t"> <span class="key">def</span> <span class="nam">_notify_position_changed</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t296" href="#t296">296</a></span><span class="t"> <span class="str">"""Notify UI of position change"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t297" href="#t297">297</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">position_changed_callback</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t298" href="#t298">298</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">position_changed_callback</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t299" href="#t299">299</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t300" href="#t300">300</a></span><span class="t"> <span class="com"># Check if chapter changed</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t301" href="#t301">301</a></span><span class="t"> <span class="nam">current_chapter</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">chapter_navigator</span><span class="op">.</span><span class="nam">get_current_chapter</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t302" href="#t302">302</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t303" href="#t303">303</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">chapter_changed_callback</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t304" href="#t304">304</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">chapter_changed_callback</span><span class="op">(</span><span class="nam">current_chapter</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t305" href="#t305">305</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t306" href="#t306">306</a></span><span class="t"> <span class="com"># Auto-save reading position</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t307" href="#t307">307</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">bookmark_manager</span><span class="op">.</span><span class="nam">save_reading_position</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t308" href="#t308">308</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t309" href="#t309">309</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_current_page</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Page</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t310" href="#t310">310</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t311" href="#t311">311</a></span><span class="t"><span class="str"> Get the page at the current reading position.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t312" href="#t312">312</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t313" href="#t313">313</a></span><span class="t"><span class="str"> If on the cover page, returns the rendered cover.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t314" href="#t314">314</a></span><span class="t"><span class="str"> Otherwise, returns the regular content page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t315" href="#t315">315</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t316" href="#t316">316</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t317" href="#t317">317</a></span><span class="t"><span class="str"> Rendered page</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t318" href="#t318">318</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t319" href="#t319">319</a></span><span class="t"> <span class="com"># Check if we're on the cover page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t320" href="#t320">320</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_on_cover_page</span> <span class="key">and</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_has_cover</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t321" href="#t321">321</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_render_cover_page</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t322" href="#t322">322</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t323" href="#t323">323</a></span><span class="t"> <span class="nam">page</span><span class="op">,</span> <span class="nam">_</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">renderer</span><span class="op">.</span><span class="nam">render_page</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t324" href="#t324">324</a></span><span class="t"> <span class="key">return</span> <span class="nam">page</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t325" href="#t325">325</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t326" href="#t326">326</a></span><span class="t"> <span class="key">def</span> <span class="nam">next_page</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Page</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t327" href="#t327">327</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t328" href="#t328">328</a></span><span class="t"><span class="str"> Advance to the next page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t329" href="#t329">329</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t330" href="#t330">330</a></span><span class="t"><span class="str"> If currently on the cover page, advances to the first content page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t331" href="#t331">331</a></span><span class="t"><span class="str"> Otherwise, advances to the next content page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t332" href="#t332">332</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t333" href="#t333">333</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t334" href="#t334">334</a></span><span class="t"><span class="str"> Next page or None if at end of document</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t335" href="#t335">335</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t336" href="#t336">336</a></span><span class="t"> <span class="com"># Special case: transitioning from cover to first content page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t337" href="#t337">337</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_on_cover_page</span> <span class="key">and</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_has_cover</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t338" href="#t338">338</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_on_cover_page</span> <span class="op">=</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t339" href="#t339">339</a></span><span class="t"> <span class="com"># If first block is an image (the cover), skip it and start from block 1</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t340" href="#t340">340</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span> <span class="key">and</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">,</span> <span class="nam">Image</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">340&#x202F;&#x219B;&#x202F;343</span><span class="annotate long">line 340 didn't jump to line 343 because the condition on line 340 was always true</span></span></p>
<p class="run"><span class="n"><a id="t341" href="#t341">341</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span> <span class="op">=</span> <span class="nam">RenderingPosition</span><span class="op">(</span><span class="nam">chapter_index</span><span class="op">=</span><span class="num">0</span><span class="op">,</span> <span class="nam">block_index</span><span class="op">=</span><span class="num">1</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t342" href="#t342">342</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t343" href="#t343">343</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span> <span class="op">=</span> <span class="nam">RenderingPosition</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t344" href="#t344">344</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_notify_position_changed</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t345" href="#t345">345</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_current_page</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t346" href="#t346">346</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t347" href="#t347">347</a></span><span class="t"> <span class="com"># Save current position to history before moving forward</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t348" href="#t348">348</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_add_to_history</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t349" href="#t349">349</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t350" href="#t350">350</a></span><span class="t"> <span class="nam">page</span><span class="op">,</span> <span class="nam">next_position</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">renderer</span><span class="op">.</span><span class="nam">render_page</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t351" href="#t351">351</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t352" href="#t352">352</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t353" href="#t353">353</a></span><span class="t"> <span class="com"># Check if we made progress</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t354" href="#t354">354</a></span><span class="t"> <span class="key">if</span> <span class="nam">next_position</span> <span class="op">!=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t355" href="#t355">355</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span> <span class="op">=</span> <span class="nam">next_position</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t356" href="#t356">356</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_notify_position_changed</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t357" href="#t357">357</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_current_page</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t358" href="#t358">358</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t359" href="#t359">359</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span> <span class="com"># At end of document</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t360" href="#t360">360</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t361" href="#t361">361</a></span><span class="t"> <span class="key">def</span> <span class="nam">previous_page</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Page</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t362" href="#t362">362</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t363" href="#t363">363</a></span><span class="t"><span class="str"> Go to the previous page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t364" href="#t364">364</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t365" href="#t365">365</a></span><span class="t"><span class="str"> Uses cached page history for instant navigation when available,</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t366" href="#t366">366</a></span><span class="t"><span class="str"> falls back to iterative refinement algorithm when needed.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t367" href="#t367">367</a></span><span class="t"><span class="str"> Can navigate back to the cover page if it exists.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t368" href="#t368">368</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t369" href="#t369">369</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t370" href="#t370">370</a></span><span class="t"><span class="str"> Previous page or None if at beginning of document (or on cover)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t371" href="#t371">371</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t372" href="#t372">372</a></span><span class="t"> <span class="com"># Special case: if at the beginning of content and there's a cover, go back to it</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t373" href="#t373">373</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_has_cover</span> <span class="key">and</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_is_at_beginning</span><span class="op">(</span><span class="op">)</span> <span class="key">and</span> <span class="key">not</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_on_cover_page</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t374" href="#t374">374</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_on_cover_page</span> <span class="op">=</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t375" href="#t375">375</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_notify_position_changed</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t376" href="#t376">376</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_current_page</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t377" href="#t377">377</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t378" href="#t378">378</a></span><span class="t"> <span class="com"># Can't go before the cover</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t379" href="#t379">379</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_on_cover_page</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">379&#x202F;&#x219B;&#x202F;380</span><span class="annotate long">line 379 didn't jump to line 380 because the condition on line 379 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t380" href="#t380">380</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t381" href="#t381">381</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t382" href="#t382">382</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_is_at_beginning</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t383" href="#t383">383</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t384" href="#t384">384</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t385" href="#t385">385</a></span><span class="t"> <span class="com"># Fast path: Check if we have this position in history</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t386" href="#t386">386</a></span><span class="t"> <span class="nam">previous_position</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_get_from_history</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t387" href="#t387">387</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t388" href="#t388">388</a></span><span class="t"> <span class="key">if</span> <span class="nam">previous_position</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t389" href="#t389">389</a></span><span class="t"> <span class="com"># Cache hit! Use the cached position for instant navigation</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t390" href="#t390">390</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span> <span class="op">=</span> <span class="nam">previous_position</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t391" href="#t391">391</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_notify_position_changed</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t392" href="#t392">392</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_current_page</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t393" href="#t393">393</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t394" href="#t394">394</a></span><span class="t"> <span class="com"># Slow path: Use backward rendering to find the previous page</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t395" href="#t395">395</a></span><span class="t"> <span class="com"># This uses the iterative refinement algorithm we just fixed</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t396" href="#t396">396</a></span><span class="t"> <span class="nam">page</span><span class="op">,</span> <span class="nam">start_position</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">renderer</span><span class="op">.</span><span class="nam">render_page_backward</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t397" href="#t397">397</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t398" href="#t398">398</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t399" href="#t399">399</a></span><span class="t"> <span class="key">if</span> <span class="nam">start_position</span> <span class="op">!=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">399&#x202F;&#x219B;&#x202F;407</span><span class="annotate long">line 399 didn't jump to line 407 because the condition on line 399 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t400" href="#t400">400</a></span><span class="t"> <span class="com"># Save this calculated position to history for future use</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t401" href="#t401">401</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_add_to_history</span><span class="op">(</span><span class="nam">start_position</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t402" href="#t402">402</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t403" href="#t403">403</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span> <span class="op">=</span> <span class="nam">start_position</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t404" href="#t404">404</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_notify_position_changed</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t405" href="#t405">405</a></span><span class="t"> <span class="key">return</span> <span class="nam">page</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t406" href="#t406">406</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t407" href="#t407">407</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span> <span class="com"># At beginning of document</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t408" href="#t408">408</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t409" href="#t409">409</a></span><span class="t"> <span class="key">def</span> <span class="nam">_is_at_beginning</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t410" href="#t410">410</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t411" href="#t411">411</a></span><span class="t"><span class="str"> Check if we're at the beginning of the document content.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t412" href="#t412">412</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t413" href="#t413">413</a></span><span class="t"><span class="str"> If a cover exists (first block is an Image), the beginning of content</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t414" href="#t414">414</a></span><span class="t"><span class="str"> is at block_index=1. Otherwise, it's at block_index=0.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t415" href="#t415">415</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t416" href="#t416">416</a></span><span class="t"> <span class="com"># Determine the first content block index</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t417" href="#t417">417</a></span><span class="t"> <span class="nam">first_content_block</span> <span class="op">=</span> <span class="num">1</span> <span class="key">if</span> <span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_has_cover</span> <span class="key">and</span> <span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span> <span class="key">and</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">,</span> <span class="nam">Image</span><span class="op">)</span><span class="op">)</span> <span class="key">else</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t418" href="#t418">418</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t419" href="#t419">419</a></span><span class="t"> <span class="key">return</span> <span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span><span class="op">.</span><span class="nam">chapter_index</span> <span class="op">==</span> <span class="num">0</span> <span class="key">and</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t420" href="#t420">420</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">==</span> <span class="nam">first_content_block</span> <span class="key">and</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t421" href="#t421">421</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span><span class="op">.</span><span class="nam">word_index</span> <span class="op">==</span> <span class="num">0</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t422" href="#t422">422</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t423" href="#t423">423</a></span><span class="t"> <span class="key">def</span> <span class="nam">jump_to_position</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Page</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t424" href="#t424">424</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t425" href="#t425">425</a></span><span class="t"><span class="str"> Jump to a specific position in the document.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t426" href="#t426">426</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t427" href="#t427">427</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t428" href="#t428">428</a></span><span class="t"><span class="str"> position: Position to jump to</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t429" href="#t429">429</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t430" href="#t430">430</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t431" href="#t431">431</a></span><span class="t"><span class="str"> Page at the new position</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t432" href="#t432">432</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t433" href="#t433">433</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span> <span class="op">=</span> <span class="nam">position</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t434" href="#t434">434</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_on_cover_page</span> <span class="op">=</span> <span class="key">False</span> <span class="com"># Jumping to a position means we're past the cover</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t435" href="#t435">435</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_notify_position_changed</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t436" href="#t436">436</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_current_page</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t437" href="#t437">437</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t438" href="#t438">438</a></span><span class="t"> <span class="key">def</span> <span class="nam">jump_to_chapter</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">chapter_title</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Page</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t439" href="#t439">439</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t440" href="#t440">440</a></span><span class="t"><span class="str"> Jump to a specific chapter by title.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t441" href="#t441">441</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t442" href="#t442">442</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t443" href="#t443">443</a></span><span class="t"><span class="str"> chapter_title: Title of the chapter to jump to</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t444" href="#t444">444</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t445" href="#t445">445</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t446" href="#t446">446</a></span><span class="t"><span class="str"> Page at chapter start or None if chapter not found</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t447" href="#t447">447</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t448" href="#t448">448</a></span><span class="t"> <span class="nam">position</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">chapter_navigator</span><span class="op">.</span><span class="nam">get_chapter_position</span><span class="op">(</span><span class="nam">chapter_title</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t449" href="#t449">449</a></span><span class="t"> <span class="key">if</span> <span class="nam">position</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t450" href="#t450">450</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">jump_to_position</span><span class="op">(</span><span class="nam">position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t451" href="#t451">451</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t452" href="#t452">452</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t453" href="#t453">453</a></span><span class="t"> <span class="key">def</span> <span class="nam">jump_to_chapter_index</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">chapter_index</span><span class="op">:</span> <span class="nam">int</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Page</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t454" href="#t454">454</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t455" href="#t455">455</a></span><span class="t"><span class="str"> Jump to a chapter by index.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t456" href="#t456">456</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t457" href="#t457">457</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t458" href="#t458">458</a></span><span class="t"><span class="str"> chapter_index: Index of the chapter (0-based)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t459" href="#t459">459</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t460" href="#t460">460</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t461" href="#t461">461</a></span><span class="t"><span class="str"> Page at chapter start or None if index invalid</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t462" href="#t462">462</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t463" href="#t463">463</a></span><span class="t"> <span class="nam">chapters</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">chapter_navigator</span><span class="op">.</span><span class="nam">chapters</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t464" href="#t464">464</a></span><span class="t"> <span class="key">if</span> <span class="num">0</span> <span class="op">&lt;=</span> <span class="nam">chapter_index</span> <span class="op">&lt;</span> <span class="nam">len</span><span class="op">(</span><span class="nam">chapters</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t465" href="#t465">465</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">jump_to_position</span><span class="op">(</span><span class="nam">chapters</span><span class="op">[</span><span class="nam">chapter_index</span><span class="op">]</span><span class="op">.</span><span class="nam">position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t466" href="#t466">466</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t467" href="#t467">467</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t468" href="#t468">468</a></span><span class="t"> <span class="key">def</span> <span class="nam">_add_to_history</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">:</span> <span class="nam">float</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t469" href="#t469">469</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t470" href="#t470">470</a></span><span class="t"><span class="str"> Add a page position to the navigation history.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t471" href="#t471">471</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t472" href="#t472">472</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t473" href="#t473">473</a></span><span class="t"><span class="str"> position: The page start position to remember</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t474" href="#t474">474</a></span><span class="t"><span class="str"> font_scale: The font scale at this position</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t475" href="#t475">475</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t476" href="#t476">476</a></span><span class="t"> <span class="com"># Only add if it's different from the last entry</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t477" href="#t477">477</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_page_history</span> <span class="key">or</span> <span class="xx">\</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t478" href="#t478">478</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_page_history</span><span class="op">[</span><span class="op">-</span><span class="num">1</span><span class="op">]</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">!=</span> <span class="nam">position</span> <span class="key">or</span> <span class="xx">\</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t479" href="#t479">479</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_page_history</span><span class="op">[</span><span class="op">-</span><span class="num">1</span><span class="op">]</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">!=</span> <span class="nam">font_scale</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t480" href="#t480">480</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t481" href="#t481">481</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_page_history</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="op">(</span><span class="nam">position</span><span class="op">.</span><span class="nam">copy</span><span class="op">(</span><span class="op">)</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t482" href="#t482">482</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t483" href="#t483">483</a></span><span class="t"> <span class="com"># Trim history if it exceeds max size</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t484" href="#t484">484</a></span><span class="t"> <span class="key">if</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_page_history</span><span class="op">)</span> <span class="op">></span> <span class="nam">self</span><span class="op">.</span><span class="nam">_max_history_size</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">484&#x202F;&#x219B;&#x202F;485</span><span class="annotate long">line 484 didn't jump to line 485 because the condition on line 484 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t485" href="#t485">485</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_page_history</span><span class="op">.</span><span class="nam">pop</span><span class="op">(</span><span class="num">0</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t486" href="#t486">486</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t487" href="#t487">487</a></span><span class="t"> <span class="key">def</span> <span class="nam">_get_from_history</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t488" href="#t488">488</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t489" href="#t489">489</a></span><span class="t"> <span class="nam">current_position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t490" href="#t490">490</a></span><span class="t"> <span class="nam">current_font_scale</span><span class="op">:</span> <span class="nam">float</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t491" href="#t491">491</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t492" href="#t492">492</a></span><span class="t"><span class="str"> Get the previous page position from history.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t493" href="#t493">493</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t494" href="#t494">494</a></span><span class="t"><span class="str"> Searches backward through history to find the last position that</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t495" href="#t495">495</a></span><span class="t"><span class="str"> comes before the current position at the same font scale.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t496" href="#t496">496</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t497" href="#t497">497</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t498" href="#t498">498</a></span><span class="t"><span class="str"> current_position: Current page position</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t499" href="#t499">499</a></span><span class="t"><span class="str"> current_font_scale: Current font scale</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t500" href="#t500">500</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t501" href="#t501">501</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t502" href="#t502">502</a></span><span class="t"><span class="str"> Previous page position or None if not found in history</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t503" href="#t503">503</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t504" href="#t504">504</a></span><span class="t"> <span class="com"># Search backward through history</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t505" href="#t505">505</a></span><span class="t"> <span class="key">for</span> <span class="nam">i</span> <span class="key">in</span> <span class="nam">range</span><span class="op">(</span><span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_page_history</span><span class="op">)</span> <span class="op">-</span> <span class="num">1</span><span class="op">,</span> <span class="op">-</span><span class="num">1</span><span class="op">,</span> <span class="op">-</span><span class="num">1</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t506" href="#t506">506</a></span><span class="t"> <span class="nam">hist_position</span><span class="op">,</span> <span class="nam">hist_font_scale</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_page_history</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t507" href="#t507">507</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t508" href="#t508">508</a></span><span class="t"> <span class="com"># Must match font scale</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t509" href="#t509">509</a></span><span class="t"> <span class="key">if</span> <span class="nam">hist_font_scale</span> <span class="op">!=</span> <span class="nam">current_font_scale</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">509&#x202F;&#x219B;&#x202F;510</span><span class="annotate long">line 509 didn't jump to line 510 because the condition on line 509 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t510" href="#t510">510</a></span><span class="t"> <span class="key">continue</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t511" href="#t511">511</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t512" href="#t512">512</a></span><span class="t"> <span class="com"># Must be before current position</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t513" href="#t513">513</a></span><span class="t"> <span class="key">if</span> <span class="op">(</span><span class="nam">hist_position</span><span class="op">.</span><span class="nam">chapter_index</span> <span class="op">&lt;</span> <span class="nam">current_position</span><span class="op">.</span><span class="nam">chapter_index</span> <span class="key">or</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t514" href="#t514">514</a></span><span class="t"> <span class="op">(</span><span class="nam">hist_position</span><span class="op">.</span><span class="nam">chapter_index</span> <span class="op">==</span> <span class="nam">current_position</span><span class="op">.</span><span class="nam">chapter_index</span> <span class="key">and</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t515" href="#t515">515</a></span><span class="t"> <span class="nam">hist_position</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">&lt;</span> <span class="nam">current_position</span><span class="op">.</span><span class="nam">block_index</span><span class="op">)</span> <span class="key">or</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t516" href="#t516">516</a></span><span class="t"> <span class="op">(</span><span class="nam">hist_position</span><span class="op">.</span><span class="nam">chapter_index</span> <span class="op">==</span> <span class="nam">current_position</span><span class="op">.</span><span class="nam">chapter_index</span> <span class="key">and</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t517" href="#t517">517</a></span><span class="t"> <span class="nam">hist_position</span><span class="op">.</span><span class="nam">block_index</span> <span class="op">==</span> <span class="nam">current_position</span><span class="op">.</span><span class="nam">block_index</span> <span class="key">and</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t518" href="#t518">518</a></span><span class="t"> <span class="nam">hist_position</span><span class="op">.</span><span class="nam">word_index</span> <span class="op">&lt;</span> <span class="nam">current_position</span><span class="op">.</span><span class="nam">word_index</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t519" href="#t519">519</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t520" href="#t520">520</a></span><span class="t"> <span class="com"># Found a previous position - remove it and everything after from history</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t521" href="#t521">521</a></span><span class="t"> <span class="com"># since we're navigating backward</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t522" href="#t522">522</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_page_history</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_page_history</span><span class="op">[</span><span class="op">:</span><span class="nam">i</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t523" href="#t523">523</a></span><span class="t"> <span class="key">return</span> <span class="nam">hist_position</span><span class="op">.</span><span class="nam">copy</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t524" href="#t524">524</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t525" href="#t525">525</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t526" href="#t526">526</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t527" href="#t527">527</a></span><span class="t"> <span class="key">def</span> <span class="nam">_clear_history</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t528" href="#t528">528</a></span><span class="t"> <span class="str">"""Clear the page navigation history."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t529" href="#t529">529</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_page_history</span><span class="op">.</span><span class="nam">clear</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t530" href="#t530">530</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t531" href="#t531">531</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_font_scale</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">scale</span><span class="op">:</span> <span class="nam">float</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Page</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t532" href="#t532">532</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t533" href="#t533">533</a></span><span class="t"><span class="str"> Change the font scale and re-render current page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t534" href="#t534">534</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t535" href="#t535">535</a></span><span class="t"><span class="str"> Clears page history since font changes invalidate all cached positions.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t536" href="#t536">536</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t537" href="#t537">537</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t538" href="#t538">538</a></span><span class="t"><span class="str"> scale: Font scaling factor (1.0 = normal, 2.0 = double size, etc.)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t539" href="#t539">539</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t540" href="#t540">540</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t541" href="#t541">541</a></span><span class="t"><span class="str"> Re-rendered page with new font scale</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t542" href="#t542">542</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t543" href="#t543">543</a></span><span class="t"> <span class="key">if</span> <span class="nam">scale</span> <span class="op">!=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">font_scale</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t544" href="#t544">544</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">font_scale</span> <span class="op">=</span> <span class="nam">scale</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t545" href="#t545">545</a></span><span class="t"> <span class="com"># Clear history since font scale changes invalidate all cached positions</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t546" href="#t546">546</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_clear_history</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t547" href="#t547">547</a></span><span class="t"> <span class="com"># The renderer will handle cache invalidation</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t548" href="#t548">548</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t549" href="#t549">549</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_current_page</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t550" href="#t550">550</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t551" href="#t551">551</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_font_scale</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">float</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t552" href="#t552">552</a></span><span class="t"> <span class="str">"""Get the current font scale"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t553" href="#t553">553</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">font_scale</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t554" href="#t554">554</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t555" href="#t555">555</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_font_family</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">family</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">BundledFont</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Page</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t556" href="#t556">556</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t557" href="#t557">557</a></span><span class="t"><span class="str"> Change the font family and re-render current page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t558" href="#t558">558</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t559" href="#t559">559</a></span><span class="t"><span class="str"> Switches all text in the document to use the specified bundled font family</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t560" href="#t560">560</a></span><span class="t"><span class="str"> while preserving font weights, styles, sizes, and other attributes.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t561" href="#t561">561</a></span><span class="t"><span class="str"> Clears page history and cache since font changes invalidate all cached positions.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t562" href="#t562">562</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t563" href="#t563">563</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t564" href="#t564">564</a></span><span class="t"><span class="str"> family: Bundled font family to use (SANS, SERIF, MONOSPACE, or None for original fonts)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t565" href="#t565">565</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t566" href="#t566">566</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t567" href="#t567">567</a></span><span class="t"><span class="str"> Re-rendered page with new font family</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t568" href="#t568">568</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t569" href="#t569">569</a></span><span class="t"><span class="str"> Example:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t570" href="#t570">570</a></span><span class="t"><span class="str"> >>> from pyWebLayout.style.fonts import BundledFont</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t571" href="#t571">571</a></span><span class="t"><span class="str"> >>> manager.set_font_family(BundledFont.SERIF) # Switch to serif</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t572" href="#t572">572</a></span><span class="t"><span class="str"> >>> manager.set_font_family(BundledFont.SANS) # Switch to sans</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t573" href="#t573">573</a></span><span class="t"><span class="str"> >>> manager.set_font_family(None) # Restore original fonts</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t574" href="#t574">574</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t575" href="#t575">575</a></span><span class="t"> <span class="com"># Update the renderer's font family</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t576" href="#t576">576</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">renderer</span><span class="op">.</span><span class="nam">set_font_family</span><span class="op">(</span><span class="nam">family</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t577" href="#t577">577</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t578" href="#t578">578</a></span><span class="t"> <span class="com"># Clear history since font changes invalidate all cached positions</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t579" href="#t579">579</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_clear_history</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t580" href="#t580">580</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t581" href="#t581">581</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_current_page</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t582" href="#t582">582</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t583" href="#t583">583</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_font_family</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">BundledFont</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t584" href="#t584">584</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t585" href="#t585">585</a></span><span class="t"><span class="str"> Get the current font family override.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t586" href="#t586">586</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t587" href="#t587">587</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t588" href="#t588">588</a></span><span class="t"><span class="str"> Current font family (SANS, SERIF, MONOSPACE) or None if using original fonts</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t589" href="#t589">589</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t590" href="#t590">590</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">renderer</span><span class="op">.</span><span class="nam">get_font_family</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t591" href="#t591">591</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t592" href="#t592">592</a></span><span class="t"> <span class="key">def</span> <span class="nam">increase_line_spacing</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">amount</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">2</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Page</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t593" href="#t593">593</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t594" href="#t594">594</a></span><span class="t"><span class="str"> Increase line spacing and re-render current page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t595" href="#t595">595</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t596" href="#t596">596</a></span><span class="t"><span class="str"> Clears page history since spacing changes invalidate all cached positions.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t597" href="#t597">597</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t598" href="#t598">598</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t599" href="#t599">599</a></span><span class="t"><span class="str"> amount: Pixels to add to line spacing (default: 2)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t600" href="#t600">600</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t601" href="#t601">601</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t602" href="#t602">602</a></span><span class="t"><span class="str"> Re-rendered page with increased line spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t603" href="#t603">603</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t604" href="#t604">604</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span><span class="op">.</span><span class="nam">line_spacing</span> <span class="op">+=</span> <span class="nam">amount</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t605" href="#t605">605</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">renderer</span><span class="op">.</span><span class="nam">page_style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span> <span class="com"># Update renderer's reference</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t606" href="#t606">606</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">renderer</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">invalidate_all</span><span class="op">(</span><span class="op">)</span> <span class="com"># Clear cache to force re-render</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t607" href="#t607">607</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_clear_history</span><span class="op">(</span><span class="op">)</span> <span class="com"># Clear position history</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t608" href="#t608">608</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_current_page</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t609" href="#t609">609</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t610" href="#t610">610</a></span><span class="t"> <span class="key">def</span> <span class="nam">decrease_line_spacing</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">amount</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">2</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Page</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t611" href="#t611">611</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t612" href="#t612">612</a></span><span class="t"><span class="str"> Decrease line spacing and re-render current page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t613" href="#t613">613</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t614" href="#t614">614</a></span><span class="t"><span class="str"> Clears page history since spacing changes invalidate all cached positions.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t615" href="#t615">615</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t616" href="#t616">616</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t617" href="#t617">617</a></span><span class="t"><span class="str"> amount: Pixels to remove from line spacing (default: 2)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t618" href="#t618">618</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t619" href="#t619">619</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t620" href="#t620">620</a></span><span class="t"><span class="str"> Re-rendered page with decreased line spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t621" href="#t621">621</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t622" href="#t622">622</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span><span class="op">.</span><span class="nam">line_spacing</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span><span class="op">.</span><span class="nam">line_spacing</span> <span class="op">-</span> <span class="nam">amount</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t623" href="#t623">623</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">renderer</span><span class="op">.</span><span class="nam">page_style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span> <span class="com"># Update renderer's reference</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t624" href="#t624">624</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">renderer</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">invalidate_all</span><span class="op">(</span><span class="op">)</span> <span class="com"># Clear cache to force re-render</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t625" href="#t625">625</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_clear_history</span><span class="op">(</span><span class="op">)</span> <span class="com"># Clear position history</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t626" href="#t626">626</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_current_page</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t627" href="#t627">627</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t628" href="#t628">628</a></span><span class="t"> <span class="key">def</span> <span class="nam">increase_inter_block_spacing</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">amount</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">5</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Page</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t629" href="#t629">629</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t630" href="#t630">630</a></span><span class="t"><span class="str"> Increase spacing between blocks and re-render current page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t631" href="#t631">631</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t632" href="#t632">632</a></span><span class="t"><span class="str"> Clears page history since spacing changes invalidate all cached positions.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t633" href="#t633">633</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t634" href="#t634">634</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t635" href="#t635">635</a></span><span class="t"><span class="str"> amount: Pixels to add to inter-block spacing (default: 5)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t636" href="#t636">636</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t637" href="#t637">637</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t638" href="#t638">638</a></span><span class="t"><span class="str"> Re-rendered page with increased block spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t639" href="#t639">639</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t640" href="#t640">640</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span><span class="op">.</span><span class="nam">inter_block_spacing</span> <span class="op">+=</span> <span class="nam">amount</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t641" href="#t641">641</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">renderer</span><span class="op">.</span><span class="nam">page_style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span> <span class="com"># Update renderer's reference</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t642" href="#t642">642</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">renderer</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">invalidate_all</span><span class="op">(</span><span class="op">)</span> <span class="com"># Clear cache to force re-render</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t643" href="#t643">643</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_clear_history</span><span class="op">(</span><span class="op">)</span> <span class="com"># Clear position history</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t644" href="#t644">644</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_current_page</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t645" href="#t645">645</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t646" href="#t646">646</a></span><span class="t"> <span class="key">def</span> <span class="nam">decrease_inter_block_spacing</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">amount</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">5</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Page</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t647" href="#t647">647</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t648" href="#t648">648</a></span><span class="t"><span class="str"> Decrease spacing between blocks and re-render current page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t649" href="#t649">649</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t650" href="#t650">650</a></span><span class="t"><span class="str"> Clears page history since spacing changes invalidate all cached positions.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t651" href="#t651">651</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t652" href="#t652">652</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t653" href="#t653">653</a></span><span class="t"><span class="str"> amount: Pixels to remove from inter-block spacing (default: 5)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t654" href="#t654">654</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t655" href="#t655">655</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t656" href="#t656">656</a></span><span class="t"><span class="str"> Re-rendered page with decreased block spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t657" href="#t657">657</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t658" href="#t658">658</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span><span class="op">.</span><span class="nam">inter_block_spacing</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t659" href="#t659">659</a></span><span class="t"> <span class="num">0</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span><span class="op">.</span><span class="nam">inter_block_spacing</span> <span class="op">-</span> <span class="nam">amount</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t660" href="#t660">660</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">renderer</span><span class="op">.</span><span class="nam">page_style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span> <span class="com"># Update renderer's reference</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t661" href="#t661">661</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">renderer</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">invalidate_all</span><span class="op">(</span><span class="op">)</span> <span class="com"># Clear cache to force re-render</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t662" href="#t662">662</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_clear_history</span><span class="op">(</span><span class="op">)</span> <span class="com"># Clear position history</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t663" href="#t663">663</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_current_page</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t664" href="#t664">664</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t665" href="#t665">665</a></span><span class="t"> <span class="key">def</span> <span class="nam">increase_word_spacing</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">amount</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">2</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Page</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t666" href="#t666">666</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t667" href="#t667">667</a></span><span class="t"><span class="str"> Increase spacing between words and re-render current page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t668" href="#t668">668</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t669" href="#t669">669</a></span><span class="t"><span class="str"> Clears page history since spacing changes invalidate all cached positions.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t670" href="#t670">670</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t671" href="#t671">671</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t672" href="#t672">672</a></span><span class="t"><span class="str"> amount: Pixels to add to word spacing (default: 2)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t673" href="#t673">673</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t674" href="#t674">674</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t675" href="#t675">675</a></span><span class="t"><span class="str"> Re-rendered page with increased word spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t676" href="#t676">676</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t677" href="#t677">677</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span><span class="op">.</span><span class="nam">word_spacing</span> <span class="op">+=</span> <span class="nam">amount</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t678" href="#t678">678</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">renderer</span><span class="op">.</span><span class="nam">page_style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span> <span class="com"># Update renderer's reference</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t679" href="#t679">679</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">renderer</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">invalidate_all</span><span class="op">(</span><span class="op">)</span> <span class="com"># Clear cache to force re-render</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t680" href="#t680">680</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_clear_history</span><span class="op">(</span><span class="op">)</span> <span class="com"># Clear position history</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t681" href="#t681">681</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_current_page</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t682" href="#t682">682</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t683" href="#t683">683</a></span><span class="t"> <span class="key">def</span> <span class="nam">decrease_word_spacing</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">amount</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">2</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Page</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t684" href="#t684">684</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t685" href="#t685">685</a></span><span class="t"><span class="str"> Decrease spacing between words and re-render current page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t686" href="#t686">686</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t687" href="#t687">687</a></span><span class="t"><span class="str"> Clears page history since spacing changes invalidate all cached positions.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t688" href="#t688">688</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t689" href="#t689">689</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t690" href="#t690">690</a></span><span class="t"><span class="str"> amount: Pixels to remove from word spacing (default: 2)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t691" href="#t691">691</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t692" href="#t692">692</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t693" href="#t693">693</a></span><span class="t"><span class="str"> Re-rendered page with decreased word spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t694" href="#t694">694</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t695" href="#t695">695</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span><span class="op">.</span><span class="nam">word_spacing</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span><span class="op">.</span><span class="nam">word_spacing</span> <span class="op">-</span> <span class="nam">amount</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t696" href="#t696">696</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">renderer</span><span class="op">.</span><span class="nam">page_style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span> <span class="com"># Update renderer's reference</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t697" href="#t697">697</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">renderer</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">invalidate_all</span><span class="op">(</span><span class="op">)</span> <span class="com"># Clear cache to force re-render</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t698" href="#t698">698</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_clear_history</span><span class="op">(</span><span class="op">)</span> <span class="com"># Clear position history</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t699" href="#t699">699</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_current_page</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t700" href="#t700">700</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t701" href="#t701">701</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_table_of_contents</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t702" href="#t702">702</a></span><span class="t"> <span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">Tuple</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">HeadingLevel</span><span class="op">,</span> <span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t703" href="#t703">703</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t704" href="#t704">704</a></span><span class="t"><span class="str"> Get the table of contents.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t705" href="#t705">705</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t706" href="#t706">706</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t707" href="#t707">707</a></span><span class="t"><span class="str"> List of (title, level, position) tuples</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t708" href="#t708">708</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t709" href="#t709">709</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">chapter_navigator</span><span class="op">.</span><span class="nam">get_table_of_contents</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t710" href="#t710">710</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t711" href="#t711">711</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_current_chapter</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">ChapterInfo</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t712" href="#t712">712</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t713" href="#t713">713</a></span><span class="t"><span class="str"> Get information about the current chapter.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t714" href="#t714">714</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t715" href="#t715">715</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t716" href="#t716">716</a></span><span class="t"><span class="str"> Current chapter info or None if no chapters</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t717" href="#t717">717</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t718" href="#t718">718</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">chapter_navigator</span><span class="op">.</span><span class="nam">get_current_chapter</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t719" href="#t719">719</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t720" href="#t720">720</a></span><span class="t"> <span class="key">def</span> <span class="nam">add_bookmark</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">name</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t721" href="#t721">721</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t722" href="#t722">722</a></span><span class="t"><span class="str"> Add a bookmark at the current position.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t723" href="#t723">723</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t724" href="#t724">724</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t725" href="#t725">725</a></span><span class="t"><span class="str"> name: Bookmark name</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t726" href="#t726">726</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t727" href="#t727">727</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t728" href="#t728">728</a></span><span class="t"><span class="str"> True if bookmark was added successfully</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t729" href="#t729">729</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t730" href="#t730">730</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t731" href="#t731">731</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">bookmark_manager</span><span class="op">.</span><span class="nam">add_bookmark</span><span class="op">(</span><span class="nam">name</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t732" href="#t732">732</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t733" href="#t733">733</a></span><span class="t"> <span class="key">except</span> <span class="nam">Exception</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t734" href="#t734">734</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t735" href="#t735">735</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t736" href="#t736">736</a></span><span class="t"> <span class="key">def</span> <span class="nam">remove_bookmark</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">name</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t737" href="#t737">737</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t738" href="#t738">738</a></span><span class="t"><span class="str"> Remove a bookmark.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t739" href="#t739">739</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t740" href="#t740">740</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t741" href="#t741">741</a></span><span class="t"><span class="str"> name: Bookmark name</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t742" href="#t742">742</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t743" href="#t743">743</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t744" href="#t744">744</a></span><span class="t"><span class="str"> True if bookmark was removed</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t745" href="#t745">745</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t746" href="#t746">746</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">bookmark_manager</span><span class="op">.</span><span class="nam">remove_bookmark</span><span class="op">(</span><span class="nam">name</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t747" href="#t747">747</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t748" href="#t748">748</a></span><span class="t"> <span class="key">def</span> <span class="nam">jump_to_bookmark</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">name</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Page</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t749" href="#t749">749</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t750" href="#t750">750</a></span><span class="t"><span class="str"> Jump to a bookmark.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t751" href="#t751">751</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t752" href="#t752">752</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t753" href="#t753">753</a></span><span class="t"><span class="str"> name: Bookmark name</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t754" href="#t754">754</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t755" href="#t755">755</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t756" href="#t756">756</a></span><span class="t"><span class="str"> Page at bookmark position or None if bookmark not found</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t757" href="#t757">757</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t758" href="#t758">758</a></span><span class="t"> <span class="nam">position</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">bookmark_manager</span><span class="op">.</span><span class="nam">get_bookmark</span><span class="op">(</span><span class="nam">name</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t759" href="#t759">759</a></span><span class="t"> <span class="key">if</span> <span class="nam">position</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t760" href="#t760">760</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">jump_to_position</span><span class="op">(</span><span class="nam">position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t761" href="#t761">761</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t762" href="#t762">762</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t763" href="#t763">763</a></span><span class="t"> <span class="key">def</span> <span class="nam">list_bookmarks</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">Tuple</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t764" href="#t764">764</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t765" href="#t765">765</a></span><span class="t"><span class="str"> Get all bookmarks.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t766" href="#t766">766</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t767" href="#t767">767</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t768" href="#t768">768</a></span><span class="t"><span class="str"> List of (name, position) tuples</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t769" href="#t769">769</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t770" href="#t770">770</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">bookmark_manager</span><span class="op">.</span><span class="nam">list_bookmarks</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t771" href="#t771">771</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t772" href="#t772">772</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_reading_progress</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">float</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t773" href="#t773">773</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t774" href="#t774">774</a></span><span class="t"><span class="str"> Get reading progress as a percentage.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t775" href="#t775">775</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t776" href="#t776">776</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t777" href="#t777">777</a></span><span class="t"><span class="str"> Progress from 0.0 to 1.0</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t778" href="#t778">778</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t779" href="#t779">779</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t780" href="#t780">780</a></span><span class="t"> <span class="key">return</span> <span class="num">0.0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t781" href="#t781">781</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t782" href="#t782">782</a></span><span class="t"> <span class="com"># Simple progress calculation based on block index</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t783" href="#t783">783</a></span><span class="t"> <span class="com"># A more sophisticated version would consider word positions</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t784" href="#t784">784</a></span><span class="t"> <span class="nam">total_blocks</span> <span class="op">=</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t785" href="#t785">785</a></span><span class="t"> <span class="nam">current_block</span> <span class="op">=</span> <span class="nam">min</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span><span class="op">.</span><span class="nam">block_index</span><span class="op">,</span> <span class="nam">total_blocks</span> <span class="op">-</span> <span class="num">1</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t786" href="#t786">786</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t787" href="#t787">787</a></span><span class="t"> <span class="key">return</span> <span class="nam">current_block</span> <span class="op">/</span> <span class="nam">max</span><span class="op">(</span><span class="num">1</span><span class="op">,</span> <span class="nam">total_blocks</span> <span class="op">-</span> <span class="num">1</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t788" href="#t788">788</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t789" href="#t789">789</a></span><span class="t"> <span class="key">def</span> <span class="nam">has_cover</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t790" href="#t790">790</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t791" href="#t791">791</a></span><span class="t"><span class="str"> Check if the document has a cover page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t792" href="#t792">792</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t793" href="#t793">793</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t794" href="#t794">794</a></span><span class="t"><span class="str"> True if a cover page is available</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t795" href="#t795">795</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t796" href="#t796">796</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_has_cover</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t797" href="#t797">797</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t798" href="#t798">798</a></span><span class="t"> <span class="key">def</span> <span class="nam">is_on_cover</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t799" href="#t799">799</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t800" href="#t800">800</a></span><span class="t"><span class="str"> Check if currently viewing the cover page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t801" href="#t801">801</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t802" href="#t802">802</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t803" href="#t803">803</a></span><span class="t"><span class="str"> True if on the cover page</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t804" href="#t804">804</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t805" href="#t805">805</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_on_cover_page</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t806" href="#t806">806</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t807" href="#t807">807</a></span><span class="t"> <span class="key">def</span> <span class="nam">jump_to_cover</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Page</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t808" href="#t808">808</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t809" href="#t809">809</a></span><span class="t"><span class="str"> Jump to the cover page if one exists.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t810" href="#t810">810</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t811" href="#t811">811</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t812" href="#t812">812</a></span><span class="t"><span class="str"> Cover page or None if no cover exists</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t813" href="#t813">813</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t814" href="#t814">814</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_has_cover</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">814&#x202F;&#x219B;&#x202F;815</span><span class="annotate long">line 814 didn't jump to line 815 because the condition on line 814 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t815" href="#t815">815</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t816" href="#t816">816</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t817" href="#t817">817</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_on_cover_page</span> <span class="op">=</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t818" href="#t818">818</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_notify_position_changed</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t819" href="#t819">819</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_current_page</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t820" href="#t820">820</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t821" href="#t821">821</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_position_info</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t822" href="#t822">822</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t823" href="#t823">823</a></span><span class="t"><span class="str"> Get detailed information about the current position.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t824" href="#t824">824</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t825" href="#t825">825</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t826" href="#t826">826</a></span><span class="t"><span class="str"> Dictionary with position details</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t827" href="#t827">827</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t828" href="#t828">828</a></span><span class="t"> <span class="nam">current_chapter</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_current_chapter</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t829" href="#t829">829</a></span><span class="t"> <span class="nam">font_family</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_font_family</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t830" href="#t830">830</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t831" href="#t831">831</a></span><span class="t"> <span class="key">return</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t832" href="#t832">832</a></span><span class="t"> <span class="str">'position'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span><span class="op">.</span><span class="nam">to_dict</span><span class="op">(</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t833" href="#t833">833</a></span><span class="t"> <span class="str">'on_cover'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_on_cover_page</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t834" href="#t834">834</a></span><span class="t"> <span class="str">'has_cover'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_has_cover</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t835" href="#t835">835</a></span><span class="t"> <span class="str">'chapter'</span><span class="op">:</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t836" href="#t836">836</a></span><span class="t"> <span class="str">'title'</span><span class="op">:</span> <span class="nam">current_chapter</span><span class="op">.</span><span class="nam">title</span> <span class="key">if</span> <span class="nam">current_chapter</span> <span class="key">else</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t837" href="#t837">837</a></span><span class="t"> <span class="str">'level'</span><span class="op">:</span> <span class="nam">current_chapter</span><span class="op">.</span><span class="nam">level</span> <span class="key">if</span> <span class="nam">current_chapter</span> <span class="key">else</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t838" href="#t838">838</a></span><span class="t"> <span class="str">'index'</span><span class="op">:</span> <span class="nam">current_chapter</span><span class="op">.</span><span class="nam">block_index</span> <span class="key">if</span> <span class="nam">current_chapter</span> <span class="key">else</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t839" href="#t839">839</a></span><span class="t"> <span class="op">}</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t840" href="#t840">840</a></span><span class="t"> <span class="str">'progress'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_reading_progress</span><span class="op">(</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t841" href="#t841">841</a></span><span class="t"> <span class="str">'font_scale'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">font_scale</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t842" href="#t842">842</a></span><span class="t"> <span class="str">'font_family'</span><span class="op">:</span> <span class="nam">font_family</span><span class="op">.</span><span class="nam">value</span> <span class="key">if</span> <span class="nam">font_family</span> <span class="key">else</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t843" href="#t843">843</a></span><span class="t"> <span class="str">'page_size'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page_size</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t844" href="#t844">844</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t845" href="#t845">845</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t846" href="#t846">846</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_cache_stats</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t847" href="#t847">847</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t848" href="#t848">848</a></span><span class="t"><span class="str"> Get cache statistics for debugging/monitoring.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t849" href="#t849">849</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t850" href="#t850">850</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t851" href="#t851">851</a></span><span class="t"><span class="str"> Dictionary with cache statistics</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t852" href="#t852">852</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t853" href="#t853">853</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">renderer</span><span class="op">.</span><span class="nam">get_cache_stats</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t854" href="#t854">854</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t855" href="#t855">855</a></span><span class="t"> <span class="key">def</span> <span class="nam">shutdown</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t856" href="#t856">856</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t857" href="#t857">857</a></span><span class="t"><span class="str"> Shutdown the ereader manager and clean up resources.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t858" href="#t858">858</a></span><span class="t"><span class="str"> Call this when the application is closing.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t859" href="#t859">859</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t860" href="#t860">860</a></span><span class="t"> <span class="com"># Save current position</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t861" href="#t861">861</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">bookmark_manager</span><span class="op">.</span><span class="nam">save_reading_position</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t862" href="#t862">862</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t863" href="#t863">863</a></span><span class="t"> <span class="com"># Shutdown renderer and buffer</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t864" href="#t864">864</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">renderer</span><span class="op">.</span><span class="nam">shutdown</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t865" href="#t865">865</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t866" href="#t866">866</a></span><span class="t"> <span class="key">def</span> <span class="nam">__del__</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t867" href="#t867">867</a></span><span class="t"> <span class="str">"""Cleanup on destruction"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t868" href="#t868">868</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">shutdown</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t869" href="#t869">869</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t870" href="#t870">870</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t871" href="#t871">871</a></span><span class="t"><span class="com"># Convenience function for quick setup</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t872" href="#t872">872</a></span><span class="t"><span class="key">def</span> <span class="nam">create_ereader_manager</span><span class="op">(</span><span class="nam">blocks</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">Block</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t873" href="#t873">873</a></span><span class="t"> <span class="nam">page_size</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t874" href="#t874">874</a></span><span class="t"> <span class="nam">document_id</span><span class="op">:</span> <span class="nam">str</span> <span class="op">=</span> <span class="str">"default"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t875" href="#t875">875</a></span><span class="t"> <span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span> <span class="op">-></span> <span class="nam">EreaderLayoutManager</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t876" href="#t876">876</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t877" href="#t877">877</a></span><span class="t"><span class="str"> Convenience function to create an ereader manager with sensible defaults.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t878" href="#t878">878</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t879" href="#t879">879</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t880" href="#t880">880</a></span><span class="t"><span class="str"> blocks: Document blocks to render</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t881" href="#t881">881</a></span><span class="t"><span class="str"> page_size: Page size (width, height) in pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t882" href="#t882">882</a></span><span class="t"><span class="str"> document_id: Unique identifier for the document</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t883" href="#t883">883</a></span><span class="t"><span class="str"> **kwargs: Additional arguments passed to EreaderLayoutManager</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t884" href="#t884">884</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t885" href="#t885">885</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t886" href="#t886">886</a></span><span class="t"><span class="str"> Configured EreaderLayoutManager instance</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t887" href="#t887">887</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t888" href="#t888">888</a></span><span class="t"> <span class="key">return</span> <span class="nam">EreaderLayoutManager</span><span class="op">(</span><span class="nam">blocks</span><span class="op">,</span> <span class="nam">page_size</span><span class="op">,</span> <span class="nam">document_id</span><span class="op">,</span> <span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_427cc3035faf7633_ereader_layout_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_427cc3035faf7633_page_buffer_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,619 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/layout/page_buffer.py: 83%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/layout/page_buffer.py</b>:
<span class="pc_cov">83%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">195 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">168<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">27<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">25<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">9<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_427cc3035faf7633_ereader_manager_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_427cc3035faf7633_table_optimizer_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">Multi-process page buffering system for high-performance ereader navigation.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">This module provides intelligent page caching with background rendering using</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">multiprocessing to achieve sub-second page navigation performance.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="key">from</span> <span class="nam">__future__</span> <span class="key">import</span> <span class="nam">annotations</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">Dict</span><span class="op">,</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">List</span><span class="op">,</span> <span class="nam">Tuple</span><span class="op">,</span> <span class="nam">Any</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="key">from</span> <span class="nam">collections</span> <span class="key">import</span> <span class="nam">OrderedDict</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="key">from</span> <span class="nam">concurrent</span><span class="op">.</span><span class="nam">futures</span> <span class="key">import</span> <span class="nam">ProcessPoolExecutor</span><span class="op">,</span> <span class="nam">Future</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="key">import</span> <span class="nam">threading</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"><span class="key">import</span> <span class="nam">pickle</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">ereader_layout</span> <span class="key">import</span> <span class="nam">RenderingPosition</span><span class="op">,</span> <span class="nam">BidirectionalLayouter</span><span class="op">,</span> <span class="nam">FontFamilyOverride</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span><span class="op">.</span><span class="nam">page</span> <span class="key">import</span> <span class="nam">Page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">block</span> <span class="key">import</span> <span class="nam">Block</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">page_style</span> <span class="key">import</span> <span class="nam">PageStyle</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">fonts</span> <span class="key">import</span> <span class="nam">BundledFont</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"><span class="key">def</span> <span class="nam">_render_page_worker</span><span class="op">(</span><span class="nam">args</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">List</span><span class="op">[</span><span class="nam">Block</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"> <span class="nam">PageStyle</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"> <span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"> <span class="nam">float</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"> <span class="nam">bool</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"> <span class="nam">Optional</span><span class="op">[</span><span class="nam">BundledFont</span><span class="op">]</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t"> <span class="nam">bytes</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"> <span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"><span class="str"> Worker function for multiprocess page rendering.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"><span class="str"> args: Tuple of (blocks, page_style, position, font_scale, is_backward, font_family)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"><span class="str"> Tuple of (original_position, pickled_page, next_position)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"> <span class="nam">blocks</span><span class="op">,</span> <span class="nam">page_style</span><span class="op">,</span> <span class="nam">position</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">,</span> <span class="nam">is_backward</span><span class="op">,</span> <span class="nam">font_family</span> <span class="op">=</span> <span class="nam">args</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t"> <span class="com"># Create font family override if specified</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t"> <span class="nam">font_family_override</span> <span class="op">=</span> <span class="nam">FontFamilyOverride</span><span class="op">(</span><span class="nam">font_family</span><span class="op">)</span> <span class="key">if</span> <span class="nam">font_family</span> <span class="key">else</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"> <span class="nam">layouter</span> <span class="op">=</span> <span class="nam">BidirectionalLayouter</span><span class="op">(</span><span class="nam">blocks</span><span class="op">,</span> <span class="nam">page_style</span><span class="op">,</span> <span class="nam">font_family_override</span><span class="op">=</span><span class="nam">font_family_override</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"> <span class="key">if</span> <span class="nam">is_backward</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"> <span class="nam">page</span><span class="op">,</span> <span class="nam">next_pos</span> <span class="op">=</span> <span class="nam">layouter</span><span class="op">.</span><span class="nam">render_page_backward</span><span class="op">(</span><span class="nam">position</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t"> <span class="nam">page</span><span class="op">,</span> <span class="nam">next_pos</span> <span class="op">=</span> <span class="nam">layouter</span><span class="op">.</span><span class="nam">render_page_forward</span><span class="op">(</span><span class="nam">position</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t"> <span class="com"># Serialize the page for inter-process communication</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t"> <span class="nam">pickled_page</span> <span class="op">=</span> <span class="nam">pickle</span><span class="op">.</span><span class="nam">dumps</span><span class="op">(</span><span class="nam">page</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t"> <span class="key">return</span> <span class="nam">position</span><span class="op">,</span> <span class="nam">pickled_page</span><span class="op">,</span> <span class="nam">next_pos</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t"><span class="key">class</span> <span class="nam">PageBuffer</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"><span class="str"> Intelligent page caching system with LRU eviction and background rendering.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"><span class="str"> Maintains separate forward and backward buffers for optimal navigation performance.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">buffer_size</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">5</span><span class="op">,</span> <span class="nam">max_workers</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">4</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"><span class="str"> Initialize the page buffer.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"><span class="str"> buffer_size: Number of pages to cache in each direction</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"><span class="str"> max_workers: Maximum number of worker processes for background rendering</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer_size</span> <span class="op">=</span> <span class="nam">buffer_size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">max_workers</span> <span class="op">=</span> <span class="nam">max_workers</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t"> <span class="com"># LRU caches for forward and backward pages</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">forward_buffer</span><span class="op">:</span> <span class="nam">OrderedDict</span><span class="op">[</span><span class="nam">RenderingPosition</span><span class="op">,</span> <span class="nam">Page</span><span class="op">]</span> <span class="op">=</span> <span class="nam">OrderedDict</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">backward_buffer</span><span class="op">:</span> <span class="nam">OrderedDict</span><span class="op">[</span><span class="nam">RenderingPosition</span><span class="op">,</span> <span class="nam">Page</span><span class="op">]</span> <span class="op">=</span> <span class="nam">OrderedDict</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"> <span class="com"># Position tracking for next/previous positions</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">position_map</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t"> <span class="nam">RenderingPosition</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span> <span class="com"># current -> next</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">reverse_position_map</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t"> <span class="nam">RenderingPosition</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span> <span class="com"># current -> previous</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"> <span class="com"># Background rendering</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">executor</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">ProcessPoolExecutor</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">pending_renders</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">RenderingPosition</span><span class="op">,</span> <span class="nam">Future</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">render_lock</span> <span class="op">=</span> <span class="nam">threading</span><span class="op">.</span><span class="nam">Lock</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"> <span class="com"># Document state</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">List</span><span class="op">[</span><span class="nam">Block</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">PageStyle</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_font_scale</span><span class="op">:</span> <span class="nam">float</span> <span class="op">=</span> <span class="num">1.0</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_font_family</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">BundledFont</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t"> <span class="key">def</span> <span class="nam">initialize</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t"> <span class="nam">blocks</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">Block</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t"> <span class="nam">page_style</span><span class="op">:</span> <span class="nam">PageStyle</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"> <span class="nam">font_scale</span><span class="op">:</span> <span class="nam">float</span> <span class="op">=</span> <span class="num">1.0</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t"> <span class="nam">font_family</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">BundledFont</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"><span class="str"> Initialize the buffer with document blocks and page style.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t"><span class="str"> blocks: Document blocks to render</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t"><span class="str"> page_style: Page styling configuration</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t"><span class="str"> font_scale: Current font scaling factor</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t"><span class="str"> font_family: Optional font family override</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span> <span class="op">=</span> <span class="nam">blocks</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span> <span class="op">=</span> <span class="nam">page_style</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_font_scale</span> <span class="op">=</span> <span class="nam">font_scale</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_font_family</span> <span class="op">=</span> <span class="nam">font_family</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t"> <span class="com"># Start the process pool</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">executor</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">116&#x202F;&#x219B;&#x202F;exit</span><span class="annotate long">line 116 didn't return from function 'initialize' because the condition on line 116 was always true</span></span></p>
<p class="run"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">executor</span> <span class="op">=</span> <span class="nam">ProcessPoolExecutor</span><span class="op">(</span><span class="nam">max_workers</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">max_workers</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_page</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Page</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t"><span class="str"> Get a cached page if available.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t"><span class="str"> position: Position to get page for</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t"><span class="str"> Cached page or None if not available</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t"> <span class="com"># Check forward buffer first</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t"> <span class="key">if</span> <span class="nam">position</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">forward_buffer</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t"> <span class="com"># Move to end (most recently used)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t"> <span class="nam">page</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">forward_buffer</span><span class="op">.</span><span class="nam">pop</span><span class="op">(</span><span class="nam">position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">forward_buffer</span><span class="op">[</span><span class="nam">position</span><span class="op">]</span> <span class="op">=</span> <span class="nam">page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t"> <span class="key">return</span> <span class="nam">page</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"> <span class="com"># Check backward buffer</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t"> <span class="key">if</span> <span class="nam">position</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">backward_buffer</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"> <span class="com"># Move to end (most recently used)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t"> <span class="nam">page</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">backward_buffer</span><span class="op">.</span><span class="nam">pop</span><span class="op">(</span><span class="nam">position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">backward_buffer</span><span class="op">[</span><span class="nam">position</span><span class="op">]</span> <span class="op">=</span> <span class="nam">page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t"> <span class="key">return</span> <span class="nam">page</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t"> <span class="key">def</span> <span class="nam">cache_page</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"> <span class="nam">position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"> <span class="nam">page</span><span class="op">:</span> <span class="nam">Page</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t"> <span class="nam">next_position</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">RenderingPosition</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t"> <span class="nam">is_backward</span><span class="op">:</span> <span class="nam">bool</span> <span class="op">=</span> <span class="key">False</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t"><span class="str"> Cache a rendered page with LRU eviction.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t"><span class="str"> position: Position of the page</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t"><span class="str"> page: Rendered page to cache</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t"><span class="str"> next_position: Position of the next page (for forward navigation)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t"><span class="str"> is_backward: Whether this is a backward-rendered page</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"> <span class="nam">target_buffer</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">backward_buffer</span> <span class="key">if</span> <span class="nam">is_backward</span> <span class="key">else</span> <span class="nam">self</span><span class="op">.</span><span class="nam">forward_buffer</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t"> <span class="com"># Add to cache</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"> <span class="nam">target_buffer</span><span class="op">[</span><span class="nam">position</span><span class="op">]</span> <span class="op">=</span> <span class="nam">page</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t"> <span class="com"># Track position relationships</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"> <span class="key">if</span> <span class="nam">next_position</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">166&#x202F;&#x219B;&#x202F;173</span><span class="annotate long">line 166 didn't jump to line 173 because the condition on line 166 was always true</span></span></p>
<p class="run"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t"> <span class="key">if</span> <span class="nam">is_backward</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">reverse_position_map</span><span class="op">[</span><span class="nam">next_position</span><span class="op">]</span> <span class="op">=</span> <span class="nam">position</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">position_map</span><span class="op">[</span><span class="nam">position</span><span class="op">]</span> <span class="op">=</span> <span class="nam">next_position</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t"> <span class="com"># Evict oldest if buffer is full</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t"> <span class="key">if</span> <span class="nam">len</span><span class="op">(</span><span class="nam">target_buffer</span><span class="op">)</span> <span class="op">></span> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer_size</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t"> <span class="nam">oldest_pos</span><span class="op">,</span> <span class="nam">_</span> <span class="op">=</span> <span class="nam">target_buffer</span><span class="op">.</span><span class="nam">popitem</span><span class="op">(</span><span class="nam">last</span><span class="op">=</span><span class="key">False</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t"> <span class="com"># Clean up position maps</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">position_map</span><span class="op">.</span><span class="nam">pop</span><span class="op">(</span><span class="nam">oldest_pos</span><span class="op">,</span> <span class="key">None</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">reverse_position_map</span><span class="op">.</span><span class="nam">pop</span><span class="op">(</span><span class="nam">oldest_pos</span><span class="op">,</span> <span class="key">None</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t"> <span class="key">def</span> <span class="nam">start_background_rendering</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t"> <span class="nam">current_position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t"> <span class="nam">direction</span><span class="op">:</span> <span class="nam">str</span> <span class="op">=</span> <span class="str">'forward'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t"><span class="str"> Start background rendering of upcoming pages.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t"><span class="str"> current_position: Current reading position</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t"><span class="str"> direction: 'forward', 'backward', or 'both'</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span> <span class="key">or</span> <span class="key">not</span> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span> <span class="key">or</span> <span class="key">not</span> <span class="nam">self</span><span class="op">.</span><span class="nam">executor</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">190&#x202F;&#x219B;&#x202F;191</span><span class="annotate long">line 190 didn't jump to line 191 because the condition on line 190 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t"> <span class="key">return</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t"> <span class="key">with</span> <span class="nam">self</span><span class="op">.</span><span class="nam">render_lock</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t"> <span class="key">if</span> <span class="nam">direction</span> <span class="key">in</span> <span class="op">[</span><span class="str">'forward'</span><span class="op">,</span> <span class="str">'both'</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">194&#x202F;&#x219B;&#x202F;197</span><span class="annotate long">line 194 didn't jump to line 197 because the condition on line 194 was always true</span></span></p>
<p class="run"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_queue_forward_renders</span><span class="op">(</span><span class="nam">current_position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"> <span class="key">if</span> <span class="nam">direction</span> <span class="key">in</span> <span class="op">[</span><span class="str">'backward'</span><span class="op">,</span> <span class="str">'both'</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_queue_backward_renders</span><span class="op">(</span><span class="nam">current_position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t"> <span class="key">def</span> <span class="nam">_queue_forward_renders</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">start_position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t"> <span class="str">"""Queue forward page renders starting from the given position"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t"> <span class="nam">current_pos</span> <span class="op">=</span> <span class="nam">start_position</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t"> <span class="key">for</span> <span class="nam">i</span> <span class="key">in</span> <span class="nam">range</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">buffer_size</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t"> <span class="com"># Skip if already cached or being rendered</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t"> <span class="key">if</span> <span class="nam">current_pos</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">forward_buffer</span> <span class="key">or</span> <span class="nam">current_pos</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">pending_renders</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t"> <span class="com"># Try to get next position from cache</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"> <span class="nam">current_pos</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">position_map</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="nam">current_pos</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">current_pos</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t"> <span class="key">break</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t"> <span class="key">continue</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"> <span class="com"># Queue render job</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t"> <span class="nam">args</span> <span class="op">=</span> <span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t"> <span class="nam">current_pos</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_font_scale</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t"> <span class="key">False</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_font_family</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t"> <span class="nam">future</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">executor</span><span class="op">.</span><span class="nam">submit</span><span class="op">(</span><span class="nam">_render_page_worker</span><span class="op">,</span> <span class="nam">args</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">pending_renders</span><span class="op">[</span><span class="nam">current_pos</span><span class="op">]</span> <span class="op">=</span> <span class="nam">future</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t"> <span class="com"># We don't know the next position yet, so we'll update it when the render</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t"> <span class="com"># completes</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t"> <span class="key">break</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t"> <span class="key">def</span> <span class="nam">_queue_backward_renders</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">start_position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t"> <span class="str">"""Queue backward page renders ending at the given position"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t"> <span class="nam">current_pos</span> <span class="op">=</span> <span class="nam">start_position</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t"> <span class="key">for</span> <span class="nam">i</span> <span class="key">in</span> <span class="nam">range</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">buffer_size</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">232&#x202F;&#x219B;&#x202F;exit</span><span class="annotate long">line 232 didn't return from function '_queue_backward_renders' because the loop on line 232 didn't complete</span></span></p>
<p class="pln"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t"> <span class="com"># Skip if already cached or being rendered</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t"> <span class="key">if</span> <span class="nam">current_pos</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">backward_buffer</span> <span class="key">or</span> <span class="nam">current_pos</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">pending_renders</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t"> <span class="com"># Try to get previous position from cache</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t"> <span class="nam">current_pos</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">reverse_position_map</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="nam">current_pos</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">current_pos</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t"> <span class="key">break</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t"> <span class="key">continue</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t"> <span class="com"># Queue render job</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t"> <span class="nam">args</span> <span class="op">=</span> <span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t"> <span class="nam">current_pos</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_font_scale</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t"> <span class="key">True</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_font_family</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t"> <span class="nam">future</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">executor</span><span class="op">.</span><span class="nam">submit</span><span class="op">(</span><span class="nam">_render_page_worker</span><span class="op">,</span> <span class="nam">args</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">pending_renders</span><span class="op">[</span><span class="nam">current_pos</span><span class="op">]</span> <span class="op">=</span> <span class="nam">future</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t"> <span class="com"># We don't know the previous position yet, so we'll update it when the</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t"> <span class="com"># render completes</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t"> <span class="key">break</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t"> <span class="key">def</span> <span class="nam">check_completed_renders</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t"> <span class="str">"""Check for completed background renders and cache the results"""</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">self</span><span class="op">.</span><span class="nam">pending_renders</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">258&#x202F;&#x219B;&#x202F;259</span><span class="annotate long">line 258 didn't jump to line 259 because the condition on line 258 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t"> <span class="key">return</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t"> <span class="nam">completed</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t"> <span class="key">with</span> <span class="nam">self</span><span class="op">.</span><span class="nam">render_lock</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t"> <span class="key">for</span> <span class="nam">position</span><span class="op">,</span> <span class="nam">future</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">pending_renders</span><span class="op">.</span><span class="nam">items</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t"> <span class="key">if</span> <span class="nam">future</span><span class="op">.</span><span class="nam">done</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t"> <span class="nam">original_pos</span><span class="op">,</span> <span class="nam">pickled_page</span><span class="op">,</span> <span class="nam">next_pos</span> <span class="op">=</span> <span class="nam">future</span><span class="op">.</span><span class="nam">result</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t"> <span class="com"># Deserialize the page</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t"> <span class="nam">page</span> <span class="op">=</span> <span class="nam">pickle</span><span class="op">.</span><span class="nam">loads</span><span class="op">(</span><span class="nam">pickled_page</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t"> <span class="com"># Cache the page</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">cache_page</span><span class="op">(</span><span class="nam">original_pos</span><span class="op">,</span> <span class="nam">page</span><span class="op">,</span> <span class="nam">next_pos</span><span class="op">,</span> <span class="nam">is_backward</span><span class="op">=</span><span class="key">False</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t"> <span class="nam">completed</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t"> <span class="key">except</span> <span class="nam">Exception</span> <span class="key">as</span> <span class="nam">e</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t"> <span class="nam">print</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Background render failed for position </span><span class="op">{</span><span class="nam">position</span><span class="op">}</span><span class="fst">: </span><span class="op">{</span><span class="nam">e</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t279" href="#t279">279</a></span><span class="t"> <span class="nam">completed</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t280" href="#t280">280</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t281" href="#t281">281</a></span><span class="t"> <span class="com"># Remove completed renders</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t282" href="#t282">282</a></span><span class="t"> <span class="key">for</span> <span class="nam">pos</span> <span class="key">in</span> <span class="nam">completed</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t283" href="#t283">283</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">pending_renders</span><span class="op">.</span><span class="nam">pop</span><span class="op">(</span><span class="nam">pos</span><span class="op">,</span> <span class="key">None</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t284" href="#t284">284</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t285" href="#t285">285</a></span><span class="t"> <span class="key">def</span> <span class="nam">invalidate_all</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t286" href="#t286">286</a></span><span class="t"> <span class="str">"""Clear all cached pages and cancel pending renders"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t287" href="#t287">287</a></span><span class="t"> <span class="key">with</span> <span class="nam">self</span><span class="op">.</span><span class="nam">render_lock</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t288" href="#t288">288</a></span><span class="t"> <span class="com"># Cancel pending renders</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t289" href="#t289">289</a></span><span class="t"> <span class="key">for</span> <span class="nam">future</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">pending_renders</span><span class="op">.</span><span class="nam">values</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t290" href="#t290">290</a></span><span class="t"> <span class="nam">future</span><span class="op">.</span><span class="nam">cancel</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t291" href="#t291">291</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">pending_renders</span><span class="op">.</span><span class="nam">clear</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t292" href="#t292">292</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t293" href="#t293">293</a></span><span class="t"> <span class="com"># Clear caches</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t294" href="#t294">294</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">forward_buffer</span><span class="op">.</span><span class="nam">clear</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t295" href="#t295">295</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">backward_buffer</span><span class="op">.</span><span class="nam">clear</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t296" href="#t296">296</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">position_map</span><span class="op">.</span><span class="nam">clear</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t297" href="#t297">297</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">reverse_position_map</span><span class="op">.</span><span class="nam">clear</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t298" href="#t298">298</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t299" href="#t299">299</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_font_scale</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">:</span> <span class="nam">float</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t300" href="#t300">300</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t301" href="#t301">301</a></span><span class="t"><span class="str"> Update font scale and invalidate cache.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t302" href="#t302">302</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t303" href="#t303">303</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t304" href="#t304">304</a></span><span class="t"><span class="str"> font_scale: New font scaling factor</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t305" href="#t305">305</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t306" href="#t306">306</a></span><span class="t"> <span class="key">if</span> <span class="nam">font_scale</span> <span class="op">!=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">current_font_scale</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">306&#x202F;&#x219B;&#x202F;exit</span><span class="annotate long">line 306 didn't return from function 'set_font_scale' because the condition on line 306 was always true</span></span></p>
<p class="run"><span class="n"><a id="t307" href="#t307">307</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_font_scale</span> <span class="op">=</span> <span class="nam">font_scale</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t308" href="#t308">308</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">invalidate_all</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t309" href="#t309">309</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t310" href="#t310">310</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_font_family</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">font_family</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">BundledFont</span><span class="op">]</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t311" href="#t311">311</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t312" href="#t312">312</a></span><span class="t"><span class="str"> Update font family and invalidate cache.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t313" href="#t313">313</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t314" href="#t314">314</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t315" href="#t315">315</a></span><span class="t"><span class="str"> font_family: New font family (None = use original fonts)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t316" href="#t316">316</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t317" href="#t317">317</a></span><span class="t"> <span class="key">if</span> <span class="nam">font_family</span> <span class="op">!=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">current_font_family</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t318" href="#t318">318</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_font_family</span> <span class="op">=</span> <span class="nam">font_family</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t319" href="#t319">319</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">invalidate_all</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t320" href="#t320">320</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t321" href="#t321">321</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_cache_stats</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t322" href="#t322">322</a></span><span class="t"> <span class="str">"""Get cache statistics for debugging/monitoring"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t323" href="#t323">323</a></span><span class="t"> <span class="key">return</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t324" href="#t324">324</a></span><span class="t"> <span class="str">'forward_buffer_size'</span><span class="op">:</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">forward_buffer</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t325" href="#t325">325</a></span><span class="t"> <span class="str">'backward_buffer_size'</span><span class="op">:</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">backward_buffer</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t326" href="#t326">326</a></span><span class="t"> <span class="str">'pending_renders'</span><span class="op">:</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">pending_renders</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t327" href="#t327">327</a></span><span class="t"> <span class="str">'position_mappings'</span><span class="op">:</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">position_map</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t328" href="#t328">328</a></span><span class="t"> <span class="str">'reverse_position_mappings'</span><span class="op">:</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">reverse_position_map</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t329" href="#t329">329</a></span><span class="t"> <span class="str">'current_font_scale'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">current_font_scale</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t330" href="#t330">330</a></span><span class="t"> <span class="str">'current_font_family'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">current_font_family</span><span class="op">.</span><span class="nam">value</span> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">current_font_family</span> <span class="key">else</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t331" href="#t331">331</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t332" href="#t332">332</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t333" href="#t333">333</a></span><span class="t"> <span class="key">def</span> <span class="nam">shutdown</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t334" href="#t334">334</a></span><span class="t"> <span class="str">"""Shutdown the page buffer and clean up resources"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t335" href="#t335">335</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">executor</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t336" href="#t336">336</a></span><span class="t"> <span class="com"># Cancel pending renders</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t337" href="#t337">337</a></span><span class="t"> <span class="key">with</span> <span class="nam">self</span><span class="op">.</span><span class="nam">render_lock</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t338" href="#t338">338</a></span><span class="t"> <span class="key">for</span> <span class="nam">future</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">pending_renders</span><span class="op">.</span><span class="nam">values</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t339" href="#t339">339</a></span><span class="t"> <span class="nam">future</span><span class="op">.</span><span class="nam">cancel</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t340" href="#t340">340</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t341" href="#t341">341</a></span><span class="t"> <span class="com"># Shutdown executor</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t342" href="#t342">342</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">executor</span><span class="op">.</span><span class="nam">shutdown</span><span class="op">(</span><span class="nam">wait</span><span class="op">=</span><span class="key">True</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t343" href="#t343">343</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">executor</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t344" href="#t344">344</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t345" href="#t345">345</a></span><span class="t"> <span class="com"># Clear all caches</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t346" href="#t346">346</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">invalidate_all</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t347" href="#t347">347</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t348" href="#t348">348</a></span><span class="t"> <span class="key">def</span> <span class="nam">__del__</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t349" href="#t349">349</a></span><span class="t"> <span class="str">"""Cleanup on destruction"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t350" href="#t350">350</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">shutdown</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t351" href="#t351">351</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t352" href="#t352">352</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t353" href="#t353">353</a></span><span class="t"><span class="key">class</span> <span class="nam">BufferedPageRenderer</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t354" href="#t354">354</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t355" href="#t355">355</a></span><span class="t"><span class="str"> High-level interface for buffered page rendering with automatic background caching.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t356" href="#t356">356</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t357" href="#t357">357</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t358" href="#t358">358</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t359" href="#t359">359</a></span><span class="t"> <span class="nam">blocks</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">Block</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t360" href="#t360">360</a></span><span class="t"> <span class="nam">page_style</span><span class="op">:</span> <span class="nam">PageStyle</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t361" href="#t361">361</a></span><span class="t"> <span class="nam">buffer_size</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">5</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t362" href="#t362">362</a></span><span class="t"> <span class="nam">page_size</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t363" href="#t363">363</a></span><span class="t"> <span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="op">(</span><span class="num">800</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t364" href="#t364">364</a></span><span class="t"> <span class="num">600</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t365" href="#t365">365</a></span><span class="t"> <span class="nam">font_family</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">BundledFont</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t366" href="#t366">366</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t367" href="#t367">367</a></span><span class="t"><span class="str"> Initialize the buffered renderer.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t368" href="#t368">368</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t369" href="#t369">369</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t370" href="#t370">370</a></span><span class="t"><span class="str"> blocks: Document blocks to render</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t371" href="#t371">371</a></span><span class="t"><span class="str"> page_style: Page styling configuration</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t372" href="#t372">372</a></span><span class="t"><span class="str"> buffer_size: Number of pages to cache in each direction</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t373" href="#t373">373</a></span><span class="t"><span class="str"> page_size: Page size (width, height) in pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t374" href="#t374">374</a></span><span class="t"><span class="str"> font_family: Optional font family override</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t375" href="#t375">375</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t376" href="#t376">376</a></span><span class="t"> <span class="com"># Create font family override if specified</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t377" href="#t377">377</a></span><span class="t"> <span class="nam">font_family_override</span> <span class="op">=</span> <span class="nam">FontFamilyOverride</span><span class="op">(</span><span class="nam">font_family</span><span class="op">)</span> <span class="key">if</span> <span class="nam">font_family</span> <span class="key">else</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t378" href="#t378">378</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t379" href="#t379">379</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">layouter</span> <span class="op">=</span> <span class="nam">BidirectionalLayouter</span><span class="op">(</span><span class="nam">blocks</span><span class="op">,</span> <span class="nam">page_style</span><span class="op">,</span> <span class="nam">page_size</span><span class="op">,</span> <span class="nam">font_family_override</span><span class="op">=</span><span class="nam">font_family_override</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t380" href="#t380">380</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer</span> <span class="op">=</span> <span class="nam">PageBuffer</span><span class="op">(</span><span class="nam">buffer_size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t381" href="#t381">381</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">initialize</span><span class="op">(</span><span class="nam">blocks</span><span class="op">,</span> <span class="nam">page_style</span><span class="op">,</span> <span class="nam">font_family</span><span class="op">=</span><span class="nam">font_family</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t382" href="#t382">382</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">page_size</span> <span class="op">=</span> <span class="nam">page_size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t383" href="#t383">383</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span> <span class="op">=</span> <span class="nam">blocks</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t384" href="#t384">384</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span> <span class="op">=</span> <span class="nam">page_style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t385" href="#t385">385</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t386" href="#t386">386</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">current_position</span> <span class="op">=</span> <span class="nam">RenderingPosition</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t387" href="#t387">387</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">font_scale</span> <span class="op">=</span> <span class="num">1.0</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t388" href="#t388">388</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">font_family</span> <span class="op">=</span> <span class="nam">font_family</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t389" href="#t389">389</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t390" href="#t390">390</a></span><span class="t"> <span class="key">def</span> <span class="nam">render_page</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t391" href="#t391">391</a></span><span class="t"> <span class="nam">font_scale</span><span class="op">:</span> <span class="nam">float</span> <span class="op">=</span> <span class="num">1.0</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">Page</span><span class="op">,</span> <span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t392" href="#t392">392</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t393" href="#t393">393</a></span><span class="t"><span class="str"> Render a page with intelligent caching.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t394" href="#t394">394</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t395" href="#t395">395</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t396" href="#t396">396</a></span><span class="t"><span class="str"> position: Position to render from</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t397" href="#t397">397</a></span><span class="t"><span class="str"> font_scale: Font scaling factor</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t398" href="#t398">398</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t399" href="#t399">399</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t400" href="#t400">400</a></span><span class="t"><span class="str"> Tuple of (rendered_page, next_position)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t401" href="#t401">401</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t402" href="#t402">402</a></span><span class="t"> <span class="com"># Update font scale if changed</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t403" href="#t403">403</a></span><span class="t"> <span class="key">if</span> <span class="nam">font_scale</span> <span class="op">!=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">font_scale</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t404" href="#t404">404</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">font_scale</span> <span class="op">=</span> <span class="nam">font_scale</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t405" href="#t405">405</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">set_font_scale</span><span class="op">(</span><span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t406" href="#t406">406</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t407" href="#t407">407</a></span><span class="t"> <span class="com"># Check cache first</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t408" href="#t408">408</a></span><span class="t"> <span class="nam">cached_page</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">get_page</span><span class="op">(</span><span class="nam">position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t409" href="#t409">409</a></span><span class="t"> <span class="key">if</span> <span class="nam">cached_page</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t410" href="#t410">410</a></span><span class="t"> <span class="com"># Get next position from position map</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t411" href="#t411">411</a></span><span class="t"> <span class="nam">next_pos</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">position_map</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="nam">position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t412" href="#t412">412</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t413" href="#t413">413</a></span><span class="t"> <span class="com"># Only use cache if we have the forward position mapping</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t414" href="#t414">414</a></span><span class="t"> <span class="com"># Otherwise, we need to compute it</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t415" href="#t415">415</a></span><span class="t"> <span class="key">if</span> <span class="nam">next_pos</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t416" href="#t416">416</a></span><span class="t"> <span class="com"># Start background rendering for upcoming pages</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t417" href="#t417">417</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">start_background_rendering</span><span class="op">(</span><span class="nam">position</span><span class="op">,</span> <span class="str">'forward'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t418" href="#t418">418</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t419" href="#t419">419</a></span><span class="t"> <span class="key">return</span> <span class="nam">cached_page</span><span class="op">,</span> <span class="nam">next_pos</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t420" href="#t420">420</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t421" href="#t421">421</a></span><span class="t"> <span class="com"># Cache hit for the page, but we don't have the forward position</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t422" href="#t422">422</a></span><span class="t"> <span class="com"># Fall through to compute it below</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t423" href="#t423">423</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t424" href="#t424">424</a></span><span class="t"> <span class="com"># Render the page directly</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t425" href="#t425">425</a></span><span class="t"> <span class="nam">page</span><span class="op">,</span> <span class="nam">next_pos</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">layouter</span><span class="op">.</span><span class="nam">render_page_forward</span><span class="op">(</span><span class="nam">position</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t426" href="#t426">426</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t427" href="#t427">427</a></span><span class="t"> <span class="com"># Cache the result</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t428" href="#t428">428</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">cache_page</span><span class="op">(</span><span class="nam">position</span><span class="op">,</span> <span class="nam">page</span><span class="op">,</span> <span class="nam">next_pos</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t429" href="#t429">429</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t430" href="#t430">430</a></span><span class="t"> <span class="com"># Start background rendering</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t431" href="#t431">431</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">start_background_rendering</span><span class="op">(</span><span class="nam">position</span><span class="op">,</span> <span class="str">'both'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t432" href="#t432">432</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t433" href="#t433">433</a></span><span class="t"> <span class="com"># Check for completed background renders</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t434" href="#t434">434</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">check_completed_renders</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t435" href="#t435">435</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t436" href="#t436">436</a></span><span class="t"> <span class="key">return</span> <span class="nam">page</span><span class="op">,</span> <span class="nam">next_pos</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t437" href="#t437">437</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t438" href="#t438">438</a></span><span class="t"> <span class="key">def</span> <span class="nam">render_page_backward</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t439" href="#t439">439</a></span><span class="t"> <span class="nam">end_position</span><span class="op">:</span> <span class="nam">RenderingPosition</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t440" href="#t440">440</a></span><span class="t"> <span class="nam">font_scale</span><span class="op">:</span> <span class="nam">float</span> <span class="op">=</span> <span class="num">1.0</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">Page</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t441" href="#t441">441</a></span><span class="t"> <span class="nam">RenderingPosition</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t442" href="#t442">442</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t443" href="#t443">443</a></span><span class="t"><span class="str"> Render a page ending at the given position with intelligent caching.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t444" href="#t444">444</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t445" href="#t445">445</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t446" href="#t446">446</a></span><span class="t"><span class="str"> end_position: Position where page should end</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t447" href="#t447">447</a></span><span class="t"><span class="str"> font_scale: Font scaling factor</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t448" href="#t448">448</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t449" href="#t449">449</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t450" href="#t450">450</a></span><span class="t"><span class="str"> Tuple of (rendered_page, start_position)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t451" href="#t451">451</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t452" href="#t452">452</a></span><span class="t"> <span class="com"># Update font scale if changed</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t453" href="#t453">453</a></span><span class="t"> <span class="key">if</span> <span class="nam">font_scale</span> <span class="op">!=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">font_scale</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">453&#x202F;&#x219B;&#x202F;454</span><span class="annotate long">line 453 didn't jump to line 454 because the condition on line 453 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t454" href="#t454">454</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">font_scale</span> <span class="op">=</span> <span class="nam">font_scale</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t455" href="#t455">455</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">set_font_scale</span><span class="op">(</span><span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t456" href="#t456">456</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t457" href="#t457">457</a></span><span class="t"> <span class="com"># Check cache first</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t458" href="#t458">458</a></span><span class="t"> <span class="nam">cached_page</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">get_page</span><span class="op">(</span><span class="nam">end_position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t459" href="#t459">459</a></span><span class="t"> <span class="key">if</span> <span class="nam">cached_page</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">459&#x202F;&#x219B;&#x202F;461</span><span class="annotate long">line 459 didn't jump to line 461 because the condition on line 459 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t460" href="#t460">460</a></span><span class="t"> <span class="com"># Get previous position from reverse position map</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t461" href="#t461">461</a></span><span class="t"> <span class="nam">prev_pos</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">reverse_position_map</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="nam">end_position</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t462" href="#t462">462</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t463" href="#t463">463</a></span><span class="t"> <span class="com"># Only use cache if we have the reverse position mapping</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t464" href="#t464">464</a></span><span class="t"> <span class="com"># Otherwise, we need to compute it</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t465" href="#t465">465</a></span><span class="t"> <span class="key">if</span> <span class="nam">prev_pos</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t466" href="#t466">466</a></span><span class="t"> <span class="com"># Start background rendering for previous pages</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t467" href="#t467">467</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">start_background_rendering</span><span class="op">(</span><span class="nam">end_position</span><span class="op">,</span> <span class="str">'backward'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t468" href="#t468">468</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t469" href="#t469">469</a></span><span class="t"> <span class="key">return</span> <span class="nam">cached_page</span><span class="op">,</span> <span class="nam">prev_pos</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t470" href="#t470">470</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t471" href="#t471">471</a></span><span class="t"> <span class="com"># Cache hit for the page, but we don't have the reverse position</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t472" href="#t472">472</a></span><span class="t"> <span class="com"># Fall through to compute it below</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t473" href="#t473">473</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t474" href="#t474">474</a></span><span class="t"> <span class="com"># Render the page directly</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t475" href="#t475">475</a></span><span class="t"> <span class="nam">page</span><span class="op">,</span> <span class="nam">start_pos</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">layouter</span><span class="op">.</span><span class="nam">render_page_backward</span><span class="op">(</span><span class="nam">end_position</span><span class="op">,</span> <span class="nam">font_scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t476" href="#t476">476</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t477" href="#t477">477</a></span><span class="t"> <span class="com"># Cache the result</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t478" href="#t478">478</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">cache_page</span><span class="op">(</span><span class="nam">start_pos</span><span class="op">,</span> <span class="nam">page</span><span class="op">,</span> <span class="nam">end_position</span><span class="op">,</span> <span class="nam">is_backward</span><span class="op">=</span><span class="key">True</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t479" href="#t479">479</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t480" href="#t480">480</a></span><span class="t"> <span class="com"># Start background rendering</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t481" href="#t481">481</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">start_background_rendering</span><span class="op">(</span><span class="nam">end_position</span><span class="op">,</span> <span class="str">'both'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t482" href="#t482">482</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t483" href="#t483">483</a></span><span class="t"> <span class="com"># Check for completed background renders</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t484" href="#t484">484</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">check_completed_renders</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t485" href="#t485">485</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t486" href="#t486">486</a></span><span class="t"> <span class="key">return</span> <span class="nam">page</span><span class="op">,</span> <span class="nam">start_pos</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t487" href="#t487">487</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t488" href="#t488">488</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_font_family</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">font_family</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">BundledFont</span><span class="op">]</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t489" href="#t489">489</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t490" href="#t490">490</a></span><span class="t"><span class="str"> Change the font family and invalidate cache.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t491" href="#t491">491</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t492" href="#t492">492</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t493" href="#t493">493</a></span><span class="t"><span class="str"> font_family: New font family (None = use original fonts)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t494" href="#t494">494</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t495" href="#t495">495</a></span><span class="t"> <span class="key">if</span> <span class="nam">font_family</span> <span class="op">!=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">font_family</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t496" href="#t496">496</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">font_family</span> <span class="op">=</span> <span class="nam">font_family</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t497" href="#t497">497</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t498" href="#t498">498</a></span><span class="t"> <span class="com"># Update buffer</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t499" href="#t499">499</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">set_font_family</span><span class="op">(</span><span class="nam">font_family</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t500" href="#t500">500</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t501" href="#t501">501</a></span><span class="t"> <span class="com"># Recreate layouter with new font family override</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t502" href="#t502">502</a></span><span class="t"> <span class="nam">font_family_override</span> <span class="op">=</span> <span class="nam">FontFamilyOverride</span><span class="op">(</span><span class="nam">font_family</span><span class="op">)</span> <span class="key">if</span> <span class="nam">font_family</span> <span class="key">else</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t503" href="#t503">503</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">layouter</span> <span class="op">=</span> <span class="nam">BidirectionalLayouter</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t504" href="#t504">504</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">blocks</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t505" href="#t505">505</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">page_style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t506" href="#t506">506</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">page_size</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t507" href="#t507">507</a></span><span class="t"> <span class="nam">font_family_override</span><span class="op">=</span><span class="nam">font_family_override</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t508" href="#t508">508</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t509" href="#t509">509</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t510" href="#t510">510</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_font_family</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">BundledFont</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t511" href="#t511">511</a></span><span class="t"> <span class="str">"""Get the current font family override"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t512" href="#t512">512</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">font_family</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t513" href="#t513">513</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t514" href="#t514">514</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_cache_stats</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t515" href="#t515">515</a></span><span class="t"> <span class="str">"""Get cache statistics"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t516" href="#t516">516</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">get_cache_stats</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t517" href="#t517">517</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t518" href="#t518">518</a></span><span class="t"> <span class="key">def</span> <span class="nam">shutdown</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t519" href="#t519">519</a></span><span class="t"> <span class="str">"""Shutdown the renderer and clean up resources"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t520" href="#t520">520</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">buffer</span><span class="op">.</span><span class="nam">shutdown</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_427cc3035faf7633_ereader_manager_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_427cc3035faf7633_table_optimizer_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,495 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/layout/table_optimizer.py: 88%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/layout/table_optimizer.py</b>:
<span class="pc_cov">88%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">151 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">137<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">14<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">9<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">9<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_427cc3035faf7633_page_buffer_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_ba7f6bdeb0188088___init___py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">Table column width optimization for pyWebLayout.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">This module provides intelligent column width distribution for tables,</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">ensuring optimal space usage while respecting content constraints.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">List</span><span class="op">,</span> <span class="nam">Tuple</span><span class="op">,</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">Dict</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">block</span> <span class="key">import</span> <span class="nam">Table</span><span class="op">,</span> <span class="nam">TableRow</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="key">def</span> <span class="nam">optimize_table_layout</span><span class="op">(</span><span class="nam">table</span><span class="op">:</span> <span class="nam">Table</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"> <span class="nam">available_width</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t"> <span class="nam">sample_size</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">5</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"> <span class="nam">style</span><span class="op">=</span><span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"><span class="str"> Optimize column widths for a table.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"><span class="str"> Strategy:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"><span class="str"> 1. Check for HTML width overrides (colspan, width attributes)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"><span class="str"> 2. Sample first ~5 rows to estimate column requirements (performance)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"><span class="str"> 3. Calculate minimum width for each column (longest unbreakable word)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"><span class="str"> 4. Calculate preferred width for each column (no wrapping)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"><span class="str"> 5. If total preferred fits: use preferred</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"><span class="str"> 6. Otherwise: distribute available space proportionally</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"><span class="str"> 7. Ensure no column &lt; min_width</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t"><span class="str"> Note: Hyphenation threshold is controlled by Font.min_hyphenation_width,</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"><span class="str"> not passed as a parameter here to avoid duplication.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"><span class="str"> table: The table to optimize</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"><span class="str"> available_width: Total width available</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"><span class="str"> sample_size: Number of rows to sample for measurement (default 5)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"><span class="str"> style: Optional table style for border/padding calculations</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t"><span class="str"> List of optimized column widths</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span><span class="op">.</span><span class="nam">dynamic_page</span> <span class="key">import</span> <span class="nam">DynamicPage</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t"> <span class="nam">n_cols</span> <span class="op">=</span> <span class="nam">get_column_count</span><span class="op">(</span><span class="nam">table</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t"> <span class="key">if</span> <span class="nam">n_cols</span> <span class="op">==</span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"> <span class="key">return</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"> <span class="com"># Account for table borders/padding overhead</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"> <span class="key">if</span> <span class="nam">style</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"> <span class="nam">overhead</span> <span class="op">=</span> <span class="nam">calculate_table_overhead</span><span class="op">(</span><span class="nam">n_cols</span><span class="op">,</span> <span class="nam">style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t"> <span class="nam">available_for_content</span> <span class="op">=</span> <span class="nam">available_width</span> <span class="op">-</span> <span class="nam">overhead</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t"> <span class="com"># Default border overhead</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t"> <span class="nam">border_width</span> <span class="op">=</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"> <span class="nam">overhead</span> <span class="op">=</span> <span class="nam">border_width</span> <span class="op">*</span> <span class="op">(</span><span class="nam">n_cols</span> <span class="op">+</span> <span class="num">1</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t"> <span class="nam">available_for_content</span> <span class="op">=</span> <span class="nam">available_width</span> <span class="op">-</span> <span class="nam">overhead</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t"> <span class="com"># Phase 0: Check for HTML width overrides</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t"> <span class="nam">html_widths</span> <span class="op">=</span> <span class="nam">extract_html_column_widths</span><span class="op">(</span><span class="nam">table</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t"> <span class="nam">fixed_columns</span> <span class="op">=</span> <span class="op">{</span><span class="nam">i</span><span class="op">:</span> <span class="nam">width</span> <span class="key">for</span> <span class="nam">i</span><span class="op">,</span> <span class="nam">width</span> <span class="key">in</span> <span class="nam">enumerate</span><span class="op">(</span><span class="nam">html_widths</span><span class="op">)</span> <span class="key">if</span> <span class="nam">width</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"> <span class="com"># Phase 1: Sample rows and measure constraints for each column</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"> <span class="nam">min_widths</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span> <span class="com"># Minimum without breaking words (Font handles hyphenation)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t"> <span class="nam">pref_widths</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span> <span class="com"># Preferred (no wrapping)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"> <span class="com"># Sample first ~5 rows from each section (header, body, footer)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"> <span class="nam">sampled_rows</span> <span class="op">=</span> <span class="nam">sample_table_rows</span><span class="op">(</span><span class="nam">table</span><span class="op">,</span> <span class="nam">sample_size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t"> <span class="key">for</span> <span class="nam">col_idx</span> <span class="key">in</span> <span class="nam">range</span><span class="op">(</span><span class="nam">n_cols</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"> <span class="com"># Check if this column has HTML width override</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"> <span class="key">if</span> <span class="nam">col_idx</span> <span class="key">in</span> <span class="nam">fixed_columns</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">69&#x202F;&#x219B;&#x202F;70</span><span class="annotate long">line 69 didn't jump to line 70 because the condition on line 69 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t"> <span class="nam">fixed_width</span> <span class="op">=</span> <span class="nam">fixed_columns</span><span class="op">[</span><span class="nam">col_idx</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t"> <span class="nam">min_widths</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">fixed_width</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t"> <span class="nam">pref_widths</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">fixed_width</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"> <span class="key">continue</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"> <span class="nam">col_min</span> <span class="op">=</span> <span class="num">50</span> <span class="com"># Absolute minimum</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t"> <span class="nam">col_pref</span> <span class="op">=</span> <span class="num">50</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"> <span class="com"># Check sampled cells in this column</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t"> <span class="key">for</span> <span class="nam">row</span> <span class="key">in</span> <span class="nam">sampled_rows</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t"> <span class="nam">cells</span> <span class="op">=</span> <span class="nam">list</span><span class="op">(</span><span class="nam">row</span><span class="op">.</span><span class="nam">cells</span><span class="op">(</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t"> <span class="key">if</span> <span class="nam">col_idx</span> <span class="op">>=</span> <span class="nam">len</span><span class="op">(</span><span class="nam">cells</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">81&#x202F;&#x219B;&#x202F;82</span><span class="annotate long">line 81 didn't jump to line 82 because the condition on line 81 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t"> <span class="key">continue</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"> <span class="nam">cell</span> <span class="op">=</span> <span class="nam">cells</span><span class="op">[</span><span class="nam">col_idx</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t"> <span class="com"># Create a DynamicPage for this cell with no padding/borders</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t"> <span class="com"># (we're just measuring content, not rendering a full page)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">page_style</span> <span class="key">import</span> <span class="nam">PageStyle</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"> <span class="nam">measurement_style</span> <span class="op">=</span> <span class="nam">PageStyle</span><span class="op">(</span><span class="nam">padding</span><span class="op">=</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">,</span> <span class="nam">border_width</span><span class="op">=</span><span class="num">0</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t"> <span class="nam">cell_page</span> <span class="op">=</span> <span class="nam">DynamicPage</span><span class="op">(</span><span class="nam">style</span><span class="op">=</span><span class="nam">measurement_style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t"> <span class="com"># Add cell content to page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t"> <span class="nam">layout_cell_content</span><span class="op">(</span><span class="nam">cell_page</span><span class="op">,</span> <span class="nam">cell</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t"> <span class="com"># Measure minimum width (Font's min_hyphenation_width controls breaking)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t"> <span class="com"># DynamicPage returns pure content width (no padding since we set it to 0)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t"> <span class="com"># TableRenderer will add cell padding later</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t"> <span class="nam">cell_min</span> <span class="op">=</span> <span class="nam">cell_page</span><span class="op">.</span><span class="nam">get_min_width</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"> <span class="nam">col_min</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">col_min</span><span class="op">,</span> <span class="nam">cell_min</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"> <span class="com"># Measure preferred width (no wrapping)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"> <span class="nam">cell_pref</span> <span class="op">=</span> <span class="nam">cell_page</span><span class="op">.</span><span class="nam">get_preferred_width</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t"> <span class="nam">col_pref</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">col_pref</span><span class="op">,</span> <span class="nam">cell_pref</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t"> <span class="nam">min_widths</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">col_min</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t"> <span class="nam">pref_widths</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">col_pref</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t"> <span class="com"># Phase 2: Distribute width (respecting fixed columns)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t"> <span class="key">return</span> <span class="nam">distribute_column_widths</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"> <span class="nam">min_widths</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t"> <span class="nam">pref_widths</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"> <span class="nam">available_for_content</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t"> <span class="nam">fixed_columns</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t"><span class="key">def</span> <span class="nam">layout_cell_content</span><span class="op">(</span><span class="nam">page</span><span class="op">,</span> <span class="nam">cell</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"><span class="str"> Layout cell content onto a DynamicPage.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t"><span class="str"> This adds all blocks from the cell (paragraphs, images, etc.)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t"><span class="str"> as children of the page so they can be measured.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t"><span class="str"> page: DynamicPage to add content to</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t"><span class="str"> cell: TableCell containing blocks</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span><span class="op">.</span><span class="nam">text</span> <span class="key">import</span> <span class="nam">Line</span><span class="op">,</span> <span class="nam">Text</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">fonts</span> <span class="key">import</span> <span class="nam">Font</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span> <span class="key">import</span> <span class="nam">FontWeight</span><span class="op">,</span> <span class="nam">Alignment</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">block</span> <span class="key">import</span> <span class="nam">Paragraph</span><span class="op">,</span> <span class="nam">Heading</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t"> <span class="key">from</span> <span class="nam">PIL</span> <span class="key">import</span> <span class="nam">Image</span> <span class="key">as</span> <span class="nam">PILImage</span><span class="op">,</span> <span class="nam">ImageDraw</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t"> <span class="com"># Default font for measurement</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t"> <span class="nam">font_size</span> <span class="op">=</span> <span class="num">12</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"> <span class="nam">font_path</span> <span class="op">=</span> <span class="str">"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t"> <span class="nam">font</span> <span class="op">=</span> <span class="nam">Font</span><span class="op">(</span><span class="nam">font_path</span><span class="op">=</span><span class="nam">font_path</span><span class="op">,</span> <span class="nam">font_size</span><span class="op">=</span><span class="nam">font_size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t"> <span class="com"># Create a minimal draw context for Text measurement</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t"> <span class="com"># (Text needs this for width calculation)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t"> <span class="nam">dummy_img</span> <span class="op">=</span> <span class="nam">PILImage</span><span class="op">.</span><span class="nam">new</span><span class="op">(</span><span class="str">'RGB'</span><span class="op">,</span> <span class="op">(</span><span class="num">1</span><span class="op">,</span> <span class="num">1</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t"> <span class="nam">dummy_draw</span> <span class="op">=</span> <span class="nam">ImageDraw</span><span class="op">.</span><span class="nam">Draw</span><span class="op">(</span><span class="nam">dummy_img</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"> <span class="com"># Get all blocks from the cell</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t"> <span class="key">for</span> <span class="nam">block</span> <span class="key">in</span> <span class="nam">cell</span><span class="op">.</span><span class="nam">blocks</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="op">(</span><span class="nam">Paragraph</span><span class="op">,</span> <span class="nam">Heading</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">146&#x202F;&#x219B;&#x202F;145</span><span class="annotate long">line 146 didn't jump to line 145 because the condition on line 146 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"> <span class="com"># Get words from the block</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"> <span class="nam">word_items</span> <span class="op">=</span> <span class="nam">block</span><span class="op">.</span><span class="nam">words</span><span class="op">(</span><span class="op">)</span> <span class="key">if</span> <span class="nam">callable</span><span class="op">(</span><span class="nam">block</span><span class="op">.</span><span class="nam">words</span><span class="op">)</span> <span class="key">else</span> <span class="nam">block</span><span class="op">.</span><span class="nam">words</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t"> <span class="nam">words</span> <span class="op">=</span> <span class="nam">list</span><span class="op">(</span><span class="nam">word_items</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">words</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">151&#x202F;&#x219B;&#x202F;152</span><span class="annotate long">line 151 didn't jump to line 152 because the condition on line 151 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t"> <span class="key">continue</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t"> <span class="com"># Create a line for measurement</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t"> <span class="nam">line</span> <span class="op">=</span> <span class="nam">Line</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t"> <span class="nam">spacing</span><span class="op">=</span><span class="op">(</span><span class="num">3</span><span class="op">,</span> <span class="num">6</span><span class="op">)</span><span class="op">,</span> <span class="com"># word spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t"> <span class="nam">origin</span><span class="op">=</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t"> <span class="nam">size</span><span class="op">=</span><span class="op">(</span><span class="num">1000</span><span class="op">,</span> <span class="num">20</span><span class="op">)</span><span class="op">,</span> <span class="com"># Large size for measurement</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t"> <span class="nam">draw</span><span class="op">=</span><span class="nam">dummy_draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"> <span class="nam">font</span><span class="op">=</span><span class="nam">font</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t"> <span class="nam">halign</span><span class="op">=</span><span class="nam">Alignment</span><span class="op">.</span><span class="nam">LEFT</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t"> <span class="com"># Add all words to estimate width</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t"> <span class="key">for</span> <span class="nam">word_item</span> <span class="key">in</span> <span class="nam">words</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"> <span class="com"># Handle word tuples (index, word_obj)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">word_item</span><span class="op">,</span> <span class="nam">tuple</span><span class="op">)</span> <span class="key">and</span> <span class="nam">len</span><span class="op">(</span><span class="nam">word_item</span><span class="op">)</span> <span class="op">>=</span> <span class="num">2</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">167&#x202F;&#x219B;&#x202F;168</span><span class="annotate long">line 167 didn't jump to line 168 because the condition on line 167 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t"> <span class="nam">word_obj</span> <span class="op">=</span> <span class="nam">word_item</span><span class="op">[</span><span class="num">1</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"> <span class="nam">word_obj</span> <span class="op">=</span> <span class="nam">word_item</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t"> <span class="com"># Extract text from the word</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t"> <span class="nam">word_text</span> <span class="op">=</span> <span class="nam">word_obj</span><span class="op">.</span><span class="nam">text</span> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">word_obj</span><span class="op">,</span> <span class="str">'text'</span><span class="op">)</span> <span class="key">else</span> <span class="nam">str</span><span class="op">(</span><span class="nam">word_obj</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t"> <span class="com"># Create Text object for the word</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t"> <span class="com"># Text constructor: (text, style, draw)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t"> <span class="nam">text_obj</span> <span class="op">=</span> <span class="nam">Text</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t"> <span class="nam">text</span><span class="op">=</span><span class="nam">word_text</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t"> <span class="nam">style</span><span class="op">=</span><span class="nam">font</span><span class="op">,</span> <span class="com"># Font is the style</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t"> <span class="nam">draw</span><span class="op">=</span><span class="nam">dummy_draw</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t"> <span class="nam">line</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">text_obj</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t"> <span class="com"># Add line to page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t"> <span class="nam">page</span><span class="op">.</span><span class="nam">add_child</span><span class="op">(</span><span class="nam">line</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t"><span class="key">def</span> <span class="nam">get_column_count</span><span class="op">(</span><span class="nam">table</span><span class="op">:</span> <span class="nam">Table</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t"><span class="str"> Get the number of columns in a table.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t"><span class="str"> table: The table to analyze</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"><span class="str"> Number of columns</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t"> <span class="nam">all_rows</span> <span class="op">=</span> <span class="nam">list</span><span class="op">(</span><span class="nam">table</span><span class="op">.</span><span class="nam">all_rows</span><span class="op">(</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">all_rows</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t"> <span class="key">return</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t"> <span class="com"># Get from first row</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t"> <span class="nam">first_row</span> <span class="op">=</span> <span class="nam">all_rows</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">[</span><span class="num">1</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t"> <span class="key">return</span> <span class="nam">first_row</span><span class="op">.</span><span class="nam">cell_count</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"><span class="key">def</span> <span class="nam">sample_table_rows</span><span class="op">(</span><span class="nam">table</span><span class="op">:</span> <span class="nam">Table</span><span class="op">,</span> <span class="nam">sample_size</span><span class="op">:</span> <span class="nam">int</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">TableRow</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t"><span class="str"> Sample first ~sample_size rows from each table section.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"><span class="str"> table: The table to sample</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t"><span class="str"> sample_size: Number of rows to sample per section</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t"><span class="str"> List of sampled rows</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t"> <span class="nam">sampled</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t"> <span class="key">for</span> <span class="nam">section</span> <span class="key">in</span> <span class="op">[</span><span class="str">"header"</span><span class="op">,</span> <span class="str">"body"</span><span class="op">,</span> <span class="str">"footer"</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"> <span class="nam">section_rows</span> <span class="op">=</span> <span class="op">[</span><span class="nam">row</span> <span class="key">for</span> <span class="nam">sec</span><span class="op">,</span> <span class="nam">row</span> <span class="key">in</span> <span class="nam">table</span><span class="op">.</span><span class="nam">all_rows</span><span class="op">(</span><span class="op">)</span> <span class="key">if</span> <span class="nam">sec</span> <span class="op">==</span> <span class="nam">section</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t"> <span class="com"># Take first sample_size rows (or fewer if section is smaller)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t"> <span class="nam">sampled</span><span class="op">.</span><span class="nam">extend</span><span class="op">(</span><span class="nam">section_rows</span><span class="op">[</span><span class="op">:</span><span class="nam">sample_size</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t"> <span class="key">return</span> <span class="nam">sampled</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t"><span class="key">def</span> <span class="nam">extract_html_column_widths</span><span class="op">(</span><span class="nam">table</span><span class="op">:</span> <span class="nam">Table</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t"><span class="str"> Extract column width overrides from HTML attributes.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t"><span class="str"> Checks for:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t"><span class="str"> - &lt;col width="100px"> elements</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t"><span class="str"> - &lt;td width="100px"> in first row</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t"><span class="str"> - &lt;th width="100px"> in header</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t"><span class="str"> table: The table to check</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t"><span class="str"> List of widths (None for auto-layout columns)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t"> <span class="nam">n_cols</span> <span class="op">=</span> <span class="nam">get_column_count</span><span class="op">(</span><span class="nam">table</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t"> <span class="nam">widths</span> <span class="op">=</span> <span class="op">[</span><span class="key">None</span><span class="op">]</span> <span class="op">*</span> <span class="nam">n_cols</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t"> <span class="com"># Check for &lt;col> elements with width</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">table</span><span class="op">,</span> <span class="str">'col_widths'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">248&#x202F;&#x219B;&#x202F;249</span><span class="annotate long">line 248 didn't jump to line 249 because the condition on line 248 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t"> <span class="key">for</span> <span class="nam">i</span><span class="op">,</span> <span class="nam">width</span> <span class="key">in</span> <span class="nam">enumerate</span><span class="op">(</span><span class="nam">table</span><span class="op">.</span><span class="nam">col_widths</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t"> <span class="key">if</span> <span class="nam">width</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t"> <span class="nam">widths</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span> <span class="op">=</span> <span class="nam">parse_html_width</span><span class="op">(</span><span class="nam">width</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t"> <span class="com"># Check first row cells for width attributes</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t"> <span class="nam">all_rows</span> <span class="op">=</span> <span class="nam">list</span><span class="op">(</span><span class="nam">table</span><span class="op">.</span><span class="nam">all_rows</span><span class="op">(</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t"> <span class="key">if</span> <span class="nam">all_rows</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">255&#x202F;&#x219B;&#x202F;262</span><span class="annotate long">line 255 didn't jump to line 262 because the condition on line 255 was always true</span></span></p>
<p class="run"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t"> <span class="nam">first_row</span> <span class="op">=</span> <span class="nam">all_rows</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">[</span><span class="num">1</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t"> <span class="nam">cells</span> <span class="op">=</span> <span class="nam">list</span><span class="op">(</span><span class="nam">first_row</span><span class="op">.</span><span class="nam">cells</span><span class="op">(</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t"> <span class="key">for</span> <span class="nam">i</span><span class="op">,</span> <span class="nam">cell</span> <span class="key">in</span> <span class="nam">enumerate</span><span class="op">(</span><span class="nam">cells</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t"> <span class="key">if</span> <span class="nam">i</span> <span class="op">&lt;</span> <span class="nam">len</span><span class="op">(</span><span class="nam">widths</span><span class="op">)</span> <span class="key">and</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">cell</span><span class="op">,</span> <span class="str">'width'</span><span class="op">)</span> <span class="key">and</span> <span class="nam">cell</span><span class="op">.</span><span class="nam">width</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t"> <span class="nam">widths</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span> <span class="op">=</span> <span class="nam">parse_html_width</span><span class="op">(</span><span class="nam">cell</span><span class="op">.</span><span class="nam">width</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t"> <span class="key">return</span> <span class="nam">widths</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t"><span class="key">def</span> <span class="nam">parse_html_width</span><span class="op">(</span><span class="nam">width_value</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t"><span class="str"> Parse HTML width value (e.g., "100px", "20%", "100").</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t"><span class="str"> width_value: HTML width attribute value</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t"><span class="str"> Width in pixels, or None if percentage/invalid</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">width_value</span><span class="op">,</span> <span class="nam">int</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t"> <span class="key">return</span> <span class="nam">width_value</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">width_value</span><span class="op">,</span> <span class="nam">str</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">278&#x202F;&#x219B;&#x202F;299</span><span class="annotate long">line 278 didn't jump to line 299 because the condition on line 278 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t279" href="#t279">279</a></span><span class="t"> <span class="com"># Remove whitespace</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t280" href="#t280">280</a></span><span class="t"> <span class="nam">width_value</span> <span class="op">=</span> <span class="nam">width_value</span><span class="op">.</span><span class="nam">strip</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t281" href="#t281">281</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t282" href="#t282">282</a></span><span class="t"> <span class="com"># Percentage widths not supported yet</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t283" href="#t283">283</a></span><span class="t"> <span class="key">if</span> <span class="str">'%'</span> <span class="key">in</span> <span class="nam">width_value</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t284" href="#t284">284</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t285" href="#t285">285</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t286" href="#t286">286</a></span><span class="t"> <span class="com"># Parse pixel values</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t287" href="#t287">287</a></span><span class="t"> <span class="key">if</span> <span class="nam">width_value</span><span class="op">.</span><span class="nam">endswith</span><span class="op">(</span><span class="str">'px'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t288" href="#t288">288</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t289" href="#t289">289</a></span><span class="t"> <span class="key">return</span> <span class="nam">int</span><span class="op">(</span><span class="nam">width_value</span><span class="op">[</span><span class="op">:</span><span class="op">-</span><span class="num">2</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t290" href="#t290">290</a></span><span class="t"> <span class="key">except</span> <span class="nam">ValueError</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t291" href="#t291">291</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t292" href="#t292">292</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t293" href="#t293">293</a></span><span class="t"> <span class="com"># Plain number</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t294" href="#t294">294</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t295" href="#t295">295</a></span><span class="t"> <span class="key">return</span> <span class="nam">int</span><span class="op">(</span><span class="nam">width_value</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t296" href="#t296">296</a></span><span class="t"> <span class="key">except</span> <span class="nam">ValueError</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t297" href="#t297">297</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t298" href="#t298">298</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t299" href="#t299">299</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t300" href="#t300">300</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t301" href="#t301">301</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t302" href="#t302">302</a></span><span class="t"><span class="key">def</span> <span class="nam">distribute_column_widths</span><span class="op">(</span><span class="nam">min_widths</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t303" href="#t303">303</a></span><span class="t"> <span class="nam">pref_widths</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t304" href="#t304">304</a></span><span class="t"> <span class="nam">available_width</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t305" href="#t305">305</a></span><span class="t"> <span class="nam">fixed_columns</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t306" href="#t306">306</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t307" href="#t307">307</a></span><span class="t"><span class="str"> Distribute width among columns, respecting fixed column widths.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t308" href="#t308">308</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t309" href="#t309">309</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t310" href="#t310">310</a></span><span class="t"><span class="str"> min_widths: Minimum width for each column</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t311" href="#t311">311</a></span><span class="t"><span class="str"> pref_widths: Preferred width for each column</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t312" href="#t312">312</a></span><span class="t"><span class="str"> available_width: Total width available</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t313" href="#t313">313</a></span><span class="t"><span class="str"> fixed_columns: Dict mapping column index to fixed width</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t314" href="#t314">314</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t315" href="#t315">315</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t316" href="#t316">316</a></span><span class="t"><span class="str"> List of final column widths</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t317" href="#t317">317</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t318" href="#t318">318</a></span><span class="t"> <span class="nam">n_cols</span> <span class="op">=</span> <span class="nam">len</span><span class="op">(</span><span class="nam">min_widths</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t319" href="#t319">319</a></span><span class="t"> <span class="key">if</span> <span class="nam">n_cols</span> <span class="op">==</span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t320" href="#t320">320</a></span><span class="t"> <span class="key">return</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t321" href="#t321">321</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t322" href="#t322">322</a></span><span class="t"> <span class="com"># Calculate available space for flexible columns</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t323" href="#t323">323</a></span><span class="t"> <span class="nam">fixed_total</span> <span class="op">=</span> <span class="nam">sum</span><span class="op">(</span><span class="nam">fixed_columns</span><span class="op">.</span><span class="nam">values</span><span class="op">(</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t324" href="#t324">324</a></span><span class="t"> <span class="nam">flexible_available</span> <span class="op">=</span> <span class="nam">available_width</span> <span class="op">-</span> <span class="nam">fixed_total</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t325" href="#t325">325</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t326" href="#t326">326</a></span><span class="t"> <span class="com"># Get indices of flexible columns</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t327" href="#t327">327</a></span><span class="t"> <span class="nam">flexible_cols</span> <span class="op">=</span> <span class="op">[</span><span class="nam">i</span> <span class="key">for</span> <span class="nam">i</span> <span class="key">in</span> <span class="nam">range</span><span class="op">(</span><span class="nam">n_cols</span><span class="op">)</span> <span class="key">if</span> <span class="nam">i</span> <span class="key">not</span> <span class="key">in</span> <span class="nam">fixed_columns</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t328" href="#t328">328</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t329" href="#t329">329</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">flexible_cols</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t330" href="#t330">330</a></span><span class="t"> <span class="com"># All columns fixed - return as-is</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t331" href="#t331">331</a></span><span class="t"> <span class="key">return</span> <span class="op">[</span><span class="nam">fixed_columns</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="nam">i</span><span class="op">,</span> <span class="nam">min_widths</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span><span class="op">)</span> <span class="key">for</span> <span class="nam">i</span> <span class="key">in</span> <span class="nam">range</span><span class="op">(</span><span class="nam">n_cols</span><span class="op">)</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t332" href="#t332">332</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t333" href="#t333">333</a></span><span class="t"> <span class="com"># Calculate totals for flexible columns only</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t334" href="#t334">334</a></span><span class="t"> <span class="nam">flex_min_total</span> <span class="op">=</span> <span class="nam">sum</span><span class="op">(</span><span class="nam">min_widths</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span> <span class="key">for</span> <span class="nam">i</span> <span class="key">in</span> <span class="nam">flexible_cols</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t335" href="#t335">335</a></span><span class="t"> <span class="nam">flex_pref_total</span> <span class="op">=</span> <span class="nam">sum</span><span class="op">(</span><span class="nam">pref_widths</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span> <span class="key">for</span> <span class="nam">i</span> <span class="key">in</span> <span class="nam">flexible_cols</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t336" href="#t336">336</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t337" href="#t337">337</a></span><span class="t"> <span class="com"># Distribute space among flexible columns</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t338" href="#t338">338</a></span><span class="t"> <span class="nam">widths</span> <span class="op">=</span> <span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">*</span> <span class="nam">n_cols</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t339" href="#t339">339</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t340" href="#t340">340</a></span><span class="t"> <span class="com"># Set fixed columns</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t341" href="#t341">341</a></span><span class="t"> <span class="key">for</span> <span class="nam">i</span><span class="op">,</span> <span class="nam">width</span> <span class="key">in</span> <span class="nam">fixed_columns</span><span class="op">.</span><span class="nam">items</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t342" href="#t342">342</a></span><span class="t"> <span class="nam">widths</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span> <span class="op">=</span> <span class="nam">width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t343" href="#t343">343</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t344" href="#t344">344</a></span><span class="t"> <span class="com"># Distribute to flexible columns</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t345" href="#t345">345</a></span><span class="t"> <span class="key">if</span> <span class="nam">flex_pref_total</span> <span class="op">&lt;=</span> <span class="nam">flexible_available</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t346" href="#t346">346</a></span><span class="t"> <span class="com"># Preferred widths fit - distribute remaining space proportionally</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t347" href="#t347">347</a></span><span class="t"> <span class="nam">extra_space</span> <span class="op">=</span> <span class="nam">flexible_available</span> <span class="op">-</span> <span class="nam">flex_pref_total</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t348" href="#t348">348</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t349" href="#t349">349</a></span><span class="t"> <span class="key">if</span> <span class="nam">extra_space</span> <span class="op">></span> <span class="num">0</span> <span class="key">and</span> <span class="nam">flex_pref_total</span> <span class="op">></span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t350" href="#t350">350</a></span><span class="t"> <span class="com"># Distribute extra space proportionally based on preferred widths</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t351" href="#t351">351</a></span><span class="t"> <span class="key">for</span> <span class="nam">i</span> <span class="key">in</span> <span class="nam">flexible_cols</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t352" href="#t352">352</a></span><span class="t"> <span class="nam">proportion</span> <span class="op">=</span> <span class="nam">pref_widths</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span> <span class="op">/</span> <span class="nam">flex_pref_total</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t353" href="#t353">353</a></span><span class="t"> <span class="nam">widths</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">pref_widths</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span> <span class="op">+</span> <span class="op">(</span><span class="nam">extra_space</span> <span class="op">*</span> <span class="nam">proportion</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t354" href="#t354">354</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t355" href="#t355">355</a></span><span class="t"> <span class="com"># No extra space, just use preferred widths</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t356" href="#t356">356</a></span><span class="t"> <span class="key">for</span> <span class="nam">i</span> <span class="key">in</span> <span class="nam">flexible_cols</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t357" href="#t357">357</a></span><span class="t"> <span class="nam">widths</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span> <span class="op">=</span> <span class="nam">pref_widths</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t358" href="#t358">358</a></span><span class="t"> <span class="key">elif</span> <span class="nam">flex_min_total</span> <span class="op">></span> <span class="nam">flexible_available</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t359" href="#t359">359</a></span><span class="t"> <span class="com"># Can't satisfy minimum - force it anyway (graceful degradation)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t360" href="#t360">360</a></span><span class="t"> <span class="key">for</span> <span class="nam">i</span> <span class="key">in</span> <span class="nam">flexible_cols</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t361" href="#t361">361</a></span><span class="t"> <span class="nam">widths</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span> <span class="op">=</span> <span class="nam">min_widths</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t362" href="#t362">362</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t363" href="#t363">363</a></span><span class="t"> <span class="com"># Proportional distribution between min and pref</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t364" href="#t364">364</a></span><span class="t"> <span class="nam">extra_space</span> <span class="op">=</span> <span class="nam">flexible_available</span> <span class="op">-</span> <span class="nam">flex_min_total</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t365" href="#t365">365</a></span><span class="t"> <span class="nam">flex_pref_over_min</span> <span class="op">=</span> <span class="nam">flex_pref_total</span> <span class="op">-</span> <span class="nam">flex_min_total</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t366" href="#t366">366</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t367" href="#t367">367</a></span><span class="t"> <span class="key">for</span> <span class="nam">i</span> <span class="key">in</span> <span class="nam">flexible_cols</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t368" href="#t368">368</a></span><span class="t"> <span class="key">if</span> <span class="nam">flex_pref_over_min</span> <span class="op">></span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">368&#x202F;&#x219B;&#x202F;374</span><span class="annotate long">line 368 didn't jump to line 374 because the condition on line 368 was always true</span></span></p>
<p class="run"><span class="n"><a id="t369" href="#t369">369</a></span><span class="t"> <span class="nam">pref_over_min</span> <span class="op">=</span> <span class="nam">pref_widths</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span> <span class="op">-</span> <span class="nam">min_widths</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t370" href="#t370">370</a></span><span class="t"> <span class="nam">proportion</span> <span class="op">=</span> <span class="nam">pref_over_min</span> <span class="op">/</span> <span class="nam">flex_pref_over_min</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t371" href="#t371">371</a></span><span class="t"> <span class="nam">extra</span> <span class="op">=</span> <span class="nam">extra_space</span> <span class="op">*</span> <span class="nam">proportion</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t372" href="#t372">372</a></span><span class="t"> <span class="nam">widths</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">min_widths</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span> <span class="op">+</span> <span class="nam">extra</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t373" href="#t373">373</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t374" href="#t374">374</a></span><span class="t"> <span class="nam">widths</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">min_widths</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t375" href="#t375">375</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t376" href="#t376">376</a></span><span class="t"> <span class="key">return</span> <span class="nam">widths</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t377" href="#t377">377</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t378" href="#t378">378</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t379" href="#t379">379</a></span><span class="t"><span class="key">def</span> <span class="nam">calculate_table_overhead</span><span class="op">(</span><span class="nam">n_cols</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">style</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t380" href="#t380">380</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t381" href="#t381">381</a></span><span class="t"><span class="str"> Calculate the pixel overhead for table borders and spacing.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t382" href="#t382">382</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t383" href="#t383">383</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t384" href="#t384">384</a></span><span class="t"><span class="str"> n_cols: Number of columns</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t385" href="#t385">385</a></span><span class="t"><span class="str"> style: TableStyle object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t386" href="#t386">386</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t387" href="#t387">387</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t388" href="#t388">388</a></span><span class="t"><span class="str"> Total pixel overhead</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t389" href="#t389">389</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t390" href="#t390">390</a></span><span class="t"> <span class="com"># Border on each side of each column + outer borders</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t391" href="#t391">391</a></span><span class="t"> <span class="nam">border_overhead</span> <span class="op">=</span> <span class="nam">style</span><span class="op">.</span><span class="nam">border_width</span> <span class="op">*</span> <span class="op">(</span><span class="nam">n_cols</span> <span class="op">+</span> <span class="num">1</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t392" href="#t392">392</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t393" href="#t393">393</a></span><span class="t"> <span class="com"># Cell spacing if any</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t394" href="#t394">394</a></span><span class="t"> <span class="nam">spacing_overhead</span> <span class="op">=</span> <span class="nam">style</span><span class="op">.</span><span class="nam">cell_spacing</span> <span class="op">*</span> <span class="op">(</span><span class="nam">n_cols</span> <span class="op">-</span> <span class="num">1</span><span class="op">)</span> <span class="key">if</span> <span class="nam">n_cols</span> <span class="op">></span> <span class="num">1</span> <span class="key">else</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t395" href="#t395">395</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t396" href="#t396">396</a></span><span class="t"> <span class="key">return</span> <span class="nam">border_overhead</span> <span class="op">+</span> <span class="nam">spacing_overhead</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_427cc3035faf7633_page_buffer_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_ba7f6bdeb0188088___init___py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,124 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/concrete/__init__.py: 100%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/concrete/__init__.py</b>:
<span class="pc_cov">100%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">7 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">7<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">0<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">1<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">0<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_af715639580e2d86_interactive_image_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_7d48e1f4c6486fa2_box_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">Concrete layer for the pyWebLayout library.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">This package contains concrete implementations that can be directly rendered.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">text</span> <span class="key">import</span> <span class="nam">Text</span><span class="op">,</span> <span class="nam">Line</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">box</span> <span class="key">import</span> <span class="nam">Box</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">image</span> <span class="key">import</span> <span class="nam">RenderableImage</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">page</span> <span class="key">import</span> <span class="nam">Page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">block</span> <span class="key">import</span> <span class="nam">Table</span><span class="op">,</span> <span class="nam">TableRow</span> <span class="key">as</span> <span class="nam">Row</span><span class="op">,</span> <span class="nam">TableCell</span> <span class="key">as</span> <span class="nam">Cell</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">functional</span> <span class="key">import</span> <span class="nam">LinkText</span><span class="op">,</span> <span class="nam">ButtonText</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t"><span class="nam">__all__</span> <span class="op">=</span> <span class="op">[</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"> <span class="str">'Text'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"> <span class="str">'Line'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"> <span class="str">'Box'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"> <span class="str">'RenderableImage'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"> <span class="str">'Page'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"> <span class="str">'Table'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"> <span class="str">'Row'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"> <span class="str">'Cell'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"> <span class="str">'LinkText'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"> <span class="str">'ButtonText'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_af715639580e2d86_interactive_image_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_7d48e1f4c6486fa2_box_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,139 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/concrete/box.py: 100%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/concrete/box.py</b>:
<span class="pc_cov">100%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">19 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">19<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">0<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">1<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">0<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_7d48e1f4c6486fa2___init___py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_7d48e1f4c6486fa2_dynamic_page_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="run"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="key">from</span> <span class="nam">__future__</span> <span class="key">import</span> <span class="nam">annotations</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="key">import</span> <span class="nam">numpy</span> <span class="key">as</span> <span class="nam">np</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t"><span class="key">from</span> <span class="nam">PIL</span> <span class="key">import</span> <span class="nam">Image</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">core</span><span class="op">.</span><span class="nam">base</span> <span class="key">import</span> <span class="nam">Renderable</span><span class="op">,</span> <span class="nam">Queriable</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">core</span> <span class="key">import</span> <span class="nam">Geometric</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span> <span class="key">import</span> <span class="nam">Alignment</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="key">class</span> <span class="nam">Box</span><span class="op">(</span><span class="nam">Geometric</span><span class="op">,</span> <span class="nam">Renderable</span><span class="op">,</span> <span class="nam">Queriable</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="str"> A box with geometric properties (origin and size).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t"><span class="str"> Uses Geometric mixin for origin and size management.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"> <span class="nam">origin</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"> <span class="nam">size</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"> <span class="nam">callback</span><span class="op">=</span><span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"> <span class="nam">sheet</span><span class="op">:</span> <span class="nam">Image</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"> <span class="nam">mode</span><span class="op">:</span> <span class="nam">bool</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"> <span class="nam">halign</span><span class="op">=</span><span class="nam">Alignment</span><span class="op">.</span><span class="nam">CENTER</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"> <span class="nam">valign</span><span class="op">=</span><span class="nam">Alignment</span><span class="op">.</span><span class="nam">CENTER</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="nam">origin</span><span class="op">=</span><span class="nam">origin</span><span class="op">,</span> <span class="nam">size</span><span class="op">=</span><span class="nam">size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_end</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_callback</span> <span class="op">=</span> <span class="nam">callback</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_sheet</span><span class="op">:</span> <span class="nam">Image</span> <span class="op">=</span> <span class="nam">sheet</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_sheet</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_mode</span> <span class="op">=</span> <span class="nam">mode</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_mode</span> <span class="op">=</span> <span class="nam">sheet</span><span class="op">.</span><span class="nam">mode</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_halign</span> <span class="op">=</span> <span class="nam">halign</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_valign</span> <span class="op">=</span> <span class="nam">valign</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"> <span class="com"># origin and size properties are provided by Geometric mixin</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"> <span class="key">def</span> <span class="nam">in_shape</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">point</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"> <span class="key">return</span> <span class="nam">np</span><span class="op">.</span><span class="nam">all</span><span class="op">(</span><span class="op">(</span><span class="nam">point</span> <span class="op">>=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">)</span> <span class="op">&amp;</span> <span class="op">(</span><span class="nam">point</span> <span class="op">&lt;</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_end</span><span class="op">)</span><span class="op">,</span> <span class="nam">axis</span><span class="op">=</span><span class="op">-</span><span class="num">1</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_7d48e1f4c6486fa2___init___py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_7d48e1f4c6486fa2_dynamic_page_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,517 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/concrete/dynamic_page.py: 68%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/concrete/dynamic_page.py</b>:
<span class="pc_cov">68%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">178 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">136<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">42<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">17<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">19<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_7d48e1f4c6486fa2_box_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_7d48e1f4c6486fa2_functional_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">DynamicPage implementation for pyWebLayout.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">A DynamicPage is a page that dynamically sizes itself based on content and constraints.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">Unlike a regular Page with fixed size, a DynamicPage measures its content first and</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="str">then layouts within the allocated space.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="str">Use cases:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="str">- Table cells that need to fit content</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="str">- Containers that should grow with content</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="str">- Responsive layouts that adapt to constraints</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">Tuple</span><span class="op">,</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">List</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"><span class="key">from</span> <span class="nam">dataclasses</span> <span class="key">import</span> <span class="nam">dataclass</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"><span class="key">import</span> <span class="nam">numpy</span> <span class="key">as</span> <span class="nam">np</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"><span class="key">from</span> <span class="nam">PIL</span> <span class="key">import</span> <span class="nam">Image</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span><span class="op">.</span><span class="nam">page</span> <span class="key">import</span> <span class="nam">Page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">page_style</span> <span class="key">import</span> <span class="nam">PageStyle</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">core</span><span class="op">.</span><span class="nam">base</span> <span class="key">import</span> <span class="nam">Renderable</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"><span class="op">@</span><span class="nam">dataclass</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"><span class="key">class</span> <span class="nam">SizeConstraints</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"> <span class="str">"""Size constraints for dynamic layout."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"> <span class="nam">min_width</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t"> <span class="nam">max_width</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"> <span class="nam">min_height</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"> <span class="nam">max_height</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"> <span class="com"># Note: Hyphenation threshold is controlled by Font.min_hyphenation_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"> <span class="com"># Don't duplicate that logic here</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"><span class="key">class</span> <span class="nam">DynamicPage</span><span class="op">(</span><span class="nam">Page</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"><span class="str"> A page that dynamically sizes itself based on content and constraints.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"><span class="str"> The layout process has two phases:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"><span class="str"> 1. Measurement: Calculate intrinsic size needed for content</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t"><span class="str"> 2. Layout: Position content within allocated size</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t"><span class="str"> This allows containers (like tables) to optimize space allocation before rendering.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"> <span class="nam">constraints</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">SizeConstraints</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"> <span class="nam">style</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">PageStyle</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"><span class="str"> Initialize a dynamic page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"><span class="str"> constraints: Optional size constraints (min/max width/height)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t"><span class="str"> style: The PageStyle defining borders, spacing, and appearance</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t"> <span class="com"># Start with zero size - will be determined during measurement/layout</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="nam">size</span><span class="op">=</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">,</span> <span class="nam">style</span><span class="op">=</span><span class="nam">style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_constraints</span> <span class="op">=</span> <span class="nam">constraints</span> <span class="key">if</span> <span class="nam">constraints</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span> <span class="key">else</span> <span class="nam">SizeConstraints</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"> <span class="com"># Measurement state</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_is_measured</span> <span class="op">=</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_intrinsic_size</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_min_width_cache</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_preferred_width_cache</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_content_height_cache</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t"> <span class="com"># Pagination state</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_render_offset</span> <span class="op">=</span> <span class="num">0</span> <span class="com"># For partial rendering (pagination)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_is_laid_out</span> <span class="op">=</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t"> <span class="key">def</span> <span class="nam">constraints</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">SizeConstraints</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"> <span class="str">"""Get the size constraints for this page."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_constraints</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t"> <span class="key">def</span> <span class="nam">measure</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">available_width</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"><span class="str"> Measure the intrinsic size needed for content.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t"><span class="str"> This walks through all children and calculates how much space they need.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t"><span class="str"> The measurement respects constraints (min/max width/height).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"><span class="str"> available_width: Optional width constraint for wrapping content</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t"><span class="str"> Tuple of (width, height) needed</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_is_measured</span> <span class="key">and</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_intrinsic_size</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_intrinsic_size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t"> <span class="com"># Apply constraints to available width</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t"> <span class="key">if</span> <span class="nam">available_width</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_constraints</span><span class="op">.</span><span class="nam">max_width</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">94&#x202F;&#x219B;&#x202F;95</span><span class="annotate long">line 94 didn't jump to line 95 because the condition on line 94 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t"> <span class="nam">available_width</span> <span class="op">=</span> <span class="nam">min</span><span class="op">(</span><span class="nam">available_width</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_constraints</span><span class="op">.</span><span class="nam">max_width</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_constraints</span><span class="op">.</span><span class="nam">min_width</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t"> <span class="nam">available_width</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">available_width</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_constraints</span><span class="op">.</span><span class="nam">min_width</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"> <span class="com"># Measure content</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t"> <span class="com"># For now, walk through children and sum their sizes</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"> <span class="nam">total_width</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"> <span class="nam">total_height</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t"> <span class="key">for</span> <span class="nam">child</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_children</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">104&#x202F;&#x219B;&#x202F;105</span><span class="annotate long">line 104 didn't jump to line 105 because the loop on line 104 never started</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'measure'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t"> <span class="com"># Child is also dynamic - ask it to measure</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t"> <span class="nam">child_size</span> <span class="op">=</span> <span class="nam">child</span><span class="op">.</span><span class="nam">measure</span><span class="op">(</span><span class="nam">available_width</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t"> <span class="nam">child_width</span><span class="op">,</span> <span class="nam">child_height</span> <span class="op">=</span> <span class="nam">child_size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"> <span class="com"># Child has fixed size</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t"> <span class="nam">child_width</span> <span class="op">=</span> <span class="nam">child</span><span class="op">.</span><span class="nam">size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'size'</span><span class="op">)</span> <span class="key">else</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"> <span class="nam">child_height</span> <span class="op">=</span> <span class="nam">child</span><span class="op">.</span><span class="nam">size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'size'</span><span class="op">)</span> <span class="key">else</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t"> <span class="nam">total_width</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">total_width</span><span class="op">,</span> <span class="nam">child_width</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t"> <span class="nam">total_height</span> <span class="op">+=</span> <span class="nam">child_height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t"> <span class="com"># Add page padding/borders</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t"> <span class="nam">total_width</span> <span class="op">+=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">total_horizontal_padding</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">total_border_width</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"> <span class="nam">total_height</span> <span class="op">+=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">total_vertical_padding</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">total_border_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t"> <span class="com"># Apply constraints</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_constraints</span><span class="op">.</span><span class="nam">min_width</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"> <span class="nam">total_width</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">total_width</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_constraints</span><span class="op">.</span><span class="nam">min_width</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_constraints</span><span class="op">.</span><span class="nam">max_width</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">124&#x202F;&#x219B;&#x202F;125</span><span class="annotate long">line 124 didn't jump to line 125 because the condition on line 124 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t"> <span class="nam">total_width</span> <span class="op">=</span> <span class="nam">min</span><span class="op">(</span><span class="nam">total_width</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_constraints</span><span class="op">.</span><span class="nam">max_width</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_constraints</span><span class="op">.</span><span class="nam">min_height</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t"> <span class="nam">total_height</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">total_height</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_constraints</span><span class="op">.</span><span class="nam">min_height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_constraints</span><span class="op">.</span><span class="nam">max_height</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">128&#x202F;&#x219B;&#x202F;129</span><span class="annotate long">line 128 didn't jump to line 129 because the condition on line 128 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t"> <span class="nam">total_height</span> <span class="op">=</span> <span class="nam">min</span><span class="op">(</span><span class="nam">total_height</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_constraints</span><span class="op">.</span><span class="nam">max_height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_intrinsic_size</span> <span class="op">=</span> <span class="op">(</span><span class="nam">total_width</span><span class="op">,</span> <span class="nam">total_height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_is_measured</span> <span class="op">=</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_intrinsic_size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_min_width</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"><span class="str"> Get minimum width needed to render content.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t"><span class="str"> This finds the widest word/element that cannot be broken,</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t"><span class="str"> using Font.min_hyphenation_width for hyphenation control.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"><span class="str"> Minimum width in pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t"> <span class="com"># Check cache</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_min_width_cache</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">147&#x202F;&#x219B;&#x202F;148</span><span class="annotate long">line 147 didn't jump to line 148 because the condition on line 147 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_min_width_cache</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t"> <span class="com"># Calculate minimum width based on content</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span><span class="op">.</span><span class="nam">text</span> <span class="key">import</span> <span class="nam">Line</span><span class="op">,</span> <span class="nam">Text</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t"> <span class="nam">min_width</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t"> <span class="com"># Walk through children and find longest unbreakable segment</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t"> <span class="key">for</span> <span class="nam">child</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_children</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="nam">Line</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">157&#x202F;&#x219B;&#x202F;170</span><span class="annotate long">line 157 didn't jump to line 170 because the condition on line 157 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t"> <span class="com"># Check all words in the line</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t"> <span class="com"># Font's min_hyphenation_width already controls breaking</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"> <span class="key">for</span> <span class="nam">text_obj</span> <span class="key">in</span> <span class="nam">getattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'_text_objects'</span><span class="op">,</span> <span class="op">[</span><span class="op">]</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">text_obj</span><span class="op">,</span> <span class="nam">Text</span><span class="op">)</span> <span class="key">and</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">text_obj</span><span class="op">,</span> <span class="str">'_text'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">161&#x202F;&#x219B;&#x202F;160</span><span class="annotate long">line 161 didn't jump to line 160 because the condition on line 161 was always true</span></span></p>
<p class="run"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t"> <span class="nam">word_text</span> <span class="op">=</span> <span class="nam">text_obj</span><span class="op">.</span><span class="nam">_text</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"> <span class="com"># Text stores font in _style, not _font</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t"> <span class="nam">font</span> <span class="op">=</span> <span class="nam">getattr</span><span class="op">(</span><span class="nam">text_obj</span><span class="op">,</span> <span class="str">'_style'</span><span class="op">,</span> <span class="key">None</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"> <span class="key">if</span> <span class="nam">font</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">166&#x202F;&#x219B;&#x202F;160</span><span class="annotate long">line 166 didn't jump to line 160 because the condition on line 166 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t"> <span class="com"># Just measure the word - Font handles hyphenation rules</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t"> <span class="nam">word_width</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">font</span><span class="op">.</span><span class="nam">font</span><span class="op">.</span><span class="nam">getlength</span><span class="op">(</span><span class="nam">word_text</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t"> <span class="nam">min_width</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">min_width</span><span class="op">,</span> <span class="nam">word_width</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"> <span class="key">elif</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'get_min_width'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t"> <span class="com"># Child supports min width calculation</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t"> <span class="nam">child_min</span> <span class="op">=</span> <span class="nam">child</span><span class="op">.</span><span class="nam">get_min_width</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t"> <span class="nam">min_width</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">min_width</span><span class="op">,</span> <span class="nam">child_min</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t"> <span class="key">elif</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'size'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t"> <span class="com"># Use actual width</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t"> <span class="nam">min_width</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">min_width</span><span class="op">,</span> <span class="nam">child</span><span class="op">.</span><span class="nam">size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t"> <span class="com"># Add padding/borders</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t"> <span class="nam">min_width</span> <span class="op">+=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">total_horizontal_padding</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">total_border_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t"> <span class="com"># Apply minimum constraint</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_constraints</span><span class="op">.</span><span class="nam">min_width</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">182&#x202F;&#x219B;&#x202F;183</span><span class="annotate long">line 182 didn't jump to line 183 because the condition on line 182 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t"> <span class="nam">min_width</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">min_width</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_constraints</span><span class="op">.</span><span class="nam">min_width</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_min_width_cache</span> <span class="op">=</span> <span class="nam">min_width</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t"> <span class="key">return</span> <span class="nam">min_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_preferred_width</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t"><span class="str"> Get preferred width (no wrapping).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t"><span class="str"> This returns the width needed to render all content without any</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t"><span class="str"> line wrapping.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t"><span class="str"> Preferred width in pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t"> <span class="com"># Check cache</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_preferred_width_cache</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">199&#x202F;&#x219B;&#x202F;200</span><span class="annotate long">line 199 didn't jump to line 200 because the condition on line 199 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_preferred_width_cache</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t"> <span class="com"># Calculate preferred width (no wrapping)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span><span class="op">.</span><span class="nam">text</span> <span class="key">import</span> <span class="nam">Line</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t"> <span class="nam">pref_width</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t"> <span class="key">for</span> <span class="nam">child</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_children</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="nam">Line</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">208&#x202F;&#x219B;&#x202F;227</span><span class="annotate long">line 208 didn't jump to line 227 because the condition on line 208 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t"> <span class="com"># Get line width without wrapping (including spacing between words)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t"> <span class="nam">text_objects</span> <span class="op">=</span> <span class="nam">getattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'_text_objects'</span><span class="op">,</span> <span class="op">[</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t"> <span class="key">if</span> <span class="nam">text_objects</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">211&#x202F;&#x219B;&#x202F;207</span><span class="annotate long">line 211 didn't jump to line 207 because the condition on line 211 was always true</span></span></p>
<p class="run"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t"> <span class="nam">line_width</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"> <span class="key">for</span> <span class="nam">i</span><span class="op">,</span> <span class="nam">text_obj</span> <span class="key">in</span> <span class="nam">enumerate</span><span class="op">(</span><span class="nam">text_objects</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">text_obj</span><span class="op">,</span> <span class="str">'_text'</span><span class="op">)</span> <span class="key">and</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">text_obj</span><span class="op">,</span> <span class="str">'_style'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">214&#x202F;&#x219B;&#x202F;213</span><span class="annotate long">line 214 didn't jump to line 213 because the condition on line 214 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t"> <span class="com"># Text stores font in _style, not _font</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t"> <span class="nam">word_width</span> <span class="op">=</span> <span class="nam">text_obj</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">font</span><span class="op">.</span><span class="nam">getlength</span><span class="op">(</span><span class="nam">text_obj</span><span class="op">.</span><span class="nam">_text</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t"> <span class="nam">line_width</span> <span class="op">+=</span> <span class="nam">word_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t"> <span class="com"># Add spacing after word (except last word)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t"> <span class="key">if</span> <span class="nam">i</span> <span class="op">&lt;</span> <span class="nam">len</span><span class="op">(</span><span class="nam">text_objects</span><span class="op">)</span> <span class="op">-</span> <span class="num">1</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t"> <span class="com"># Get spacing from Line if available, otherwise use default</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"> <span class="nam">spacing</span> <span class="op">=</span> <span class="nam">getattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'_spacing'</span><span class="op">,</span> <span class="op">(</span><span class="num">3</span><span class="op">,</span> <span class="num">6</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t"> <span class="com"># Use minimum spacing for preferred width calculation</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t"> <span class="nam">line_width</span> <span class="op">+=</span> <span class="nam">spacing</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">spacing</span><span class="op">,</span> <span class="nam">tuple</span><span class="op">)</span> <span class="key">else</span> <span class="num">3</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t"> <span class="nam">pref_width</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">pref_width</span><span class="op">,</span> <span class="nam">line_width</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t"> <span class="key">elif</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'get_preferred_width'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t"> <span class="nam">child_pref</span> <span class="op">=</span> <span class="nam">child</span><span class="op">.</span><span class="nam">get_preferred_width</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t"> <span class="nam">pref_width</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">pref_width</span><span class="op">,</span> <span class="nam">child_pref</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t"> <span class="key">elif</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'size'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t"> <span class="com"># Use actual size</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t"> <span class="nam">pref_width</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">pref_width</span><span class="op">,</span> <span class="nam">child</span><span class="op">.</span><span class="nam">size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t"> <span class="com"># Add padding/borders</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t"> <span class="nam">pref_width</span> <span class="op">+=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">total_horizontal_padding</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">total_border_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t"> <span class="com"># Apply constraints</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_constraints</span><span class="op">.</span><span class="nam">max_width</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">238&#x202F;&#x219B;&#x202F;239</span><span class="annotate long">line 238 didn't jump to line 239 because the condition on line 238 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t"> <span class="nam">pref_width</span> <span class="op">=</span> <span class="nam">min</span><span class="op">(</span><span class="nam">pref_width</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_constraints</span><span class="op">.</span><span class="nam">max_width</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_constraints</span><span class="op">.</span><span class="nam">min_width</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">240&#x202F;&#x219B;&#x202F;241</span><span class="annotate long">line 240 didn't jump to line 241 because the condition on line 240 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t"> <span class="nam">pref_width</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">pref_width</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_constraints</span><span class="op">.</span><span class="nam">min_width</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_preferred_width_cache</span> <span class="op">=</span> <span class="nam">pref_width</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t"> <span class="key">return</span> <span class="nam">pref_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t"> <span class="key">def</span> <span class="nam">measure_content_height</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t"><span class="str"> Measure total height needed to render all content.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t"><span class="str"> This is used for pagination to know how much content remains.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t"><span class="str"> Total height in pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t"> <span class="com"># Check cache</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_content_height_cache</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_content_height_cache</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t"> <span class="nam">total_height</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t"> <span class="key">for</span> <span class="nam">child</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_children</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">261&#x202F;&#x219B;&#x202F;262</span><span class="annotate long">line 261 didn't jump to line 262 because the loop on line 261 never started</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'measure_content_height'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t"> <span class="nam">child_height</span> <span class="op">=</span> <span class="nam">child</span><span class="op">.</span><span class="nam">measure_content_height</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t"> <span class="key">elif</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'size'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t"> <span class="nam">child_height</span> <span class="op">=</span> <span class="nam">child</span><span class="op">.</span><span class="nam">size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t"> <span class="nam">child_height</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t"> <span class="nam">total_height</span> <span class="op">+=</span> <span class="nam">child_height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t"> <span class="com"># Add padding/borders</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t"> <span class="nam">total_height</span> <span class="op">+=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">total_vertical_padding</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">total_border_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_content_height_cache</span> <span class="op">=</span> <span class="nam">total_height</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t"> <span class="key">return</span> <span class="nam">total_height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t"> <span class="key">def</span> <span class="nam">layout</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">size</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t279" href="#t279">279</a></span><span class="t"><span class="str"> Layout content within the given size.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t280" href="#t280">280</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t281" href="#t281">281</a></span><span class="t"><span class="str"> This is called after measurement to position children within</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t282" href="#t282">282</a></span><span class="t"><span class="str"> the allocated space.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t283" href="#t283">283</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t284" href="#t284">284</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t285" href="#t285">285</a></span><span class="t"><span class="str"> size: The final size allocated to this page (width, height)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t286" href="#t286">286</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t287" href="#t287">287</a></span><span class="t"> <span class="com"># Set the page size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t288" href="#t288">288</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span> <span class="op">=</span> <span class="nam">size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t289" href="#t289">289</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t290" href="#t290">290</a></span><span class="t"> <span class="com"># Position children sequentially</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t291" href="#t291">291</a></span><span class="t"> <span class="com"># Use the same logic as Page but now we know our final size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t292" href="#t292">292</a></span><span class="t"> <span class="nam">content_x</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">border_width</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">padding_left</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t293" href="#t293">293</a></span><span class="t"> <span class="nam">content_y</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">border_width</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">padding_top</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t294" href="#t294">294</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t295" href="#t295">295</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_current_y_offset</span> <span class="op">=</span> <span class="nam">content_y</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t296" href="#t296">296</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_is_first_line</span> <span class="op">=</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t297" href="#t297">297</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t298" href="#t298">298</a></span><span class="t"> <span class="com"># Children position themselves, we just track y_offset</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t299" href="#t299">299</a></span><span class="t"> <span class="com"># The actual positioning happens when children render</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t300" href="#t300">300</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t301" href="#t301">301</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_is_laid_out</span> <span class="op">=</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t302" href="#t302">302</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_dirty</span> <span class="op">=</span> <span class="key">True</span> <span class="com"># Mark for re-render</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t303" href="#t303">303</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t304" href="#t304">304</a></span><span class="t"> <span class="key">def</span> <span class="nam">render</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Image</span><span class="op">.</span><span class="nam">Image</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t305" href="#t305">305</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t306" href="#t306">306</a></span><span class="t"><span class="str"> Render the page with all its children.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t307" href="#t307">307</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t308" href="#t308">308</a></span><span class="t"><span class="str"> If not yet measured/laid out, use intrinsic sizing.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t309" href="#t309">309</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t310" href="#t310">310</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t311" href="#t311">311</a></span><span class="t"><span class="str"> PIL Image containing the rendered page</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t312" href="#t312">312</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t313" href="#t313">313</a></span><span class="t"> <span class="com"># Ensure we have a valid size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t314" href="#t314">314</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">==</span> <span class="num">0</span> <span class="key">or</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">==</span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t315" href="#t315">315</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_is_measured</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">315&#x202F;&#x219B;&#x202F;319</span><span class="annotate long">line 315 didn't jump to line 319 because the condition on line 315 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t316" href="#t316">316</a></span><span class="t"> <span class="com"># Auto-measure with no constraints</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t317" href="#t317">317</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">measure</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t318" href="#t318">318</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t319" href="#t319">319</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_intrinsic_size</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">319&#x202F;&#x219B;&#x202F;323</span><span class="annotate long">line 319 didn't jump to line 323 because the condition on line 319 was always true</span></span></p>
<p class="run"><span class="n"><a id="t320" href="#t320">320</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_intrinsic_size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t321" href="#t321">321</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t322" href="#t322">322</a></span><span class="t"> <span class="com"># Fallback to minimum size</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t323" href="#t323">323</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span> <span class="op">=</span> <span class="op">(</span><span class="num">100</span><span class="op">,</span> <span class="num">100</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t324" href="#t324">324</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t325" href="#t325">325</a></span><span class="t"> <span class="com"># Use parent's render implementation</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t326" href="#t326">326</a></span><span class="t"> <span class="key">return</span> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">render</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t327" href="#t327">327</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t328" href="#t328">328</a></span><span class="t"> <span class="com"># Pagination Support</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t329" href="#t329">329</a></span><span class="t"> <span class="com"># ------------------</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t330" href="#t330">330</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t331" href="#t331">331</a></span><span class="t"> <span class="key">def</span> <span class="nam">render_partial</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">available_height</span><span class="op">:</span> <span class="nam">int</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t332" href="#t332">332</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t333" href="#t333">333</a></span><span class="t"><span class="str"> Render as much content as fits in available_height.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t334" href="#t334">334</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t335" href="#t335">335</a></span><span class="t"><span class="str"> This is used for pagination when a page needs to be split across</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t336" href="#t336">336</a></span><span class="t"><span class="str"> multiple output pages.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t337" href="#t337">337</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t338" href="#t338">338</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t339" href="#t339">339</a></span><span class="t"><span class="str"> available_height: Height available on current page</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t340" href="#t340">340</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t341" href="#t341">341</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t342" href="#t342">342</a></span><span class="t"><span class="str"> Amount of content rendered (in pixels)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t343" href="#t343">343</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t344" href="#t344">344</a></span><span class="t"> <span class="com"># Calculate how many children fit in available height</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t345" href="#t345">345</a></span><span class="t"> <span class="nam">rendered_height</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t346" href="#t346">346</a></span><span class="t"> <span class="nam">content_start_y</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">border_width</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">padding_top</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t347" href="#t347">347</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t348" href="#t348">348</a></span><span class="t"> <span class="key">for</span> <span class="nam">i</span><span class="op">,</span> <span class="nam">child</span> <span class="key">in</span> <span class="nam">enumerate</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_children</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">348&#x202F;&#x219B;&#x202F;350</span><span class="annotate long">line 348 didn't jump to line 350 because the loop on line 348 never started</span></span></p>
<p class="pln"><span class="n"><a id="t349" href="#t349">349</a></span><span class="t"> <span class="com"># Skip already rendered children</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t350" href="#t350">350</a></span><span class="t"> <span class="key">if</span> <span class="nam">rendered_height</span> <span class="op">&lt;</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_render_offset</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t351" href="#t351">351</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'size'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t352" href="#t352">352</a></span><span class="t"> <span class="nam">rendered_height</span> <span class="op">+=</span> <span class="nam">child</span><span class="op">.</span><span class="nam">size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t353" href="#t353">353</a></span><span class="t"> <span class="key">continue</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t354" href="#t354">354</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t355" href="#t355">355</a></span><span class="t"> <span class="com"># Check if this child fits</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t356" href="#t356">356</a></span><span class="t"> <span class="nam">child_height</span> <span class="op">=</span> <span class="nam">child</span><span class="op">.</span><span class="nam">size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'size'</span><span class="op">)</span> <span class="key">else</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t357" href="#t357">357</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t358" href="#t358">358</a></span><span class="t"> <span class="key">if</span> <span class="nam">rendered_height</span> <span class="op">+</span> <span class="nam">child_height</span> <span class="op">&lt;=</span> <span class="nam">available_height</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t359" href="#t359">359</a></span><span class="t"> <span class="com"># Child fits - render it</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t360" href="#t360">360</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'render'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t361" href="#t361">361</a></span><span class="t"> <span class="nam">child</span><span class="op">.</span><span class="nam">render</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t362" href="#t362">362</a></span><span class="t"> <span class="nam">rendered_height</span> <span class="op">+=</span> <span class="nam">child_height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t363" href="#t363">363</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t364" href="#t364">364</a></span><span class="t"> <span class="com"># No more space</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t365" href="#t365">365</a></span><span class="t"> <span class="key">break</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t366" href="#t366">366</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t367" href="#t367">367</a></span><span class="t"> <span class="com"># Update render offset for next call</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t368" href="#t368">368</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_render_offset</span> <span class="op">=</span> <span class="nam">rendered_height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t369" href="#t369">369</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t370" href="#t370">370</a></span><span class="t"> <span class="key">return</span> <span class="nam">rendered_height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t371" href="#t371">371</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t372" href="#t372">372</a></span><span class="t"> <span class="key">def</span> <span class="nam">has_more_content</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t373" href="#t373">373</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t374" href="#t374">374</a></span><span class="t"><span class="str"> Check if there's unrendered content remaining.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t375" href="#t375">375</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t376" href="#t376">376</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t377" href="#t377">377</a></span><span class="t"><span class="str"> True if more content needs to be rendered</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t378" href="#t378">378</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t379" href="#t379">379</a></span><span class="t"> <span class="nam">total_height</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">measure_content_height</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t380" href="#t380">380</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_render_offset</span> <span class="op">&lt;</span> <span class="nam">total_height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t381" href="#t381">381</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t382" href="#t382">382</a></span><span class="t"> <span class="key">def</span> <span class="nam">reset_pagination</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t383" href="#t383">383</a></span><span class="t"> <span class="str">"""Reset pagination to render from beginning."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t384" href="#t384">384</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_render_offset</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t385" href="#t385">385</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t386" href="#t386">386</a></span><span class="t"> <span class="key">def</span> <span class="nam">invalidate_caches</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t387" href="#t387">387</a></span><span class="t"> <span class="str">"""Invalidate all measurement caches (call when children change)."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t388" href="#t388">388</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_is_measured</span> <span class="op">=</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t389" href="#t389">389</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_intrinsic_size</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t390" href="#t390">390</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_min_width_cache</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t391" href="#t391">391</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_preferred_width_cache</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t392" href="#t392">392</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_content_height_cache</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t393" href="#t393">393</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_is_laid_out</span> <span class="op">=</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t394" href="#t394">394</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t395" href="#t395">395</a></span><span class="t"> <span class="key">def</span> <span class="nam">add_child</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">child</span><span class="op">:</span> <span class="nam">Renderable</span><span class="op">)</span> <span class="op">-></span> <span class="str">'DynamicPage'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t396" href="#t396">396</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t397" href="#t397">397</a></span><span class="t"><span class="str"> Add a child and invalidate caches.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t398" href="#t398">398</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t399" href="#t399">399</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t400" href="#t400">400</a></span><span class="t"><span class="str"> child: The renderable object to add</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t401" href="#t401">401</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t402" href="#t402">402</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t403" href="#t403">403</a></span><span class="t"><span class="str"> Self for method chaining</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t404" href="#t404">404</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t405" href="#t405">405</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">add_child</span><span class="op">(</span><span class="nam">child</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t406" href="#t406">406</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">invalidate_caches</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t407" href="#t407">407</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t408" href="#t408">408</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t409" href="#t409">409</a></span><span class="t"> <span class="key">def</span> <span class="nam">clear_children</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="str">'DynamicPage'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t410" href="#t410">410</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t411" href="#t411">411</a></span><span class="t"><span class="str"> Remove all children and invalidate caches.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t412" href="#t412">412</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t413" href="#t413">413</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t414" href="#t414">414</a></span><span class="t"><span class="str"> Self for method chaining</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t415" href="#t415">415</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t416" href="#t416">416</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">clear_children</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t417" href="#t417">417</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">invalidate_caches</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t418" href="#t418">418</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_7d48e1f4c6486fa2_box_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_7d48e1f4c6486fa2_functional_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,560 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/concrete/functional.py: 87%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/concrete/functional.py</b>:
<span class="pc_cov">87%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">165 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">148<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">17<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">28<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">9<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_7d48e1f4c6486fa2_dynamic_page_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_7d48e1f4c6486fa2_image_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="run"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="key">from</span> <span class="nam">__future__</span> <span class="key">import</span> <span class="nam">annotations</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">Tuple</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t"><span class="key">import</span> <span class="nam">numpy</span> <span class="key">as</span> <span class="nam">np</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="key">from</span> <span class="nam">PIL</span> <span class="key">import</span> <span class="nam">ImageDraw</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">core</span><span class="op">.</span><span class="nam">base</span> <span class="key">import</span> <span class="nam">Interactable</span><span class="op">,</span> <span class="nam">Queriable</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">functional</span> <span class="key">import</span> <span class="nam">Link</span><span class="op">,</span> <span class="nam">Button</span><span class="op">,</span> <span class="nam">FormField</span><span class="op">,</span> <span class="nam">LinkType</span><span class="op">,</span> <span class="nam">FormFieldType</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span> <span class="key">import</span> <span class="nam">Font</span><span class="op">,</span> <span class="nam">TextDecoration</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">text</span> <span class="key">import</span> <span class="nam">Text</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="key">class</span> <span class="nam">LinkText</span><span class="op">(</span><span class="nam">Text</span><span class="op">,</span> <span class="nam">Interactable</span><span class="op">,</span> <span class="nam">Queriable</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t"><span class="str"> A Text subclass that can handle Link interactions.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"><span class="str"> Combines text rendering with clickable link functionality.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">link</span><span class="op">:</span> <span class="nam">Link</span><span class="op">,</span> <span class="nam">text</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span> <span class="nam">font</span><span class="op">:</span> <span class="nam">Font</span><span class="op">,</span> <span class="nam">draw</span><span class="op">:</span> <span class="nam">ImageDraw</span><span class="op">.</span><span class="nam">Draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"> <span class="nam">source</span><span class="op">=</span><span class="key">None</span><span class="op">,</span> <span class="nam">line</span><span class="op">=</span><span class="key">None</span><span class="op">,</span> <span class="nam">page</span><span class="op">=</span><span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"><span class="str"> Initialize a linkable text object.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"><span class="str"> link: The abstract Link object to handle interactions</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"><span class="str"> text: The text content to render</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"><span class="str"> font: The base font style</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"><span class="str"> draw: The drawing context</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t"><span class="str"> source: Optional source object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"><span class="str"> line: Optional line container</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"><span class="str"> page: Optional parent page (for dirty flag management)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"> <span class="com"># Create link-styled font (underlined and colored based on link type)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"> <span class="nam">link_font</span> <span class="op">=</span> <span class="nam">font</span><span class="op">.</span><span class="nam">with_decoration</span><span class="op">(</span><span class="nam">TextDecoration</span><span class="op">.</span><span class="nam">UNDERLINE</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"> <span class="key">if</span> <span class="nam">link</span><span class="op">.</span><span class="nam">link_type</span> <span class="op">==</span> <span class="nam">LinkType</span><span class="op">.</span><span class="nam">INTERNAL</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"> <span class="nam">link_font</span> <span class="op">=</span> <span class="nam">link_font</span><span class="op">.</span><span class="nam">with_colour</span><span class="op">(</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">200</span><span class="op">)</span><span class="op">)</span> <span class="com"># Blue for internal links</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"> <span class="key">elif</span> <span class="nam">link</span><span class="op">.</span><span class="nam">link_type</span> <span class="op">==</span> <span class="nam">LinkType</span><span class="op">.</span><span class="nam">EXTERNAL</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"> <span class="nam">link_font</span> <span class="op">=</span> <span class="nam">link_font</span><span class="op">.</span><span class="nam">with_colour</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t"> <span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">180</span><span class="op">)</span><span class="op">)</span> <span class="com"># Darker blue for external links</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"> <span class="key">elif</span> <span class="nam">link</span><span class="op">.</span><span class="nam">link_type</span> <span class="op">==</span> <span class="nam">LinkType</span><span class="op">.</span><span class="nam">API</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"> <span class="nam">link_font</span> <span class="op">=</span> <span class="nam">link_font</span><span class="op">.</span><span class="nam">with_colour</span><span class="op">(</span><span class="op">(</span><span class="num">150</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">)</span> <span class="com"># Red for API links</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t"> <span class="key">elif</span> <span class="nam">link</span><span class="op">.</span><span class="nam">link_type</span> <span class="op">==</span> <span class="nam">LinkType</span><span class="op">.</span><span class="nam">FUNCTION</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">41&#x202F;&#x219B;&#x202F;45</span><span class="annotate long">line 41 didn't jump to line 45 because the condition on line 41 was always true</span></span></p>
<p class="run"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t"> <span class="nam">link_font</span> <span class="op">=</span> <span class="nam">link_font</span><span class="op">.</span><span class="nam">with_colour</span><span class="op">(</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">120</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">)</span> <span class="com"># Green for function links</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"> <span class="com"># Initialize Text with the styled font</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t"> <span class="nam">Text</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">text</span><span class="op">,</span> <span class="nam">link_font</span><span class="op">,</span> <span class="nam">draw</span><span class="op">,</span> <span class="nam">source</span><span class="op">,</span> <span class="nam">line</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"> <span class="com"># Initialize Interactable with the link's execute method</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"> <span class="nam">Interactable</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">link</span><span class="op">.</span><span class="nam">execute</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"> <span class="com"># Store the link object and page reference</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_link</span> <span class="op">=</span> <span class="nam">link</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_page</span> <span class="op">=</span> <span class="nam">page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_hovered</span> <span class="op">=</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_pressed</span> <span class="op">=</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t"> <span class="com"># Ensure _origin is initialized as numpy array</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="str">'_origin'</span><span class="op">)</span> <span class="key">or</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">57&#x202F;&#x219B;&#x202F;58</span><span class="annotate long">line 57 didn't jump to line 58 because the condition on line 57 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="op">[</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"> <span class="key">def</span> <span class="nam">link</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Link</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t"> <span class="str">"""Get the associated Link object"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_link</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_hovered</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">hovered</span><span class="op">:</span> <span class="nam">bool</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t"> <span class="str">"""Set the hover state for visual feedback"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_hovered</span> <span class="op">=</span> <span class="nam">hovered</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_mark_page_dirty</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_pressed</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">pressed</span><span class="op">:</span> <span class="nam">bool</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t"> <span class="str">"""Set the pressed state for visual feedback"""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_pressed</span> <span class="op">=</span> <span class="nam">pressed</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_mark_page_dirty</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"> <span class="key">def</span> <span class="nam">_mark_page_dirty</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t"> <span class="str">"""Mark the parent page as dirty if available"""</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_page</span> <span class="key">and</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_page</span><span class="op">,</span> <span class="str">'mark_dirty'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">77&#x202F;&#x219B;&#x202F;78</span><span class="annotate long">line 77 didn't jump to line 78 because the condition on line 77 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_page</span><span class="op">.</span><span class="nam">mark_dirty</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t"> <span class="key">def</span> <span class="nam">render</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">next_text</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="str">'Text'</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span> <span class="nam">spacing</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">0</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t"><span class="str"> Render the link text with optional hover and pressed effects.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t"><span class="str"> next_text: The next Text object in the line (if any)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t"><span class="str"> spacing: The spacing to the next text object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t"> <span class="com"># Handle mock objects in tests</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"> <span class="nam">size</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">size</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">size</span><span class="op">,</span> <span class="str">'__call__'</span><span class="op">)</span><span class="op">:</span> <span class="com"># It's a Mock</span>&nbsp;</span><span class="r"><span class="annotate short">90&#x202F;&#x219B;&#x202F;92</span><span class="annotate long">line 90 didn't jump to line 92 because the condition on line 90 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t"> <span class="com"># Use default size for tests</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t"> <span class="nam">size</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="op">[</span><span class="num">100</span><span class="op">,</span> <span class="num">20</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t"> <span class="nam">size</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="nam">size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t"> <span class="com"># Ensure origin is a numpy array</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t"> <span class="nam">origin</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">)</span> <span class="key">if</span> <span class="key">not</span> <span class="nam">isinstance</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t"> <span class="nam">np</span><span class="op">.</span><span class="nam">ndarray</span><span class="op">)</span> <span class="key">else</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"> <span class="com"># Draw background based on state (before text is rendered)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_pressed</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">103&#x202F;&#x219B;&#x202F;105</span><span class="annotate long">line 103 didn't jump to line 105 because the condition on line 103 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t"> <span class="com"># Pressed state - stronger, darker highlight</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t"> <span class="nam">bg_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">180</span><span class="op">,</span> <span class="num">180</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">180</span><span class="op">)</span> <span class="com"># Stronger blue with more opacity</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">rectangle</span><span class="op">(</span><span class="op">[</span><span class="nam">origin</span><span class="op">,</span> <span class="nam">origin</span> <span class="op">+</span> <span class="nam">size</span><span class="op">]</span><span class="op">,</span> <span class="nam">fill</span><span class="op">=</span><span class="nam">bg_color</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t"> <span class="key">elif</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_hovered</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">107&#x202F;&#x219B;&#x202F;109</span><span class="annotate long">line 107 didn't jump to line 109 because the condition on line 107 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t"> <span class="com"># Hover state - subtle highlight</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t"> <span class="nam">bg_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">220</span><span class="op">,</span> <span class="num">220</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">100</span><span class="op">)</span> <span class="com"># Light blue with alpha</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">rectangle</span><span class="op">(</span><span class="op">[</span><span class="nam">origin</span><span class="op">,</span> <span class="nam">origin</span> <span class="op">+</span> <span class="nam">size</span><span class="op">]</span><span class="op">,</span> <span class="nam">fill</span><span class="op">=</span><span class="nam">bg_color</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"> <span class="com"># Call the parent Text render method with parameters</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">render</span><span class="op">(</span><span class="nam">next_text</span><span class="op">,</span> <span class="nam">spacing</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"><span class="key">class</span> <span class="nam">ButtonText</span><span class="op">(</span><span class="nam">Text</span><span class="op">,</span> <span class="nam">Interactable</span><span class="op">,</span> <span class="nam">Queriable</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t"><span class="str"> A Text subclass that can handle Button interactions.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"><span class="str"> Renders text as a clickable button with visual states.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">button</span><span class="op">:</span> <span class="nam">Button</span><span class="op">,</span> <span class="nam">font</span><span class="op">:</span> <span class="nam">Font</span><span class="op">,</span> <span class="nam">draw</span><span class="op">:</span> <span class="nam">ImageDraw</span><span class="op">.</span><span class="nam">Draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"> <span class="nam">padding</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="op">(</span><span class="num">4</span><span class="op">,</span> <span class="num">8</span><span class="op">,</span> <span class="num">4</span><span class="op">,</span> <span class="num">8</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t"> <span class="nam">source</span><span class="op">=</span><span class="key">None</span><span class="op">,</span> <span class="nam">line</span><span class="op">=</span><span class="key">None</span><span class="op">,</span> <span class="nam">page</span><span class="op">=</span><span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t"><span class="str"> Initialize a button text object.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t"><span class="str"> button: The abstract Button object to handle interactions</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t"><span class="str"> font: The base font style</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t"><span class="str"> draw: The drawing context</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t"><span class="str"> padding: Padding around the button text (top, right, bottom, left)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t"><span class="str"> source: Optional source object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t"><span class="str"> line: Optional line container</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t"><span class="str"> page: Optional parent page (for dirty flag management)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t"> <span class="com"># Initialize Text with the button label</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"> <span class="nam">Text</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">button</span><span class="op">.</span><span class="nam">label</span><span class="op">,</span> <span class="nam">font</span><span class="op">,</span> <span class="nam">draw</span><span class="op">,</span> <span class="nam">source</span><span class="op">,</span> <span class="nam">line</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t"> <span class="com"># Initialize Interactable with the button's execute method</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t"> <span class="nam">Interactable</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">button</span><span class="op">.</span><span class="nam">execute</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t"> <span class="com"># Store button properties</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_button</span> <span class="op">=</span> <span class="nam">button</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_padding</span> <span class="op">=</span> <span class="nam">padding</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_page</span> <span class="op">=</span> <span class="nam">page</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_pressed</span> <span class="op">=</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_hovered</span> <span class="op">=</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t"> <span class="com"># Recalculate dimensions to include padding</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t"> <span class="com"># Use getattr to handle mock objects in tests</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t"> <span class="nam">text_width</span> <span class="op">=</span> <span class="nam">getattr</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span> <span class="str">'_width'</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span> <span class="key">if</span> <span class="key">not</span> <span class="nam">hasattr</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_width</span><span class="op">,</span> <span class="str">'__call__'</span><span class="op">)</span> <span class="key">else</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_padded_width</span> <span class="op">=</span> <span class="nam">text_width</span> <span class="op">+</span> <span class="nam">padding</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">+</span> <span class="nam">padding</span><span class="op">[</span><span class="num">3</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_padded_height</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">font_size</span> <span class="op">+</span> <span class="nam">padding</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">+</span> <span class="nam">padding</span><span class="op">[</span><span class="num">2</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t"> <span class="key">def</span> <span class="nam">button</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Button</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"> <span class="str">"""Get the associated Button object"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_button</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t"> <span class="key">def</span> <span class="nam">size</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">np</span><span class="op">.</span><span class="nam">ndarray</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t"> <span class="str">"""Get the padded size of the button"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"> <span class="key">return</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="op">[</span><span class="nam">self</span><span class="op">.</span><span class="nam">_padded_width</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_padded_height</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_pressed</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">pressed</span><span class="op">:</span> <span class="nam">bool</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t"> <span class="str">"""Set the pressed state"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_pressed</span> <span class="op">=</span> <span class="nam">pressed</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_mark_page_dirty</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_hovered</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">hovered</span><span class="op">:</span> <span class="nam">bool</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t"> <span class="str">"""Set the hover state"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_hovered</span> <span class="op">=</span> <span class="nam">hovered</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_mark_page_dirty</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_page</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">page</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t"><span class="str"> Set the parent page reference for dirty flag management.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t"><span class="str"> page: The Page object containing this element</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_page</span> <span class="op">=</span> <span class="nam">page</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t"> <span class="key">def</span> <span class="nam">_mark_page_dirty</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t"> <span class="str">"""Mark the parent page as dirty if available"""</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_page</span> <span class="key">and</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_page</span><span class="op">,</span> <span class="str">'mark_dirty'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">189&#x202F;&#x219B;&#x202F;190</span><span class="annotate long">line 189 didn't jump to line 190 because the condition on line 189 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_page</span><span class="op">.</span><span class="nam">mark_dirty</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t"> <span class="key">def</span> <span class="nam">render</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t"><span class="str"> Render the button with background, border, and text.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t"> <span class="com"># Determine button colors based on state</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_button</span><span class="op">.</span><span class="nam">enabled</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t"> <span class="com"># Disabled button</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t"> <span class="nam">bg_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">200</span><span class="op">,</span> <span class="num">200</span><span class="op">,</span> <span class="num">200</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t"> <span class="nam">border_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">150</span><span class="op">,</span> <span class="num">150</span><span class="op">,</span> <span class="num">150</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t"> <span class="nam">text_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">100</span><span class="op">,</span> <span class="num">100</span><span class="op">,</span> <span class="num">100</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t"> <span class="key">elif</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_pressed</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">202&#x202F;&#x219B;&#x202F;204</span><span class="annotate long">line 202 didn't jump to line 204 because the condition on line 202 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t"> <span class="com"># Pressed button</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t"> <span class="nam">bg_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">70</span><span class="op">,</span> <span class="num">130</span><span class="op">,</span> <span class="num">180</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t"> <span class="nam">border_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">50</span><span class="op">,</span> <span class="num">100</span><span class="op">,</span> <span class="num">150</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t"> <span class="nam">text_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t"> <span class="key">elif</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_hovered</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">207&#x202F;&#x219B;&#x202F;209</span><span class="annotate long">line 207 didn't jump to line 209 because the condition on line 207 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"> <span class="com"># Hovered button</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t"> <span class="nam">bg_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">100</span><span class="op">,</span> <span class="num">160</span><span class="op">,</span> <span class="num">220</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t"> <span class="nam">border_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">70</span><span class="op">,</span> <span class="num">130</span><span class="op">,</span> <span class="num">180</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t"> <span class="nam">text_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"> <span class="com"># Normal button</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t"> <span class="nam">bg_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">100</span><span class="op">,</span> <span class="num">150</span><span class="op">,</span> <span class="num">200</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t"> <span class="nam">border_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">70</span><span class="op">,</span> <span class="num">120</span><span class="op">,</span> <span class="num">170</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t"> <span class="nam">text_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t"> <span class="com"># Draw button background with rounded corners</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t"> <span class="com"># rounded_rectangle expects [x0, y0, x1, y1] format</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t"> <span class="nam">button_rect</span> <span class="op">=</span> <span class="op">[</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t"> <span class="nam">int</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"> <span class="nam">int</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">1</span><span class="op">]</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t"> <span class="nam">int</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t"> <span class="nam">int</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t"> <span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">rounded_rectangle</span><span class="op">(</span><span class="nam">button_rect</span><span class="op">,</span> <span class="nam">fill</span><span class="op">=</span><span class="nam">bg_color</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t"> <span class="nam">outline</span><span class="op">=</span><span class="nam">border_color</span><span class="op">,</span> <span class="nam">width</span><span class="op">=</span><span class="num">1</span><span class="op">,</span> <span class="nam">radius</span><span class="op">=</span><span class="num">4</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t"> <span class="com"># Update text color and render text centered within padding</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">with_colour</span><span class="op">(</span><span class="nam">text_color</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t"> <span class="nam">text_x</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_padding</span><span class="op">[</span><span class="num">3</span><span class="op">]</span> <span class="com"># left padding</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t"> <span class="com"># Center text vertically within button</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t"> <span class="com"># Get font metrics to properly center the baseline</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t"> <span class="nam">ascent</span><span class="op">,</span> <span class="nam">descent</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">font</span><span class="op">.</span><span class="nam">getmetrics</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t"> <span class="com"># Total button height minus top and bottom padding gives us text area height</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t"> <span class="nam">text_area_height</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_padded_height</span> <span class="op">-</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_padding</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">-</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_padding</span><span class="op">[</span><span class="num">2</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t"> <span class="com"># Center the text visual height (ascent + descent) within the text area</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t"> <span class="com"># The y position is where the baseline sits</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t"> <span class="com"># Visual center = area_height/2, baseline should be at center + descent/2</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t"> <span class="nam">vertical_center</span> <span class="op">=</span> <span class="nam">text_area_height</span> <span class="op">/</span> <span class="num">2</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t"> <span class="nam">text_y</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_padding</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">+</span> <span class="nam">vertical_center</span> <span class="op">+</span> <span class="op">(</span><span class="nam">descent</span> <span class="op">/</span> <span class="num">2</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t"> <span class="com"># Temporarily set origin for text rendering</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t"> <span class="nam">original_origin</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">.</span><span class="nam">copy</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="op">[</span><span class="nam">text_x</span><span class="op">,</span> <span class="nam">text_y</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t"> <span class="com"># Call parent render method for the text</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">render</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t"> <span class="com"># Restore original origin</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span> <span class="op">=</span> <span class="nam">original_origin</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t"> <span class="key">def</span> <span class="nam">in_object</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">point</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t"><span class="str"> Check if a point is within this button.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t"><span class="str"> point: The coordinates to check</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t"><span class="str"> True if the point is within the button bounds (including padding)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t"> <span class="nam">point_array</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="nam">point</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t"> <span class="nam">relative_point</span> <span class="op">=</span> <span class="nam">point_array</span> <span class="op">-</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t"> <span class="com"># Check if the point is within the padded button boundaries</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t"> <span class="key">return</span> <span class="op">(</span><span class="num">0</span> <span class="op">&lt;=</span> <span class="nam">relative_point</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">&lt;</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_padded_width</span> <span class="key">and</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t"> <span class="num">0</span> <span class="op">&lt;=</span> <span class="nam">relative_point</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">&lt;</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_padded_height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t"><span class="key">class</span> <span class="nam">FormFieldText</span><span class="op">(</span><span class="nam">Text</span><span class="op">,</span> <span class="nam">Interactable</span><span class="op">,</span> <span class="nam">Queriable</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t"><span class="str"> A Text subclass that can handle FormField interactions.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t"><span class="str"> Renders form field labels and input areas.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t279" href="#t279">279</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t280" href="#t280">280</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">field</span><span class="op">:</span> <span class="nam">FormField</span><span class="op">,</span> <span class="nam">font</span><span class="op">:</span> <span class="nam">Font</span><span class="op">,</span> <span class="nam">draw</span><span class="op">:</span> <span class="nam">ImageDraw</span><span class="op">.</span><span class="nam">Draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t281" href="#t281">281</a></span><span class="t"> <span class="nam">field_height</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">24</span><span class="op">,</span> <span class="nam">source</span><span class="op">=</span><span class="key">None</span><span class="op">,</span> <span class="nam">line</span><span class="op">=</span><span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t282" href="#t282">282</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t283" href="#t283">283</a></span><span class="t"><span class="str"> Initialize a form field text object.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t284" href="#t284">284</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t285" href="#t285">285</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t286" href="#t286">286</a></span><span class="t"><span class="str"> field: The abstract FormField object to handle interactions</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t287" href="#t287">287</a></span><span class="t"><span class="str"> font: The base font style for the label</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t288" href="#t288">288</a></span><span class="t"><span class="str"> draw: The drawing context</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t289" href="#t289">289</a></span><span class="t"><span class="str"> field_height: Height of the input field area</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t290" href="#t290">290</a></span><span class="t"><span class="str"> source: Optional source object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t291" href="#t291">291</a></span><span class="t"><span class="str"> line: Optional line container</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t292" href="#t292">292</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t293" href="#t293">293</a></span><span class="t"> <span class="com"># Initialize Text with the field label</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t294" href="#t294">294</a></span><span class="t"> <span class="nam">Text</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">field</span><span class="op">.</span><span class="nam">label</span><span class="op">,</span> <span class="nam">font</span><span class="op">,</span> <span class="nam">draw</span><span class="op">,</span> <span class="nam">source</span><span class="op">,</span> <span class="nam">line</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t295" href="#t295">295</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t296" href="#t296">296</a></span><span class="t"> <span class="com"># Initialize Interactable - form fields don't have direct callbacks</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t297" href="#t297">297</a></span><span class="t"> <span class="com"># but can notify of focus/value changes</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t298" href="#t298">298</a></span><span class="t"> <span class="nam">Interactable</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="key">None</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t299" href="#t299">299</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t300" href="#t300">300</a></span><span class="t"> <span class="com"># Store field properties</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t301" href="#t301">301</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_field</span> <span class="op">=</span> <span class="nam">field</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t302" href="#t302">302</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_field_height</span> <span class="op">=</span> <span class="nam">field_height</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t303" href="#t303">303</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_focused</span> <span class="op">=</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t304" href="#t304">304</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t305" href="#t305">305</a></span><span class="t"> <span class="com"># Calculate total height (label + gap + field)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t306" href="#t306">306</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_total_height</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">font_size</span> <span class="op">+</span> <span class="num">5</span> <span class="op">+</span> <span class="nam">field_height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t307" href="#t307">307</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t308" href="#t308">308</a></span><span class="t"> <span class="com"># Field width should be at least as wide as the label</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t309" href="#t309">309</a></span><span class="t"> <span class="com"># Use getattr to handle mock objects in tests</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t310" href="#t310">310</a></span><span class="t"> <span class="nam">text_width</span> <span class="op">=</span> <span class="nam">getattr</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t311" href="#t311">311</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span> <span class="str">'_width'</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span> <span class="key">if</span> <span class="key">not</span> <span class="nam">hasattr</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t312" href="#t312">312</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_width</span><span class="op">,</span> <span class="str">'__call__'</span><span class="op">)</span> <span class="key">else</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t313" href="#t313">313</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_field_width</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">text_width</span><span class="op">,</span> <span class="num">150</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t314" href="#t314">314</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t315" href="#t315">315</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t316" href="#t316">316</a></span><span class="t"> <span class="key">def</span> <span class="nam">field</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">FormField</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t317" href="#t317">317</a></span><span class="t"> <span class="str">"""Get the associated FormField object"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t318" href="#t318">318</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_field</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t319" href="#t319">319</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t320" href="#t320">320</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t321" href="#t321">321</a></span><span class="t"> <span class="key">def</span> <span class="nam">size</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">np</span><span class="op">.</span><span class="nam">ndarray</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t322" href="#t322">322</a></span><span class="t"> <span class="str">"""Get the total size including label and field"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t323" href="#t323">323</a></span><span class="t"> <span class="key">return</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="op">[</span><span class="nam">self</span><span class="op">.</span><span class="nam">_field_width</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_total_height</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t324" href="#t324">324</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t325" href="#t325">325</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_focused</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">focused</span><span class="op">:</span> <span class="nam">bool</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t326" href="#t326">326</a></span><span class="t"> <span class="str">"""Set the focus state"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t327" href="#t327">327</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_focused</span> <span class="op">=</span> <span class="nam">focused</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t328" href="#t328">328</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t329" href="#t329">329</a></span><span class="t"> <span class="key">def</span> <span class="nam">render</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t330" href="#t330">330</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t331" href="#t331">331</a></span><span class="t"><span class="str"> Render the form field with label and input area.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t332" href="#t332">332</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t333" href="#t333">333</a></span><span class="t"> <span class="com"># Render the label</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t334" href="#t334">334</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">render</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t335" href="#t335">335</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t336" href="#t336">336</a></span><span class="t"> <span class="com"># Calculate field position (below label with 5px gap)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t337" href="#t337">337</a></span><span class="t"> <span class="nam">field_x</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">0</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t338" href="#t338">338</a></span><span class="t"> <span class="nam">field_y</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">font_size</span> <span class="op">+</span> <span class="num">5</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t339" href="#t339">339</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t340" href="#t340">340</a></span><span class="t"> <span class="com"># Draw field background and border</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t341" href="#t341">341</a></span><span class="t"> <span class="nam">bg_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t342" href="#t342">342</a></span><span class="t"> <span class="nam">border_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">100</span><span class="op">,</span> <span class="num">150</span><span class="op">,</span> <span class="num">200</span><span class="op">)</span> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_focused</span> <span class="key">else</span> <span class="op">(</span><span class="num">200</span><span class="op">,</span> <span class="num">200</span><span class="op">,</span> <span class="num">200</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t343" href="#t343">343</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t344" href="#t344">344</a></span><span class="t"> <span class="nam">field_rect</span> <span class="op">=</span> <span class="op">[</span><span class="op">(</span><span class="nam">field_x</span><span class="op">,</span> <span class="nam">field_y</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t345" href="#t345">345</a></span><span class="t"> <span class="op">(</span><span class="nam">field_x</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_field_width</span><span class="op">,</span> <span class="nam">field_y</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_field_height</span><span class="op">)</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t346" href="#t346">346</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">rectangle</span><span class="op">(</span><span class="nam">field_rect</span><span class="op">,</span> <span class="nam">fill</span><span class="op">=</span><span class="nam">bg_color</span><span class="op">,</span> <span class="nam">outline</span><span class="op">=</span><span class="nam">border_color</span><span class="op">,</span> <span class="nam">width</span><span class="op">=</span><span class="num">1</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t347" href="#t347">347</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t348" href="#t348">348</a></span><span class="t"> <span class="com"># Render field value if present</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t349" href="#t349">349</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_field</span><span class="op">.</span><span class="nam">value</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t350" href="#t350">350</a></span><span class="t"> <span class="nam">value_text</span> <span class="op">=</span> <span class="nam">str</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_field</span><span class="op">.</span><span class="nam">value</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t351" href="#t351">351</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t352" href="#t352">352</a></span><span class="t"> <span class="com"># For password fields, mask the text</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t353" href="#t353">353</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_field</span><span class="op">.</span><span class="nam">field_type</span> <span class="op">==</span> <span class="nam">FormFieldType</span><span class="op">.</span><span class="nam">PASSWORD</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t354" href="#t354">354</a></span><span class="t"> <span class="nam">value_text</span> <span class="op">=</span> <span class="str">"&#8226;"</span> <span class="op">*</span> <span class="nam">len</span><span class="op">(</span><span class="nam">value_text</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t355" href="#t355">355</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t356" href="#t356">356</a></span><span class="t"> <span class="com"># Create a temporary Text object for the value</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t357" href="#t357">357</a></span><span class="t"> <span class="nam">value_font</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">with_colour</span><span class="op">(</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t358" href="#t358">358</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t359" href="#t359">359</a></span><span class="t"> <span class="com"># Position value text within field (with some padding)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t360" href="#t360">360</a></span><span class="t"> <span class="com"># Get font metrics to properly center the baseline</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t361" href="#t361">361</a></span><span class="t"> <span class="nam">ascent</span><span class="op">,</span> <span class="nam">descent</span> <span class="op">=</span> <span class="nam">value_font</span><span class="op">.</span><span class="nam">font</span><span class="op">.</span><span class="nam">getmetrics</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t362" href="#t362">362</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t363" href="#t363">363</a></span><span class="t"> <span class="com"># Center the text vertically within the field</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t364" href="#t364">364</a></span><span class="t"> <span class="com"># The y coordinate is where the baseline sits (anchor="ls")</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t365" href="#t365">365</a></span><span class="t"> <span class="nam">vertical_center</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_field_height</span> <span class="op">/</span> <span class="num">2</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t366" href="#t366">366</a></span><span class="t"> <span class="nam">value_x</span> <span class="op">=</span> <span class="nam">field_x</span> <span class="op">+</span> <span class="num">5</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t367" href="#t367">367</a></span><span class="t"> <span class="nam">value_y</span> <span class="op">=</span> <span class="nam">field_y</span> <span class="op">+</span> <span class="nam">vertical_center</span> <span class="op">+</span> <span class="op">(</span><span class="nam">descent</span> <span class="op">/</span> <span class="num">2</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t368" href="#t368">368</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t369" href="#t369">369</a></span><span class="t"> <span class="com"># Draw the value text</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t370" href="#t370">370</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">text</span><span class="op">(</span><span class="op">(</span><span class="nam">value_x</span><span class="op">,</span> <span class="nam">value_y</span><span class="op">)</span><span class="op">,</span> <span class="nam">value_text</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t371" href="#t371">371</a></span><span class="t"> <span class="nam">font</span><span class="op">=</span><span class="nam">value_font</span><span class="op">.</span><span class="nam">font</span><span class="op">,</span> <span class="nam">fill</span><span class="op">=</span><span class="nam">value_font</span><span class="op">.</span><span class="nam">colour</span><span class="op">,</span> <span class="nam">anchor</span><span class="op">=</span><span class="str">"ls"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t372" href="#t372">372</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t373" href="#t373">373</a></span><span class="t"> <span class="key">def</span> <span class="nam">handle_click</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">point</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t374" href="#t374">374</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t375" href="#t375">375</a></span><span class="t"><span class="str"> Handle clicks on the form field.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t376" href="#t376">376</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t377" href="#t377">377</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t378" href="#t378">378</a></span><span class="t"><span class="str"> point: The click coordinates relative to this field</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t379" href="#t379">379</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t380" href="#t380">380</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t381" href="#t381">381</a></span><span class="t"><span class="str"> True if the field was clicked and focused</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t382" href="#t382">382</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t383" href="#t383">383</a></span><span class="t"> <span class="com"># Calculate field area</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t384" href="#t384">384</a></span><span class="t"> <span class="nam">field_y</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">font_size</span> <span class="op">+</span> <span class="num">5</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t385" href="#t385">385</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t386" href="#t386">386</a></span><span class="t"> <span class="com"># Check if click is within the input field area (not just the label)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t387" href="#t387">387</a></span><span class="t"> <span class="key">if</span> <span class="op">(</span><span class="num">0</span> <span class="op">&lt;=</span> <span class="nam">point</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">&lt;=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_field_width</span> <span class="key">and</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t388" href="#t388">388</a></span><span class="t"> <span class="nam">field_y</span> <span class="op">&lt;=</span> <span class="nam">point</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">&lt;=</span> <span class="nam">field_y</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_field_height</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t389" href="#t389">389</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">set_focused</span><span class="op">(</span><span class="key">True</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t390" href="#t390">390</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t391" href="#t391">391</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t392" href="#t392">392</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t393" href="#t393">393</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t394" href="#t394">394</a></span><span class="t"> <span class="key">def</span> <span class="nam">in_object</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">point</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t395" href="#t395">395</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t396" href="#t396">396</a></span><span class="t"><span class="str"> Check if a point is within this form field (including label and input area).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t397" href="#t397">397</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t398" href="#t398">398</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t399" href="#t399">399</a></span><span class="t"><span class="str"> point: The coordinates to check</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t400" href="#t400">400</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t401" href="#t401">401</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t402" href="#t402">402</a></span><span class="t"><span class="str"> True if the point is within the field bounds</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t403" href="#t403">403</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t404" href="#t404">404</a></span><span class="t"> <span class="nam">point_array</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="nam">point</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t405" href="#t405">405</a></span><span class="t"> <span class="nam">relative_point</span> <span class="op">=</span> <span class="nam">point_array</span> <span class="op">-</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t406" href="#t406">406</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t407" href="#t407">407</a></span><span class="t"> <span class="com"># Check if the point is within the total field area</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t408" href="#t408">408</a></span><span class="t"> <span class="key">return</span> <span class="op">(</span><span class="num">0</span> <span class="op">&lt;=</span> <span class="nam">relative_point</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">&lt;</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_field_width</span> <span class="key">and</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t409" href="#t409">409</a></span><span class="t"> <span class="num">0</span> <span class="op">&lt;=</span> <span class="nam">relative_point</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">&lt;</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_total_height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t410" href="#t410">410</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t411" href="#t411">411</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t412" href="#t412">412</a></span><span class="t"><span class="com"># Factory functions for creating functional text objects</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t413" href="#t413">413</a></span><span class="t"><span class="key">def</span> <span class="nam">create_link_text</span><span class="op">(</span><span class="nam">link</span><span class="op">:</span> <span class="nam">Link</span><span class="op">,</span> <span class="nam">text</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span> <span class="nam">font</span><span class="op">:</span> <span class="nam">Font</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t414" href="#t414">414</a></span><span class="t"> <span class="nam">draw</span><span class="op">:</span> <span class="nam">ImageDraw</span><span class="op">.</span><span class="nam">Draw</span><span class="op">)</span> <span class="op">-></span> <span class="nam">LinkText</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t415" href="#t415">415</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t416" href="#t416">416</a></span><span class="t"><span class="str"> Factory function to create a LinkText object.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t417" href="#t417">417</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t418" href="#t418">418</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t419" href="#t419">419</a></span><span class="t"><span class="str"> link: The Link object to associate with the text</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t420" href="#t420">420</a></span><span class="t"><span class="str"> text: The text content to display</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t421" href="#t421">421</a></span><span class="t"><span class="str"> font: The base font style</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t422" href="#t422">422</a></span><span class="t"><span class="str"> draw: The drawing context</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t423" href="#t423">423</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t424" href="#t424">424</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t425" href="#t425">425</a></span><span class="t"><span class="str"> A LinkText object ready for rendering and interaction</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t426" href="#t426">426</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t427" href="#t427">427</a></span><span class="t"> <span class="key">return</span> <span class="nam">LinkText</span><span class="op">(</span><span class="nam">link</span><span class="op">,</span> <span class="nam">text</span><span class="op">,</span> <span class="nam">font</span><span class="op">,</span> <span class="nam">draw</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t428" href="#t428">428</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t429" href="#t429">429</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t430" href="#t430">430</a></span><span class="t"><span class="key">def</span> <span class="nam">create_button_text</span><span class="op">(</span><span class="nam">button</span><span class="op">:</span> <span class="nam">Button</span><span class="op">,</span> <span class="nam">font</span><span class="op">:</span> <span class="nam">Font</span><span class="op">,</span> <span class="nam">draw</span><span class="op">:</span> <span class="nam">ImageDraw</span><span class="op">.</span><span class="nam">Draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t431" href="#t431">431</a></span><span class="t"> <span class="nam">padding</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="op">(</span><span class="num">4</span><span class="op">,</span> <span class="num">8</span><span class="op">,</span> <span class="num">4</span><span class="op">,</span> <span class="num">8</span><span class="op">)</span><span class="op">)</span> <span class="op">-></span> <span class="nam">ButtonText</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t432" href="#t432">432</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t433" href="#t433">433</a></span><span class="t"><span class="str"> Factory function to create a ButtonText object.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t434" href="#t434">434</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t435" href="#t435">435</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t436" href="#t436">436</a></span><span class="t"><span class="str"> button: The Button object to associate with the text</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t437" href="#t437">437</a></span><span class="t"><span class="str"> font: The base font style</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t438" href="#t438">438</a></span><span class="t"><span class="str"> draw: The drawing context</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t439" href="#t439">439</a></span><span class="t"><span class="str"> padding: Padding around the button text</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t440" href="#t440">440</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t441" href="#t441">441</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t442" href="#t442">442</a></span><span class="t"><span class="str"> A ButtonText object ready for rendering and interaction</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t443" href="#t443">443</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t444" href="#t444">444</a></span><span class="t"> <span class="key">return</span> <span class="nam">ButtonText</span><span class="op">(</span><span class="nam">button</span><span class="op">,</span> <span class="nam">font</span><span class="op">,</span> <span class="nam">draw</span><span class="op">,</span> <span class="nam">padding</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t445" href="#t445">445</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t446" href="#t446">446</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t447" href="#t447">447</a></span><span class="t"><span class="key">def</span> <span class="nam">create_form_field_text</span><span class="op">(</span><span class="nam">field</span><span class="op">:</span> <span class="nam">FormField</span><span class="op">,</span> <span class="nam">font</span><span class="op">:</span> <span class="nam">Font</span><span class="op">,</span> <span class="nam">draw</span><span class="op">:</span> <span class="nam">ImageDraw</span><span class="op">.</span><span class="nam">Draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t448" href="#t448">448</a></span><span class="t"> <span class="nam">field_height</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">24</span><span class="op">)</span> <span class="op">-></span> <span class="nam">FormFieldText</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t449" href="#t449">449</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t450" href="#t450">450</a></span><span class="t"><span class="str"> Factory function to create a FormFieldText object.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t451" href="#t451">451</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t452" href="#t452">452</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t453" href="#t453">453</a></span><span class="t"><span class="str"> field: The FormField object to associate with the text</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t454" href="#t454">454</a></span><span class="t"><span class="str"> font: The base font style for the label</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t455" href="#t455">455</a></span><span class="t"><span class="str"> draw: The drawing context</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t456" href="#t456">456</a></span><span class="t"><span class="str"> field_height: Height of the input field area</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t457" href="#t457">457</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t458" href="#t458">458</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t459" href="#t459">459</a></span><span class="t"><span class="str"> A FormFieldText object ready for rendering and interaction</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t460" href="#t460">460</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t461" href="#t461">461</a></span><span class="t"> <span class="key">return</span> <span class="nam">FormFieldText</span><span class="op">(</span><span class="nam">field</span><span class="op">,</span> <span class="nam">font</span><span class="op">,</span> <span class="nam">draw</span><span class="op">,</span> <span class="nam">field_height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_7d48e1f4c6486fa2_dynamic_page_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_7d48e1f4c6486fa2_image_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,379 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/concrete/image.py: 93%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/concrete/image.py</b>:
<span class="pc_cov">93%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">134 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">126<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">8<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">11<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">4<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_7d48e1f4c6486fa2_functional_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_7d48e1f4c6486fa2_interaction_handler_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="run"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="key">import</span> <span class="nam">os</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">Optional</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t"><span class="key">import</span> <span class="nam">numpy</span> <span class="key">as</span> <span class="nam">np</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="key">from</span> <span class="nam">PIL</span> <span class="key">import</span> <span class="nam">Image</span> <span class="key">as</span> <span class="nam">PILImage</span><span class="op">,</span> <span class="nam">ImageDraw</span><span class="op">,</span> <span class="nam">ImageFont</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">core</span><span class="op">.</span><span class="nam">base</span> <span class="key">import</span> <span class="nam">Renderable</span><span class="op">,</span> <span class="nam">Queriable</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">block</span> <span class="key">import</span> <span class="nam">Image</span> <span class="key">as</span> <span class="nam">AbstractImage</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span> <span class="key">import</span> <span class="nam">Alignment</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="key">class</span> <span class="nam">RenderableImage</span><span class="op">(</span><span class="nam">Renderable</span><span class="op">,</span> <span class="nam">Queriable</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="str"> A concrete implementation for rendering Image objects.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">image</span><span class="op">:</span> <span class="nam">AbstractImage</span><span class="op">,</span> <span class="nam">canvas</span><span class="op">:</span> <span class="nam">PILImage</span><span class="op">.</span><span class="nam">Image</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"> <span class="nam">max_width</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span> <span class="nam">max_height</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"> <span class="nam">origin</span><span class="op">=</span><span class="key">None</span><span class="op">,</span> <span class="nam">size</span><span class="op">=</span><span class="key">None</span><span class="op">,</span> <span class="nam">callback</span><span class="op">=</span><span class="key">None</span><span class="op">,</span> <span class="nam">sheet</span><span class="op">=</span><span class="key">None</span><span class="op">,</span> <span class="nam">mode</span><span class="op">=</span><span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"> <span class="nam">halign</span><span class="op">=</span><span class="nam">Alignment</span><span class="op">.</span><span class="nam">CENTER</span><span class="op">,</span> <span class="nam">valign</span><span class="op">=</span><span class="nam">Alignment</span><span class="op">.</span><span class="nam">CENTER</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"><span class="str"> Initialize a renderable image.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"><span class="str"> image: The abstract Image object to render</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"><span class="str"> draw: The PIL ImageDraw object to draw on</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"><span class="str"> max_width: Maximum width constraint for the image</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"><span class="str"> max_height: Maximum height constraint for the image</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"><span class="str"> origin: Optional origin coordinates</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t"><span class="str"> size: Optional size override</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"><span class="str"> callback: Optional callback function</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"><span class="str"> sheet: Optional sheet for rendering</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"><span class="str"> mode: Optional image mode</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"><span class="str"> halign: Horizontal alignment</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"><span class="str"> valign: Vertical alignment</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_abstract_image</span> <span class="op">=</span> <span class="nam">image</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span> <span class="op">=</span> <span class="nam">canvas</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_pil_image</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_error_message</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_halign</span> <span class="op">=</span> <span class="nam">halign</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_valign</span> <span class="op">=</span> <span class="nam">valign</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t"> <span class="com"># Set origin as numpy array</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="nam">origin</span><span class="op">)</span> <span class="key">if</span> <span class="nam">origin</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span> <span class="key">else</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="op">[</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"> <span class="com"># Try to load the image</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_load_image</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t"> <span class="com"># Calculate the size if not provided</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"> <span class="key">if</span> <span class="nam">size</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t"> <span class="nam">size</span> <span class="op">=</span> <span class="nam">image</span><span class="op">.</span><span class="nam">calculate_scaled_dimensions</span><span class="op">(</span><span class="nam">max_width</span><span class="op">,</span> <span class="nam">max_height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t"> <span class="com"># Ensure we have valid dimensions, fallback to defaults if None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"> <span class="key">if</span> <span class="nam">size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="key">is</span> <span class="key">None</span> <span class="key">or</span> <span class="nam">size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t"> <span class="nam">size</span> <span class="op">=</span> <span class="op">(</span><span class="num">100</span><span class="op">,</span> <span class="num">100</span><span class="op">)</span> <span class="com"># Default size when image dimensions are unavailable</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t"> <span class="com"># Ensure dimensions are positive (can be negative if calculated from insufficient space)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t"> <span class="nam">size</span> <span class="op">=</span> <span class="op">(</span><span class="nam">max</span><span class="op">(</span><span class="num">1</span><span class="op">,</span> <span class="nam">size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">)</span><span class="op">,</span> <span class="nam">max</span><span class="op">(</span><span class="num">1</span><span class="op">,</span> <span class="nam">size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"> <span class="com"># Set size as numpy array</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="nam">size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t"> <span class="key">def</span> <span class="nam">origin</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">np</span><span class="op">.</span><span class="nam">ndarray</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"> <span class="str">"""Get the origin of the image"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"> <span class="key">def</span> <span class="nam">size</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">np</span><span class="op">.</span><span class="nam">ndarray</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"> <span class="str">"""Get the size of the image"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"> <span class="key">def</span> <span class="nam">width</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t"> <span class="str">"""Get the width of the image"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_origin</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">origin</span><span class="op">:</span> <span class="nam">np</span><span class="op">.</span><span class="nam">ndarray</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"> <span class="str">"""Set the origin of this image element"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span> <span class="op">=</span> <span class="nam">origin</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t"> <span class="key">def</span> <span class="nam">_load_image</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t"> <span class="str">"""Load the image from the source path"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"> <span class="com"># Check if the image has already been loaded into memory</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span>&nbsp;</span><span class="r"><span class="annotate short">85&#x202F;&#x219B;&#x202F;88</span><span class="annotate long">line 85 didn't jump to line 88 because the condition on line 85 was never true</span></span></p>
<p class="par par2 ru2 show_par"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_abstract_image</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="par par2 ru2 show_par"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t"> <span class="str">'_loaded_image'</span><span class="op">)</span> <span class="key">and</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_abstract_image</span><span class="op">.</span><span class="nam">_loaded_image</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_pil_image</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_abstract_image</span><span class="op">.</span><span class="nam">_loaded_image</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"> <span class="key">return</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t"> <span class="nam">source</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_abstract_image</span><span class="op">.</span><span class="nam">source</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t"> <span class="com"># Handle different types of sources</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t"> <span class="key">if</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">isfile</span><span class="op">(</span><span class="nam">source</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t"> <span class="com"># Local file</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_pil_image</span> <span class="op">=</span> <span class="nam">PILImage</span><span class="op">.</span><span class="nam">open</span><span class="op">(</span><span class="nam">source</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_abstract_image</span><span class="op">.</span><span class="nam">_loaded_image</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_pil_image</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t"> <span class="key">elif</span> <span class="nam">source</span><span class="op">.</span><span class="nam">startswith</span><span class="op">(</span><span class="op">(</span><span class="str">'http://'</span><span class="op">,</span> <span class="str">'https://'</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"> <span class="com"># URL - requires requests library</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"> <span class="key">import</span> <span class="nam">requests</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"> <span class="key">from</span> <span class="nam">io</span> <span class="key">import</span> <span class="nam">BytesIO</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t"> <span class="nam">response</span> <span class="op">=</span> <span class="nam">requests</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="nam">source</span><span class="op">,</span> <span class="nam">stream</span><span class="op">=</span><span class="key">True</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t"> <span class="key">if</span> <span class="nam">response</span><span class="op">.</span><span class="nam">status_code</span> <span class="op">==</span> <span class="num">200</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_pil_image</span> <span class="op">=</span> <span class="nam">PILImage</span><span class="op">.</span><span class="nam">open</span><span class="op">(</span><span class="nam">BytesIO</span><span class="op">(</span><span class="nam">response</span><span class="op">.</span><span class="nam">content</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_abstract_image</span><span class="op">.</span><span class="nam">_loaded_image</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_pil_image</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_error_message</span> <span class="op">=</span> <span class="fst">f"</span><span class="fst">Failed to load image: HTTP status </span><span class="op">{</span><span class="nam">response</span><span class="op">.</span><span class="nam">status_code</span><span class="op">}</span><span class="fst">"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"> <span class="key">except</span> <span class="nam">ImportError</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_error_message</span> <span class="op">=</span> <span class="str">"Requests library not available for URL loading"</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_error_message</span> <span class="op">=</span> <span class="fst">f"</span><span class="fst">Unable to load image from source: </span><span class="op">{</span><span class="nam">source</span><span class="op">}</span><span class="fst">"</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t"> <span class="key">except</span> <span class="nam">Exception</span> <span class="key">as</span> <span class="nam">e</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_error_message</span> <span class="op">=</span> <span class="fst">f"</span><span class="fst">Error loading image: </span><span class="op">{</span><span class="nam">str</span><span class="op">(</span><span class="nam">e</span><span class="op">)</span><span class="op">}</span><span class="fst">"</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_abstract_image</span><span class="op">.</span><span class="nam">_error</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_error_message</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"> <span class="key">def</span> <span class="nam">render</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t"><span class="str"> Render the image directly into the canvas using the provided draw object.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_pil_image</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t"> <span class="com"># Resize the image to fit the box while maintaining aspect ratio</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t"> <span class="nam">resized_image</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_resize_image</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t"> <span class="com"># Calculate position based on alignment</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t"> <span class="nam">img_width</span><span class="op">,</span> <span class="nam">img_height</span> <span class="op">=</span> <span class="nam">resized_image</span><span class="op">.</span><span class="nam">size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t"> <span class="nam">box_width</span><span class="op">,</span> <span class="nam">box_height</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t"> <span class="com"># Horizontal alignment</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_halign</span> <span class="op">==</span> <span class="nam">Alignment</span><span class="op">.</span><span class="nam">LEFT</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t"> <span class="nam">x_offset</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t"> <span class="key">elif</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_halign</span> <span class="op">==</span> <span class="nam">Alignment</span><span class="op">.</span><span class="nam">RIGHT</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t"> <span class="nam">x_offset</span> <span class="op">=</span> <span class="nam">box_width</span> <span class="op">-</span> <span class="nam">img_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"> <span class="key">else</span><span class="op">:</span> <span class="com"># CENTER is default</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t"> <span class="nam">x_offset</span> <span class="op">=</span> <span class="op">(</span><span class="nam">box_width</span> <span class="op">-</span> <span class="nam">img_width</span><span class="op">)</span> <span class="op">//</span> <span class="num">2</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t"> <span class="com"># Vertical alignment</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_valign</span> <span class="op">==</span> <span class="nam">Alignment</span><span class="op">.</span><span class="nam">TOP</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t"> <span class="nam">y_offset</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t"> <span class="key">elif</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_valign</span> <span class="op">==</span> <span class="nam">Alignment</span><span class="op">.</span><span class="nam">BOTTOM</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t"> <span class="nam">y_offset</span> <span class="op">=</span> <span class="nam">box_height</span> <span class="op">-</span> <span class="nam">img_height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"> <span class="key">else</span><span class="op">:</span> <span class="com"># CENTER is default</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t"> <span class="nam">y_offset</span> <span class="op">=</span> <span class="op">(</span><span class="nam">box_height</span> <span class="op">-</span> <span class="nam">img_height</span><span class="op">)</span> <span class="op">//</span> <span class="num">2</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"> <span class="com"># Calculate final position on canvas</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"> <span class="nam">final_x</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">+</span> <span class="nam">x_offset</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t"> <span class="nam">final_y</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">+</span> <span class="nam">y_offset</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t"> <span class="com"># Get the underlying image from the draw object to paste onto</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span><span class="op">.</span><span class="nam">paste</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t"> <span class="nam">resized_image</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t"> <span class="op">(</span><span class="nam">final_x</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t"> <span class="nam">final_y</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t"> <span class="nam">final_x</span> <span class="op">+</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t"> <span class="nam">img_width</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t"> <span class="nam">final_y</span> <span class="op">+</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"> <span class="nam">img_height</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t"> <span class="com"># Draw error placeholder</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw_error_placeholder</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t"> <span class="key">def</span> <span class="nam">_resize_image</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">PILImage</span><span class="op">.</span><span class="nam">Image</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t"><span class="str"> Resize the image to fit within the box while maintaining aspect ratio.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"><span class="str"> A resized PIL Image</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_pil_image</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t"> <span class="key">return</span> <span class="nam">PILImage</span><span class="op">.</span><span class="nam">new</span><span class="op">(</span><span class="str">'RGBA'</span><span class="op">,</span> <span class="nam">tuple</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">)</span><span class="op">,</span> <span class="op">(</span><span class="num">200</span><span class="op">,</span> <span class="num">200</span><span class="op">,</span> <span class="num">200</span><span class="op">,</span> <span class="num">100</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t"> <span class="com"># Get the target dimensions</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t"> <span class="nam">target_width</span><span class="op">,</span> <span class="nam">target_height</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t"> <span class="com"># Ensure target dimensions are positive</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t"> <span class="nam">target_width</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="num">1</span><span class="op">,</span> <span class="nam">int</span><span class="op">(</span><span class="nam">target_width</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t"> <span class="nam">target_height</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="num">1</span><span class="op">,</span> <span class="nam">int</span><span class="op">(</span><span class="nam">target_height</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t"> <span class="com"># Get the original dimensions</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t"> <span class="nam">orig_width</span><span class="op">,</span> <span class="nam">orig_height</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_pil_image</span><span class="op">.</span><span class="nam">size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t"> <span class="com"># Calculate the scaling factor to maintain aspect ratio</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t"> <span class="nam">width_ratio</span> <span class="op">=</span> <span class="nam">target_width</span> <span class="op">/</span> <span class="nam">orig_width</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t"> <span class="nam">height_ratio</span> <span class="op">=</span> <span class="nam">target_height</span> <span class="op">/</span> <span class="nam">orig_height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t"> <span class="com"># Use the smaller ratio to ensure the image fits within the box</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t"> <span class="nam">ratio</span> <span class="op">=</span> <span class="nam">min</span><span class="op">(</span><span class="nam">width_ratio</span><span class="op">,</span> <span class="nam">height_ratio</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t"> <span class="com"># Calculate new dimensions</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t"> <span class="nam">new_width</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="num">1</span><span class="op">,</span> <span class="nam">int</span><span class="op">(</span><span class="nam">orig_width</span> <span class="op">*</span> <span class="nam">ratio</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t"> <span class="nam">new_height</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="num">1</span><span class="op">,</span> <span class="nam">int</span><span class="op">(</span><span class="nam">orig_height</span> <span class="op">*</span> <span class="nam">ratio</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t"> <span class="com"># Resize the image</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_pil_image</span><span class="op">.</span><span class="nam">mode</span> <span class="op">==</span> <span class="str">'RGBA'</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">197&#x202F;&#x219B;&#x202F;198</span><span class="annotate long">line 197 didn't jump to line 198 because the condition on line 197 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t"> <span class="nam">resized</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_pil_image</span><span class="op">.</span><span class="nam">resize</span><span class="op">(</span><span class="op">(</span><span class="nam">new_width</span><span class="op">,</span> <span class="nam">new_height</span><span class="op">)</span><span class="op">,</span> <span class="nam">PILImage</span><span class="op">.</span><span class="nam">LANCZOS</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t"> <span class="com"># Convert to RGBA if needed</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t"> <span class="nam">resized</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_pil_image</span><span class="op">.</span><span class="nam">convert</span><span class="op">(</span><span class="str">'RGBA'</span><span class="op">)</span><span class="op">.</span><span class="nam">resize</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t"> <span class="op">(</span><span class="nam">new_width</span><span class="op">,</span> <span class="nam">new_height</span><span class="op">)</span><span class="op">,</span> <span class="nam">PILImage</span><span class="op">.</span><span class="nam">LANCZOS</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t"> <span class="key">return</span> <span class="nam">resized</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t"> <span class="key">def</span> <span class="nam">_draw_error_placeholder</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"><span class="str"> Draw a placeholder for when the image can't be loaded.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t"> <span class="com"># Calculate the rectangle coordinates with origin offset</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t"> <span class="nam">x1</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t"> <span class="nam">y1</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">1</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"> <span class="nam">x2</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t"> <span class="nam">y2</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span> <span class="op">=</span> <span class="nam">ImageDraw</span><span class="op">.</span><span class="nam">Draw</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t"> <span class="com"># Draw a gray box with a border</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">rectangle</span><span class="op">(</span><span class="op">[</span><span class="op">(</span><span class="nam">x1</span><span class="op">,</span> <span class="nam">y1</span><span class="op">)</span><span class="op">,</span> <span class="op">(</span><span class="nam">x2</span><span class="op">,</span> <span class="nam">y2</span><span class="op">)</span><span class="op">]</span><span class="op">,</span> <span class="nam">fill</span><span class="op">=</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t"> <span class="num">240</span><span class="op">,</span> <span class="num">240</span><span class="op">,</span> <span class="num">240</span><span class="op">)</span><span class="op">,</span> <span class="nam">outline</span><span class="op">=</span><span class="op">(</span><span class="num">180</span><span class="op">,</span> <span class="num">180</span><span class="op">,</span> <span class="num">180</span><span class="op">)</span><span class="op">,</span> <span class="nam">width</span><span class="op">=</span><span class="num">2</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t"> <span class="com"># Draw an X across the box</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">line</span><span class="op">(</span><span class="op">[</span><span class="op">(</span><span class="nam">x1</span><span class="op">,</span> <span class="nam">y1</span><span class="op">)</span><span class="op">,</span> <span class="op">(</span><span class="nam">x2</span><span class="op">,</span> <span class="nam">y2</span><span class="op">)</span><span class="op">]</span><span class="op">,</span> <span class="nam">fill</span><span class="op">=</span><span class="op">(</span><span class="num">180</span><span class="op">,</span> <span class="num">180</span><span class="op">,</span> <span class="num">180</span><span class="op">)</span><span class="op">,</span> <span class="nam">width</span><span class="op">=</span><span class="num">2</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">line</span><span class="op">(</span><span class="op">[</span><span class="op">(</span><span class="nam">x1</span><span class="op">,</span> <span class="nam">y2</span><span class="op">)</span><span class="op">,</span> <span class="op">(</span><span class="nam">x2</span><span class="op">,</span> <span class="nam">y1</span><span class="op">)</span><span class="op">]</span><span class="op">,</span> <span class="nam">fill</span><span class="op">=</span><span class="op">(</span><span class="num">180</span><span class="op">,</span> <span class="num">180</span><span class="op">,</span> <span class="num">180</span><span class="op">)</span><span class="op">,</span> <span class="nam">width</span><span class="op">=</span><span class="num">2</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t"> <span class="com"># Add error text if available</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_error_message</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">226&#x202F;&#x219B;&#x202F;exit</span><span class="annotate long">line 226 didn't return from function '_draw_error_placeholder' because the condition on line 226 was always true</span></span></p>
<p class="run"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t"> <span class="com"># Try to use a basic font</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t"> <span class="nam">font</span> <span class="op">=</span> <span class="nam">ImageFont</span><span class="op">.</span><span class="nam">load_default</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t"> <span class="com"># Draw the error message, wrapped to fit</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t"> <span class="nam">error_text</span> <span class="op">=</span> <span class="str">"Error: "</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_error_message</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t"> <span class="com"># Simple text wrapping - split by words and add lines</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t"> <span class="nam">words</span> <span class="op">=</span> <span class="nam">error_text</span><span class="op">.</span><span class="nam">split</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t"> <span class="nam">lines</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t"> <span class="nam">current_line</span> <span class="op">=</span> <span class="str">""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t"> <span class="key">for</span> <span class="nam">word</span> <span class="key">in</span> <span class="nam">words</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t"> <span class="nam">test_line</span> <span class="op">=</span> <span class="nam">current_line</span> <span class="op">+</span> <span class="str">" "</span> <span class="op">+</span> <span class="nam">word</span> <span class="key">if</span> <span class="nam">current_line</span> <span class="key">else</span> <span class="nam">word</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t"> <span class="nam">text_bbox</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">textbbox</span><span class="op">(</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">,</span> <span class="nam">test_line</span><span class="op">,</span> <span class="nam">font</span><span class="op">=</span><span class="nam">font</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t"> <span class="nam">text_width</span> <span class="op">=</span> <span class="nam">text_bbox</span><span class="op">[</span><span class="num">2</span><span class="op">]</span> <span class="op">-</span> <span class="nam">text_bbox</span><span class="op">[</span><span class="num">0</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t"> <span class="key">if</span> <span class="nam">text_width</span> <span class="op">&lt;=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">-</span> <span class="num">20</span><span class="op">:</span> <span class="com"># 10px padding on each side</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t"> <span class="nam">current_line</span> <span class="op">=</span> <span class="nam">test_line</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t"> <span class="nam">lines</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">current_line</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t"> <span class="nam">current_line</span> <span class="op">=</span> <span class="nam">word</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t"> <span class="key">if</span> <span class="nam">current_line</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">250&#x202F;&#x219B;&#x202F;254</span><span class="annotate long">line 250 didn't jump to line 254 because the condition on line 250 was always true</span></span></p>
<p class="run"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t"> <span class="nam">lines</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">current_line</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t"> <span class="com"># Draw each line</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t"> <span class="nam">y_pos</span> <span class="op">=</span> <span class="nam">y1</span> <span class="op">+</span> <span class="num">10</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t"> <span class="key">for</span> <span class="nam">line</span> <span class="key">in</span> <span class="nam">lines</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t"> <span class="nam">text_bbox</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">textbbox</span><span class="op">(</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">,</span> <span class="nam">line</span><span class="op">,</span> <span class="nam">font</span><span class="op">=</span><span class="nam">font</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t"> <span class="nam">text_width</span> <span class="op">=</span> <span class="nam">text_bbox</span><span class="op">[</span><span class="num">2</span><span class="op">]</span> <span class="op">-</span> <span class="nam">text_bbox</span><span class="op">[</span><span class="num">0</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t"> <span class="nam">text_height</span> <span class="op">=</span> <span class="nam">text_bbox</span><span class="op">[</span><span class="num">3</span><span class="op">]</span> <span class="op">-</span> <span class="nam">text_bbox</span><span class="op">[</span><span class="num">1</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t"> <span class="com"># Center the text horizontally</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t"> <span class="nam">x_pos</span> <span class="op">=</span> <span class="nam">x1</span> <span class="op">+</span> <span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">-</span> <span class="nam">text_width</span><span class="op">)</span> <span class="op">//</span> <span class="num">2</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t"> <span class="com"># Draw the text</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">text</span><span class="op">(</span><span class="op">(</span><span class="nam">x_pos</span><span class="op">,</span> <span class="nam">y_pos</span><span class="op">)</span><span class="op">,</span> <span class="nam">line</span><span class="op">,</span> <span class="nam">fill</span><span class="op">=</span><span class="op">(</span><span class="num">80</span><span class="op">,</span> <span class="num">80</span><span class="op">,</span> <span class="num">80</span><span class="op">)</span><span class="op">,</span> <span class="nam">font</span><span class="op">=</span><span class="nam">font</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t"> <span class="com"># Move to the next line</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t"> <span class="nam">y_pos</span> <span class="op">+=</span> <span class="nam">text_height</span> <span class="op">+</span> <span class="num">2</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t"> <span class="key">except</span> <span class="nam">Exception</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t"> <span class="com"># If text rendering fails, just draw a generic error indicator</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t"> <span class="key">pass</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t"> <span class="key">def</span> <span class="nam">in_object</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">point</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t"> <span class="str">"""Check if a point is within this image"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t"> <span class="nam">point_array</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="nam">point</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t"> <span class="nam">relative_point</span> <span class="op">=</span> <span class="nam">point_array</span> <span class="op">-</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t"> <span class="com"># Check if the point is within the image boundaries</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t279" href="#t279">279</a></span><span class="t"> <span class="key">return</span> <span class="op">(</span><span class="num">0</span> <span class="op">&lt;=</span> <span class="nam">relative_point</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">&lt;</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="key">and</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t280" href="#t280">280</a></span><span class="t"> <span class="num">0</span> <span class="op">&lt;=</span> <span class="nam">relative_point</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">&lt;</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_7d48e1f4c6486fa2_functional_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_7d48e1f4c6486fa2_interaction_handler_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,409 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/concrete/interaction_handler.py: 0%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/concrete/interaction_handler.py</b>:
<span class="pc_cov">0%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">99 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">0<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">99<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">14<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">0<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_7d48e1f4c6486fa2_image_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_7d48e1f4c6486fa2_page_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">Interaction handler for managing button/link press-release lifecycle with visual feedback.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">This module provides utilities for handling interactive element states and rendering</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">frames at different stages of interaction (pressed, released).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">Tuple</span><span class="op">,</span> <span class="nam">Callable</span><span class="op">,</span> <span class="nam">Any</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="key">from</span> <span class="nam">PIL</span> <span class="key">import</span> <span class="nam">Image</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="key">import</span> <span class="nam">time</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="key">import</span> <span class="nam">numpy</span> <span class="key">as</span> <span class="nam">np</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span><span class="op">.</span><span class="nam">functional</span> <span class="key">import</span> <span class="nam">LinkText</span><span class="op">,</span> <span class="nam">ButtonText</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span><span class="op">.</span><span class="nam">page</span> <span class="key">import</span> <span class="nam">Page</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"><span class="key">class</span> <span class="nam">InteractionHandler</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"><span class="str"> Manages the press-release lifecycle for interactive elements.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"><span class="str"> This class handles the timing and state management needed to show</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"><span class="str"> visual feedback when buttons or links are clicked. It can generate</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"><span class="str"> multiple rendered frames showing the pressed and released states.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"><span class="str"> Usage patterns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"><span class="str"> Pattern A - Simple one-shot with automatic frames:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t"><span class="str"> handler = InteractionHandler(page)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"><span class="str"> frames = handler.execute_with_feedback(button_element, point)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"><span class="str"> # Returns: [pressed_frame, released_frame]</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"><span class="str"> # Show frames in sequence with brief delay</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"><span class="str"> Pattern B - Manual state management for custom event loops:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"><span class="str"> handler = InteractionHandler(page)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"><span class="str"> handler.set_pressed_state(button_element, True)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"><span class="str"> pressed_frame = handler.render_current_state()</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"><span class="str"> # ... show frame, wait, execute action ...</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t"><span class="str"> handler.set_pressed_state(button_element, False)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"><span class="str"> released_frame = handler.render_current_state()</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">page</span><span class="op">:</span> <span class="nam">Page</span><span class="op">,</span> <span class="nam">press_duration_ms</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">150</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"><span class="str"> Initialize the interaction handler.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"><span class="str"> page: The Page object containing the interactive elements</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"><span class="str"> press_duration_ms: How long to show the pressed state (default: 150ms)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_page</span> <span class="op">=</span> <span class="nam">page</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_press_duration_ms</span> <span class="op">=</span> <span class="nam">press_duration_ms</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_pressed_state</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">element</span><span class="op">,</span> <span class="nam">pressed</span><span class="op">:</span> <span class="nam">bool</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"><span class="str"> Set the pressed state of an interactive element.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t"><span class="str"> element: A LinkText or ButtonText object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"><span class="str"> pressed: True to show pressed, False to show released</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">element</span><span class="op">,</span> <span class="op">(</span><span class="nam">LinkText</span><span class="op">,</span> <span class="nam">ButtonText</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t"> <span class="com"># Ensure element has page reference for dirty flag</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">element</span><span class="op">,</span> <span class="str">'_page'</span><span class="op">)</span> <span class="key">or</span> <span class="nam">element</span><span class="op">.</span><span class="nam">_page</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"> <span class="nam">element</span><span class="op">.</span><span class="nam">set_page</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_page</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"> <span class="nam">element</span><span class="op">.</span><span class="nam">set_pressed</span><span class="op">(</span><span class="nam">pressed</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t"> <span class="key">raise</span> <span class="nam">TypeError</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"> <span class="fst">f"</span><span class="fst">Element must be LinkText or ButtonText, got </span><span class="op">{</span><span class="nam">type</span><span class="op">(</span><span class="nam">element</span><span class="op">)</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_hovered_state</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">element</span><span class="op">,</span> <span class="nam">hovered</span><span class="op">:</span> <span class="nam">bool</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t"><span class="str"> Set the hovered state of an interactive element.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"><span class="str"> element: A LinkText or ButtonText object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t"><span class="str"> hovered: True to show hovered, False for normal</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">element</span><span class="op">,</span> <span class="op">(</span><span class="nam">LinkText</span><span class="op">,</span> <span class="nam">ButtonText</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t"> <span class="com"># Ensure element has page reference for dirty flag</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">element</span><span class="op">,</span> <span class="str">'_page'</span><span class="op">)</span> <span class="key">or</span> <span class="nam">element</span><span class="op">.</span><span class="nam">_page</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t"> <span class="nam">element</span><span class="op">.</span><span class="nam">set_page</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_page</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t"> <span class="nam">element</span><span class="op">.</span><span class="nam">set_hovered</span><span class="op">(</span><span class="nam">hovered</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"> <span class="key">raise</span> <span class="nam">TypeError</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t"> <span class="fst">f"</span><span class="fst">Element must be LinkText or ButtonText, got </span><span class="op">{</span><span class="nam">type</span><span class="op">(</span><span class="nam">element</span><span class="op">)</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t"> <span class="key">def</span> <span class="nam">render_current_state</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Image</span><span class="op">.</span><span class="nam">Image</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"><span class="str"> Render the page with current element states.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t"><span class="str"> PIL Image of the rendered page</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_page</span><span class="op">.</span><span class="nam">render</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t"> <span class="key">def</span> <span class="nam">execute_with_feedback</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t"> <span class="nam">element</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"> <span class="nam">point</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">np</span><span class="op">.</span><span class="nam">ndarray</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t"> <span class="nam">callback</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Callable</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">Image</span><span class="op">.</span><span class="nam">Image</span><span class="op">,</span> <span class="nam">Image</span><span class="op">.</span><span class="nam">Image</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"><span class="str"> Execute an interaction with visual feedback at each stage.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t"><span class="str"> This is the high-level "all-in-one" method that:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t"><span class="str"> 1. Sets pressed state and renders</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t"><span class="str"> 2. Waits for press_duration_ms</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t"><span class="str"> 3. Executes the element's callback (or provided callback)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t"><span class="str"> 4. Sets released state and renders</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t"><span class="str"> element: A LinkText or ButtonText object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"><span class="str"> point: Optional point where interaction occurred</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t"><span class="str"> callback: Optional custom callback (overrides element's callback)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"><span class="str"> Tuple of (pressed_frame, released_frame, callback_result)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t"> <span class="com"># Step 1: Render pressed state</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">set_pressed_state</span><span class="op">(</span><span class="nam">element</span><span class="op">,</span> <span class="key">True</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t"> <span class="nam">pressed_frame</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">render_current_state</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t"> <span class="com"># Step 2: Wait for visual feedback duration</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"> <span class="nam">time</span><span class="op">.</span><span class="nam">sleep</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_press_duration_ms</span> <span class="op">/</span> <span class="num">1000.0</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t"> <span class="com"># Step 3: Execute callback</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t"> <span class="nam">callback_result</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t"> <span class="key">if</span> <span class="nam">callback</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t"> <span class="nam">callback_result</span> <span class="op">=</span> <span class="nam">callback</span><span class="op">(</span><span class="nam">point</span><span class="op">)</span> <span class="key">if</span> <span class="nam">point</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span> <span class="key">else</span> <span class="nam">callback</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t"> <span class="key">elif</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">element</span><span class="op">,</span> <span class="str">'interact'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t"> <span class="nam">callback_result</span> <span class="op">=</span> <span class="nam">element</span><span class="op">.</span><span class="nam">interact</span><span class="op">(</span><span class="nam">point</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t"> <span class="com"># Step 4: Render released state</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">set_pressed_state</span><span class="op">(</span><span class="nam">element</span><span class="op">,</span> <span class="key">False</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t"> <span class="nam">released_frame</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">render_current_state</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"> <span class="key">return</span> <span class="nam">pressed_frame</span><span class="op">,</span> <span class="nam">released_frame</span><span class="op">,</span> <span class="nam">callback_result</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"> <span class="key">def</span> <span class="nam">execute_async_with_feedback</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t"> <span class="nam">element</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t"> <span class="nam">point</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">np</span><span class="op">.</span><span class="nam">ndarray</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">Image</span><span class="op">.</span><span class="nam">Image</span><span class="op">,</span> <span class="nam">Callable</span><span class="op">,</span> <span class="nam">Image</span><span class="op">.</span><span class="nam">Image</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t"><span class="str"> Execute an interaction with visual feedback, returning frames immediately</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"><span class="str"> without blocking.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t"><span class="str"> This method returns the frames and a callback to execute later, allowing</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"><span class="str"> the caller to control when the action actually happens.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t"><span class="str"> element: A LinkText or ButtonText object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t"><span class="str"> point: Optional point where interaction occurred</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t"><span class="str"> Tuple of (pressed_frame, execute_callback, released_frame)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t"><span class="str"> where execute_callback is a function that will execute the interaction</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t"> <span class="com"># Render pressed state</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">set_pressed_state</span><span class="op">(</span><span class="nam">element</span><span class="op">,</span> <span class="key">True</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t"> <span class="nam">pressed_frame</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">render_current_state</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t"> <span class="com"># Create callback that will execute the interaction and reset state</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t"> <span class="key">def</span> <span class="nam">execute_callback</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"> <span class="nam">result</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">element</span><span class="op">,</span> <span class="str">'interact'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t"> <span class="nam">result</span> <span class="op">=</span> <span class="nam">element</span><span class="op">.</span><span class="nam">interact</span><span class="op">(</span><span class="nam">point</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">set_pressed_state</span><span class="op">(</span><span class="nam">element</span><span class="op">,</span> <span class="key">False</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t"> <span class="key">return</span> <span class="nam">result</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t"> <span class="com"># Pre-render the released state (element state is still pressed)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"> <span class="com"># We'll return this frame but the caller controls when to show it</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">set_pressed_state</span><span class="op">(</span><span class="nam">element</span><span class="op">,</span> <span class="key">False</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t"> <span class="nam">released_frame</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">render_current_state</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t"> <span class="com"># Reset back to pressed for consistency</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t"> <span class="com"># (caller will call execute_callback which sets to False)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">set_pressed_state</span><span class="op">(</span><span class="nam">element</span><span class="op">,</span> <span class="key">True</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t"> <span class="key">return</span> <span class="nam">pressed_frame</span><span class="op">,</span> <span class="nam">execute_callback</span><span class="op">,</span> <span class="nam">released_frame</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t"><span class="key">class</span> <span class="nam">InteractionStateManager</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t"><span class="str"> Manages interaction states for multiple elements on a page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t"><span class="str"> Useful for applications that need to track hover/press states</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t"><span class="str"> across many interactive elements simultaneously.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">page</span><span class="op">:</span> <span class="nam">Page</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t"><span class="str"> Initialize the state manager.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t"><span class="str"> page: The Page object containing interactive elements</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_page</span> <span class="op">=</span> <span class="nam">page</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_hovered_element</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_pressed_element</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t"> <span class="key">def</span> <span class="nam">update_hover</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">point</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Image</span><span class="op">.</span><span class="nam">Image</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t"><span class="str"> Update hover state based on cursor position.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t"><span class="str"> Queries the page to find what's under the cursor and updates</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t"><span class="str"> hover states accordingly.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"><span class="str"> point: Cursor position (x, y)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t"><span class="str"> New rendered frame if hover state changed, None otherwise</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"> <span class="com"># Query what's at this point</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t"> <span class="nam">result</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_page</span><span class="op">.</span><span class="nam">query_point</span><span class="op">(</span><span class="nam">point</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">result</span> <span class="key">or</span> <span class="key">not</span> <span class="nam">result</span><span class="op">.</span><span class="nam">is_interactive</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t"> <span class="com"># Nothing interactive under cursor</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_hovered_element</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t"> <span class="com"># Clear previous hover</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_hovered_element</span><span class="op">,</span> <span class="op">(</span><span class="nam">LinkText</span><span class="op">,</span> <span class="nam">ButtonText</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_hovered_element</span><span class="op">.</span><span class="nam">set_hovered</span><span class="op">(</span><span class="key">False</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_hovered_element</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_page</span><span class="op">.</span><span class="nam">render</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t"> <span class="com"># Something interactive is under cursor</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t"> <span class="nam">element</span> <span class="op">=</span> <span class="nam">result</span><span class="op">.</span><span class="nam">object</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t"> <span class="key">if</span> <span class="nam">element</span> <span class="op">!=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_hovered_element</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t"> <span class="com"># Hover changed</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t"> <span class="com"># Clear old hover</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_hovered_element</span> <span class="key">and</span> <span class="nam">isinstance</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_hovered_element</span><span class="op">,</span> <span class="op">(</span><span class="nam">LinkText</span><span class="op">,</span> <span class="nam">ButtonText</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_hovered_element</span><span class="op">.</span><span class="nam">set_hovered</span><span class="op">(</span><span class="key">False</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t"> <span class="com"># Set new hover</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">element</span><span class="op">,</span> <span class="op">(</span><span class="nam">LinkText</span><span class="op">,</span> <span class="nam">ButtonText</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t"> <span class="nam">element</span><span class="op">.</span><span class="nam">set_hovered</span><span class="op">(</span><span class="key">True</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_hovered_element</span> <span class="op">=</span> <span class="nam">element</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_page</span><span class="op">.</span><span class="nam">render</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t"> <span class="key">def</span> <span class="nam">handle_mouse_down</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">point</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Image</span><span class="op">.</span><span class="nam">Image</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t"><span class="str"> Handle mouse button press at a point.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t"><span class="str"> point: Click position (x, y)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t"><span class="str"> New rendered frame showing pressed state, or None if nothing interactive</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t"> <span class="nam">result</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_page</span><span class="op">.</span><span class="nam">query_point</span><span class="op">(</span><span class="nam">point</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">result</span> <span class="key">or</span> <span class="key">not</span> <span class="nam">result</span><span class="op">.</span><span class="nam">is_interactive</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t"> <span class="nam">element</span> <span class="op">=</span> <span class="nam">result</span><span class="op">.</span><span class="nam">object</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">element</span><span class="op">,</span> <span class="op">(</span><span class="nam">LinkText</span><span class="op">,</span> <span class="nam">ButtonText</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t"> <span class="nam">element</span><span class="op">.</span><span class="nam">set_pressed</span><span class="op">(</span><span class="key">True</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_pressed_element</span> <span class="op">=</span> <span class="nam">element</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_page</span><span class="op">.</span><span class="nam">render</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t"> <span class="key">def</span> <span class="nam">handle_mouse_up</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t"> <span class="nam">point</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t"> <span class="nam">int</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">Optional</span><span class="op">[</span><span class="nam">Image</span><span class="op">.</span><span class="nam">Image</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t"> <span class="nam">Any</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t"><span class="str"> Handle mouse button release at a point.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t"><span class="str"> point: Release position (x, y)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t279" href="#t279">279</a></span><span class="t"><span class="str"> Tuple of (rendered_frame, callback_result)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t280" href="#t280">280</a></span><span class="t"><span class="str"> Frame shows released state, result is from executing the callback</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t281" href="#t281">281</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t282" href="#t282">282</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_pressed_element</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t283" href="#t283">283</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span><span class="op">,</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t284" href="#t284">284</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t285" href="#t285">285</a></span><span class="t"> <span class="com"># Execute the interaction</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t286" href="#t286">286</a></span><span class="t"> <span class="nam">callback_result</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t287" href="#t287">287</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_pressed_element</span><span class="op">,</span> <span class="str">'interact'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t288" href="#t288">288</a></span><span class="t"> <span class="nam">callback_result</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_pressed_element</span><span class="op">.</span><span class="nam">interact</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t289" href="#t289">289</a></span><span class="t"> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="nam">point</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t290" href="#t290">290</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t291" href="#t291">291</a></span><span class="t"> <span class="com"># Release the pressed state</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t292" href="#t292">292</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_pressed_element</span><span class="op">,</span> <span class="op">(</span><span class="nam">LinkText</span><span class="op">,</span> <span class="nam">ButtonText</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t293" href="#t293">293</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_pressed_element</span><span class="op">.</span><span class="nam">set_pressed</span><span class="op">(</span><span class="key">False</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t294" href="#t294">294</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t295" href="#t295">295</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_pressed_element</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t296" href="#t296">296</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t297" href="#t297">297</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_page</span><span class="op">.</span><span class="nam">render</span><span class="op">(</span><span class="op">)</span><span class="op">,</span> <span class="nam">callback_result</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t298" href="#t298">298</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t299" href="#t299">299</a></span><span class="t"> <span class="key">def</span> <span class="nam">reset</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t300" href="#t300">300</a></span><span class="t"> <span class="str">"""Reset all interaction states."""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t301" href="#t301">301</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_hovered_element</span> <span class="key">and</span> <span class="nam">isinstance</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t302" href="#t302">302</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_hovered_element</span><span class="op">,</span> <span class="op">(</span><span class="nam">LinkText</span><span class="op">,</span> <span class="nam">ButtonText</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t303" href="#t303">303</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_hovered_element</span><span class="op">.</span><span class="nam">set_hovered</span><span class="op">(</span><span class="key">False</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t304" href="#t304">304</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t305" href="#t305">305</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_pressed_element</span> <span class="key">and</span> <span class="nam">isinstance</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t306" href="#t306">306</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_pressed_element</span><span class="op">,</span> <span class="op">(</span><span class="nam">LinkText</span><span class="op">,</span> <span class="nam">ButtonText</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t307" href="#t307">307</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_pressed_element</span><span class="op">.</span><span class="nam">set_pressed</span><span class="op">(</span><span class="key">False</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t308" href="#t308">308</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t309" href="#t309">309</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_hovered_element</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t310" href="#t310">310</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_pressed_element</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_7d48e1f4c6486fa2_image_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_7d48e1f4c6486fa2_page_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,636 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/concrete/page.py: 66%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/concrete/page.py</b>:
<span class="pc_cov">66%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">204 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">150<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">54<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">31<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">8<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_7d48e1f4c6486fa2_interaction_handler_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_7d48e1f4c6486fa2_table_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="run"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">List</span><span class="op">,</span> <span class="nam">Tuple</span><span class="op">,</span> <span class="nam">Optional</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="key">import</span> <span class="nam">numpy</span> <span class="key">as</span> <span class="nam">np</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t"><span class="key">from</span> <span class="nam">PIL</span> <span class="key">import</span> <span class="nam">Image</span><span class="op">,</span> <span class="nam">ImageDraw</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">core</span><span class="op">.</span><span class="nam">base</span> <span class="key">import</span> <span class="nam">Renderable</span><span class="op">,</span> <span class="nam">Queriable</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">core</span><span class="op">.</span><span class="nam">query</span> <span class="key">import</span> <span class="nam">QueryResult</span><span class="op">,</span> <span class="nam">SelectionRange</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">core</span><span class="op">.</span><span class="nam">callback_registry</span> <span class="key">import</span> <span class="nam">CallbackRegistry</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">page_style</span> <span class="key">import</span> <span class="nam">PageStyle</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="key">class</span> <span class="nam">Page</span><span class="op">(</span><span class="nam">Renderable</span><span class="op">,</span> <span class="nam">Queriable</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"><span class="str"> A page represents a canvas that can hold and render child renderable objects.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t"><span class="str"> It handles layout, rendering, and provides query capabilities to find which child</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"><span class="str"> contains a given point.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">size</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">,</span> <span class="nam">style</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">PageStyle</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"><span class="str"> Initialize a new page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"><span class="str"> size: The total size of the page (width, height) including borders</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"><span class="str"> style: The PageStyle defining borders, spacing, and appearance</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span> <span class="op">=</span> <span class="nam">size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span> <span class="op">=</span> <span class="nam">style</span> <span class="key">if</span> <span class="nam">style</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span> <span class="key">else</span> <span class="nam">PageStyle</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_children</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">Renderable</span><span class="op">]</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Image</span><span class="op">.</span><span class="nam">Image</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">ImageDraw</span><span class="op">.</span><span class="nam">Draw</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"> <span class="com"># Initialize y_offset to start of content area</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"> <span class="com"># Position the first line so its baseline is close to the top boundary</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"> <span class="com"># For subsequent lines, baseline-to-baseline spacing is used</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_current_y_offset</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">border_width</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">padding_top</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_is_first_line</span> <span class="op">=</span> <span class="key">True</span> <span class="com"># Track if we're placing the first line</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"> <span class="com"># Callback registry for managing interactable elements</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_callbacks</span> <span class="op">=</span> <span class="nam">CallbackRegistry</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t"> <span class="com"># Dirty flag to track if page needs re-rendering due to state changes</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_dirty</span> <span class="op">=</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t"> <span class="key">def</span> <span class="nam">free_space</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t"> <span class="str">"""Get the remaining space on the page"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t"> <span class="key">return</span> <span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">-</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_current_y_offset</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t"> <span class="key">def</span> <span class="nam">can_fit_line</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"> <span class="nam">baseline_spacing</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"> <span class="nam">ascent</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">0</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t"> <span class="nam">descent</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">0</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t"><span class="str"> Check if a line with the given metrics can fit on the page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t"><span class="str"> baseline_spacing: Distance from current position to next baseline</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"><span class="str"> ascent: Font ascent (height above baseline), defaults to 0 for backward compat</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t"><span class="str"> descent: Font descent (height below baseline), defaults to 0 for backward compat</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"><span class="str"> True if the line fits within page boundaries</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"> <span class="com"># Calculate the maximum Y position allowed (bottom boundary)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t"> <span class="nam">max_y</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">-</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">border_width</span> <span class="op">-</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">padding_bottom</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"> <span class="com"># If ascent/descent not provided, use simple check (backward compatibility)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"> <span class="key">if</span> <span class="nam">ascent</span> <span class="op">==</span> <span class="num">0</span> <span class="key">and</span> <span class="nam">descent</span> <span class="op">==</span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t"> <span class="key">return</span> <span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_current_y_offset</span> <span class="op">+</span> <span class="nam">baseline_spacing</span><span class="op">)</span> <span class="op">&lt;=</span> <span class="nam">max_y</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"> <span class="com"># Calculate where the bottom of the text would be</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"> <span class="com"># Text bottom = current_y_offset + ascent + descent</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t"> <span class="nam">text_bottom</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_current_y_offset</span> <span class="op">+</span> <span class="nam">ascent</span> <span class="op">+</span> <span class="nam">descent</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t"> <span class="com"># Check if text bottom would exceed the boundary</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"> <span class="key">return</span> <span class="nam">text_bottom</span> <span class="op">&lt;=</span> <span class="nam">max_y</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t"> <span class="key">def</span> <span class="nam">size</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t"> <span class="str">"""Get the total page size including borders"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t"> <span class="key">def</span> <span class="nam">canvas_size</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t"> <span class="str">"""Get the canvas size (page size minus borders)"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t"> <span class="nam">border_reduction</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">total_border_width</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"> <span class="key">return</span> <span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">-</span> <span class="nam">border_reduction</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">-</span> <span class="nam">border_reduction</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t"> <span class="key">def</span> <span class="nam">content_size</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t"> <span class="str">"""Get the content area size (canvas minus padding)"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t"> <span class="nam">canvas_w</span><span class="op">,</span> <span class="nam">canvas_h</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">canvas_size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t"> <span class="key">return</span> <span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t"> <span class="nam">canvas_w</span> <span class="op">-</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">total_horizontal_padding</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t"> <span class="nam">canvas_h</span> <span class="op">-</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">total_vertical_padding</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"> <span class="key">def</span> <span class="nam">border_size</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t"> <span class="str">"""Get the border width"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">border_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t"> <span class="key">def</span> <span class="nam">available_width</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t"> <span class="str">"""Get the available width for content (content area width)"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">content_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t"> <span class="key">def</span> <span class="nam">style</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">PageStyle</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"> <span class="str">"""Get the page style"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t"> <span class="key">def</span> <span class="nam">callbacks</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">CallbackRegistry</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t"> <span class="str">"""Get the callback registry for managing interactable elements"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_callbacks</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"> <span class="key">def</span> <span class="nam">is_dirty</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t"> <span class="str">"""Check if the page needs re-rendering due to state changes"""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_dirty</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"> <span class="key">def</span> <span class="nam">mark_dirty</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t"> <span class="str">"""Mark the page as needing re-rendering"""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_dirty</span> <span class="op">=</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t"> <span class="key">def</span> <span class="nam">mark_clean</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t"> <span class="str">"""Mark the page as clean (up-to-date render)"""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_dirty</span> <span class="op">=</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t"> <span class="key">def</span> <span class="nam">draw</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">ImageDraw</span><span class="op">.</span><span class="nam">Draw</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t"> <span class="str">"""Get the ImageDraw object for drawing on this page's canvas"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t"> <span class="com"># Initialize canvas and draw context if not already done</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_create_canvas</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span> <span class="op">=</span> <span class="nam">ImageDraw</span><span class="op">.</span><span class="nam">Draw</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t"> <span class="key">def</span> <span class="nam">add_child</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">child</span><span class="op">:</span> <span class="nam">Renderable</span><span class="op">)</span> <span class="op">-></span> <span class="str">'Page'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t"><span class="str"> Add a child renderable object to this page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t"><span class="str"> child: The renderable object to add</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"><span class="str"> Self for method chaining</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_children</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">child</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_current_y_offset</span> <span class="op">=</span> <span class="nam">child</span><span class="op">.</span><span class="nam">origin</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">+</span> <span class="nam">child</span><span class="op">.</span><span class="nam">size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t"> <span class="com"># Invalidate the canvas when children change</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t"> <span class="key">def</span> <span class="nam">remove_child</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">child</span><span class="op">:</span> <span class="nam">Renderable</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t"><span class="str"> Remove a child from the page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t"><span class="str"> child: The child to remove</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t"><span class="str"> True if the child was found and removed, False otherwise</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_children</span><span class="op">.</span><span class="nam">remove</span><span class="op">(</span><span class="nam">child</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"> <span class="key">except</span> <span class="nam">ValueError</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t"> <span class="key">def</span> <span class="nam">clear_children</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="str">'Page'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t"><span class="str"> Remove all children from the page.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t"><span class="str"> Self for method chaining</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_children</span><span class="op">.</span><span class="nam">clear</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t"> <span class="com"># Clear callback registry when clearing children</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_callbacks</span><span class="op">.</span><span class="nam">clear</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t"> <span class="com"># Reset y_offset to start of content area (after border and padding)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_current_y_offset</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">border_width</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">padding_top</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t"> <span class="key">def</span> <span class="nam">children</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">Renderable</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t"> <span class="str">"""Get a copy of the children list"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_children</span><span class="op">.</span><span class="nam">copy</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t"> <span class="key">def</span> <span class="nam">_get_child_property</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">child</span><span class="op">:</span> <span class="nam">Renderable</span><span class="op">,</span> <span class="nam">private_attr</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t"> <span class="nam">public_attr</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span> <span class="nam">index</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t"> <span class="nam">default</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"><span class="str"> Generic helper to extract properties from child objects with multiple fallback strategies.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t"><span class="str"> child: The child object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t"><span class="str"> private_attr: Name of the private attribute (e.g., '_size')</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t"><span class="str"> public_attr: Name of the public property (e.g., 'size')</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t"><span class="str"> index: Optional index for array-like properties (0 for width, 1 for height)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t"><span class="str"> default: Default value if property cannot be determined</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t"><span class="str"> Property value or default</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t"> <span class="com"># Try private attribute first</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="nam">private_attr</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t"> <span class="nam">value</span> <span class="op">=</span> <span class="nam">getattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="nam">private_attr</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t"> <span class="key">if</span> <span class="nam">value</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">value</span><span class="op">,</span> <span class="op">(</span><span class="nam">list</span><span class="op">,</span> <span class="nam">tuple</span><span class="op">,</span> <span class="nam">np</span><span class="op">.</span><span class="nam">ndarray</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t"> <span class="key">if</span> <span class="nam">index</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span> <span class="key">and</span> <span class="nam">len</span><span class="op">(</span><span class="nam">value</span><span class="op">)</span> <span class="op">></span> <span class="nam">index</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t"> <span class="key">return</span> <span class="nam">int</span><span class="op">(</span><span class="nam">value</span><span class="op">[</span><span class="nam">index</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t"> <span class="key">elif</span> <span class="nam">index</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t"> <span class="key">return</span> <span class="nam">value</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t"> <span class="com"># Try public property</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="nam">public_attr</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t"> <span class="nam">value</span> <span class="op">=</span> <span class="nam">getattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="nam">public_attr</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"> <span class="key">if</span> <span class="nam">value</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">value</span><span class="op">,</span> <span class="op">(</span><span class="nam">list</span><span class="op">,</span> <span class="nam">tuple</span><span class="op">,</span> <span class="nam">np</span><span class="op">.</span><span class="nam">ndarray</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t"> <span class="key">if</span> <span class="nam">index</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span> <span class="key">and</span> <span class="nam">len</span><span class="op">(</span><span class="nam">value</span><span class="op">)</span> <span class="op">></span> <span class="nam">index</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t"> <span class="key">return</span> <span class="nam">int</span><span class="op">(</span><span class="nam">value</span><span class="op">[</span><span class="nam">index</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t"> <span class="key">elif</span> <span class="nam">index</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t"> <span class="key">return</span> <span class="nam">value</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t"> <span class="key">return</span> <span class="nam">int</span><span class="op">(</span><span class="nam">value</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t"> <span class="key">return</span> <span class="nam">default</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t"> <span class="key">def</span> <span class="nam">_get_child_height</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">child</span><span class="op">:</span> <span class="nam">Renderable</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t"><span class="str"> Get the height of a child object.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t"><span class="str"> child: The child to measure</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t"><span class="str"> Height in pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t"> <span class="com"># Try to get height from size property (index 1)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t"> <span class="nam">height</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_get_child_property</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'_size'</span><span class="op">,</span> <span class="str">'size'</span><span class="op">,</span> <span class="nam">index</span><span class="op">=</span><span class="num">1</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t"> <span class="key">if</span> <span class="nam">height</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t"> <span class="key">return</span> <span class="nam">height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t"> <span class="com"># Try direct height attribute</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t"> <span class="nam">height</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_get_child_property</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'_height'</span><span class="op">,</span> <span class="str">'height'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t"> <span class="key">if</span> <span class="nam">height</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t"> <span class="key">return</span> <span class="nam">height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t"> <span class="com"># Default fallback height</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t"> <span class="key">return</span> <span class="num">20</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t"> <span class="key">def</span> <span class="nam">render_children</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t"><span class="str"> Call render on all children in the list.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t"><span class="str"> Children draw directly onto the page's canvas via the shared ImageDraw object.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t"> <span class="key">for</span> <span class="nam">child</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_children</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t"> <span class="com"># Synchronize draw context for Line objects before rendering</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'_draw'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t"> <span class="nam">child</span><span class="op">.</span><span class="nam">_draw</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t"> <span class="com"># Synchronize canvas for Image objects before rendering</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'_canvas'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">266&#x202F;&#x219B;&#x202F;267</span><span class="annotate long">line 266 didn't jump to line 267 because the condition on line 266 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t"> <span class="nam">child</span><span class="op">.</span><span class="nam">_canvas</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'render'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">268&#x202F;&#x219B;&#x202F;261</span><span class="annotate long">line 268 didn't jump to line 261 because the condition on line 268 was always true</span></span></p>
<p class="run"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t"> <span class="nam">child</span><span class="op">.</span><span class="nam">render</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t"> <span class="key">def</span> <span class="nam">render</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Image</span><span class="op">.</span><span class="nam">Image</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t"><span class="str"> Render the page with all its children.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t"><span class="str"> PIL Image containing the rendered page</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t"> <span class="com"># Create the base canvas and draw object</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t279" href="#t279">279</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_create_canvas</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t280" href="#t280">280</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span> <span class="op">=</span> <span class="nam">ImageDraw</span><span class="op">.</span><span class="nam">Draw</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t281" href="#t281">281</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t282" href="#t282">282</a></span><span class="t"> <span class="com"># Render all children - they draw directly onto the canvas</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t283" href="#t283">283</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">render_children</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t284" href="#t284">284</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t285" href="#t285">285</a></span><span class="t"> <span class="com"># Mark as clean after rendering</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t286" href="#t286">286</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_dirty</span> <span class="op">=</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t287" href="#t287">287</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t288" href="#t288">288</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t289" href="#t289">289</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t290" href="#t290">290</a></span><span class="t"> <span class="key">def</span> <span class="nam">_create_canvas</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Image</span><span class="op">.</span><span class="nam">Image</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t291" href="#t291">291</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t292" href="#t292">292</a></span><span class="t"><span class="str"> Create the base canvas with background and borders.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t293" href="#t293">293</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t294" href="#t294">294</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t295" href="#t295">295</a></span><span class="t"><span class="str"> PIL Image with background and borders applied</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t296" href="#t296">296</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t297" href="#t297">297</a></span><span class="t"> <span class="com"># Create base image</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t298" href="#t298">298</a></span><span class="t"> <span class="nam">canvas</span> <span class="op">=</span> <span class="nam">Image</span><span class="op">.</span><span class="nam">new</span><span class="op">(</span><span class="str">'RGBA'</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">,</span> <span class="op">(</span><span class="op">*</span><span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">background_color</span><span class="op">,</span> <span class="num">255</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t299" href="#t299">299</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t300" href="#t300">300</a></span><span class="t"> <span class="com"># Draw borders if needed</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t301" href="#t301">301</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">border_width</span> <span class="op">></span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t302" href="#t302">302</a></span><span class="t"> <span class="nam">draw</span> <span class="op">=</span> <span class="nam">ImageDraw</span><span class="op">.</span><span class="nam">Draw</span><span class="op">(</span><span class="nam">canvas</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t303" href="#t303">303</a></span><span class="t"> <span class="nam">border_color</span> <span class="op">=</span> <span class="op">(</span><span class="op">*</span><span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">border_color</span><span class="op">,</span> <span class="num">255</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t304" href="#t304">304</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t305" href="#t305">305</a></span><span class="t"> <span class="com"># Draw border rectangle inside the content area</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t306" href="#t306">306</a></span><span class="t"> <span class="nam">border_offset</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">border_width</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t307" href="#t307">307</a></span><span class="t"> <span class="nam">draw</span><span class="op">.</span><span class="nam">rectangle</span><span class="op">(</span><span class="op">[</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t308" href="#t308">308</a></span><span class="t"> <span class="op">(</span><span class="nam">border_offset</span><span class="op">,</span> <span class="nam">border_offset</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t309" href="#t309">309</a></span><span class="t"> <span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">-</span> <span class="nam">border_offset</span> <span class="op">-</span> <span class="num">1</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">-</span> <span class="nam">border_offset</span> <span class="op">-</span> <span class="num">1</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t310" href="#t310">310</a></span><span class="t"> <span class="op">]</span><span class="op">,</span> <span class="nam">outline</span><span class="op">=</span><span class="nam">border_color</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t311" href="#t311">311</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t312" href="#t312">312</a></span><span class="t"> <span class="key">return</span> <span class="nam">canvas</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t313" href="#t313">313</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t314" href="#t314">314</a></span><span class="t"> <span class="key">def</span> <span class="nam">_get_child_position</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">child</span><span class="op">:</span> <span class="nam">Renderable</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t315" href="#t315">315</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t316" href="#t316">316</a></span><span class="t"><span class="str"> Get the position where a child should be rendered.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t317" href="#t317">317</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t318" href="#t318">318</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t319" href="#t319">319</a></span><span class="t"><span class="str"> child: The child object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t320" href="#t320">320</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t321" href="#t321">321</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t322" href="#t322">322</a></span><span class="t"><span class="str"> Tuple of (x, y) coordinates</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t323" href="#t323">323</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t324" href="#t324">324</a></span><span class="t"> <span class="com"># Try to get x coordinate</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t325" href="#t325">325</a></span><span class="t"> <span class="nam">x</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_get_child_property</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'_origin'</span><span class="op">,</span> <span class="str">'position'</span><span class="op">,</span> <span class="nam">index</span><span class="op">=</span><span class="num">0</span><span class="op">,</span> <span class="nam">default</span><span class="op">=</span><span class="num">0</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t326" href="#t326">326</a></span><span class="t"> <span class="com"># Try to get y coordinate</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t327" href="#t327">327</a></span><span class="t"> <span class="nam">y</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_get_child_property</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'_origin'</span><span class="op">,</span> <span class="str">'position'</span><span class="op">,</span> <span class="nam">index</span><span class="op">=</span><span class="num">1</span><span class="op">,</span> <span class="nam">default</span><span class="op">=</span><span class="num">0</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t328" href="#t328">328</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t329" href="#t329">329</a></span><span class="t"> <span class="key">return</span> <span class="op">(</span><span class="nam">x</span><span class="op">,</span> <span class="nam">y</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t330" href="#t330">330</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t331" href="#t331">331</a></span><span class="t"> <span class="key">def</span> <span class="nam">query_point</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">point</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">QueryResult</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t332" href="#t332">332</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t333" href="#t333">333</a></span><span class="t"><span class="str"> Query a point to find the deepest object at that location.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t334" href="#t334">334</a></span><span class="t"><span class="str"> Traverses children and uses Queriable.in_object() for hit-testing.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t335" href="#t335">335</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t336" href="#t336">336</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t337" href="#t337">337</a></span><span class="t"><span class="str"> point: The (x, y) coordinates to query</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t338" href="#t338">338</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t339" href="#t339">339</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t340" href="#t340">340</a></span><span class="t"><span class="str"> QueryResult with metadata about what was found, or None if nothing hit</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t341" href="#t341">341</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t342" href="#t342">342</a></span><span class="t"> <span class="nam">point_array</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="nam">point</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t343" href="#t343">343</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t344" href="#t344">344</a></span><span class="t"> <span class="com"># Check each child (in reverse order so topmost child is found first)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t345" href="#t345">345</a></span><span class="t"> <span class="key">for</span> <span class="nam">child</span> <span class="key">in</span> <span class="nam">reversed</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_children</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t346" href="#t346">346</a></span><span class="t"> <span class="com"># Use Queriable mixin's in_object() for hit-testing</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t347" href="#t347">347</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="nam">Queriable</span><span class="op">)</span> <span class="key">and</span> <span class="nam">child</span><span class="op">.</span><span class="nam">in_object</span><span class="op">(</span><span class="nam">point_array</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t348" href="#t348">348</a></span><span class="t"> <span class="com"># If child can also query (has children of its own), recurse</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t349" href="#t349">349</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'query_point'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t350" href="#t350">350</a></span><span class="t"> <span class="nam">result</span> <span class="op">=</span> <span class="nam">child</span><span class="op">.</span><span class="nam">query_point</span><span class="op">(</span><span class="nam">point</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t351" href="#t351">351</a></span><span class="t"> <span class="key">if</span> <span class="nam">result</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">351&#x202F;&#x219B;&#x202F;355</span><span class="annotate long">line 351 didn't jump to line 355 because the condition on line 351 was always true</span></span></p>
<p class="run"><span class="n"><a id="t352" href="#t352">352</a></span><span class="t"> <span class="nam">result</span><span class="op">.</span><span class="nam">parent_page</span> <span class="op">=</span> <span class="nam">self</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t353" href="#t353">353</a></span><span class="t"> <span class="key">return</span> <span class="nam">result</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t354" href="#t354">354</a></span><span class="t"> <span class="com"># If child's query returned None, continue to next child</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t355" href="#t355">355</a></span><span class="t"> <span class="key">continue</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t356" href="#t356">356</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t357" href="#t357">357</a></span><span class="t"> <span class="com"># Otherwise, package this child as the result</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t358" href="#t358">358</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_make_query_result</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="nam">point</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t359" href="#t359">359</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t360" href="#t360">360</a></span><span class="t"> <span class="com"># Nothing hit - return empty result</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t361" href="#t361">361</a></span><span class="t"> <span class="key">return</span> <span class="nam">QueryResult</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t362" href="#t362">362</a></span><span class="t"> <span class="nam">object</span><span class="op">=</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t363" href="#t363">363</a></span><span class="t"> <span class="nam">object_type</span><span class="op">=</span><span class="str">"empty"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t364" href="#t364">364</a></span><span class="t"> <span class="nam">bounds</span><span class="op">=</span><span class="op">(</span><span class="nam">int</span><span class="op">(</span><span class="nam">point</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">)</span><span class="op">,</span> <span class="nam">int</span><span class="op">(</span><span class="nam">point</span><span class="op">[</span><span class="num">1</span><span class="op">]</span><span class="op">)</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t365" href="#t365">365</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t366" href="#t366">366</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t367" href="#t367">367</a></span><span class="t"> <span class="key">def</span> <span class="nam">_point_in_child</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">point</span><span class="op">:</span> <span class="nam">np</span><span class="op">.</span><span class="nam">ndarray</span><span class="op">,</span> <span class="nam">child</span><span class="op">:</span> <span class="nam">Renderable</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t368" href="#t368">368</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t369" href="#t369">369</a></span><span class="t"><span class="str"> Check if a point is within a child's bounds.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t370" href="#t370">370</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t371" href="#t371">371</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t372" href="#t372">372</a></span><span class="t"><span class="str"> point: The point to check</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t373" href="#t373">373</a></span><span class="t"><span class="str"> child: The child to check against</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t374" href="#t374">374</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t375" href="#t375">375</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t376" href="#t376">376</a></span><span class="t"><span class="str"> True if the point is within the child's bounds</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t377" href="#t377">377</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t378" href="#t378">378</a></span><span class="t"> <span class="com"># If child implements Queriable interface, use it</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t379" href="#t379">379</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="nam">Queriable</span><span class="op">)</span> <span class="key">and</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'in_object'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t380" href="#t380">380</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t381" href="#t381">381</a></span><span class="t"> <span class="key">return</span> <span class="nam">child</span><span class="op">.</span><span class="nam">in_object</span><span class="op">(</span><span class="nam">point</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t382" href="#t382">382</a></span><span class="t"> <span class="key">except</span> <span class="nam">BaseException</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t383" href="#t383">383</a></span><span class="t"> <span class="key">pass</span> <span class="com"># Fall back to bounds checking</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t384" href="#t384">384</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t385" href="#t385">385</a></span><span class="t"> <span class="com"># Get child position and size for bounds checking</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t386" href="#t386">386</a></span><span class="t"> <span class="nam">child_pos</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_get_child_position</span><span class="op">(</span><span class="nam">child</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t387" href="#t387">387</a></span><span class="t"> <span class="nam">child_size</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_get_child_size</span><span class="op">(</span><span class="nam">child</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t388" href="#t388">388</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t389" href="#t389">389</a></span><span class="t"> <span class="key">if</span> <span class="nam">child_size</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t390" href="#t390">390</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t391" href="#t391">391</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t392" href="#t392">392</a></span><span class="t"> <span class="com"># Check if point is within child bounds</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t393" href="#t393">393</a></span><span class="t"> <span class="key">return</span> <span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t394" href="#t394">394</a></span><span class="t"> <span class="nam">child_pos</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">&lt;=</span> <span class="nam">point</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">&lt;</span> <span class="nam">child_pos</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">+</span> <span class="nam">child_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="key">and</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t395" href="#t395">395</a></span><span class="t"> <span class="nam">child_pos</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">&lt;=</span> <span class="nam">point</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">&lt;</span> <span class="nam">child_pos</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">+</span> <span class="nam">child_size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t396" href="#t396">396</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t397" href="#t397">397</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t398" href="#t398">398</a></span><span class="t"> <span class="key">def</span> <span class="nam">_get_child_size</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">child</span><span class="op">:</span> <span class="nam">Renderable</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t399" href="#t399">399</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t400" href="#t400">400</a></span><span class="t"><span class="str"> Get the size of a child object.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t401" href="#t401">401</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t402" href="#t402">402</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t403" href="#t403">403</a></span><span class="t"><span class="str"> child: The child to measure</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t404" href="#t404">404</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t405" href="#t405">405</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t406" href="#t406">406</a></span><span class="t"><span class="str"> Tuple of (width, height) or None if size cannot be determined</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t407" href="#t407">407</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t408" href="#t408">408</a></span><span class="t"> <span class="com"># Try to get width and height from size property</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t409" href="#t409">409</a></span><span class="t"> <span class="nam">width</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_get_child_property</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'_size'</span><span class="op">,</span> <span class="str">'size'</span><span class="op">,</span> <span class="nam">index</span><span class="op">=</span><span class="num">0</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t410" href="#t410">410</a></span><span class="t"> <span class="nam">height</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_get_child_property</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'_size'</span><span class="op">,</span> <span class="str">'size'</span><span class="op">,</span> <span class="nam">index</span><span class="op">=</span><span class="num">1</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t411" href="#t411">411</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t412" href="#t412">412</a></span><span class="t"> <span class="com"># If size property worked, return it</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t413" href="#t413">413</a></span><span class="t"> <span class="key">if</span> <span class="nam">width</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span> <span class="key">and</span> <span class="nam">height</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t414" href="#t414">414</a></span><span class="t"> <span class="key">return</span> <span class="op">(</span><span class="nam">width</span><span class="op">,</span> <span class="nam">height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t415" href="#t415">415</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t416" href="#t416">416</a></span><span class="t"> <span class="com"># Try direct width/height attributes</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t417" href="#t417">417</a></span><span class="t"> <span class="nam">width</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_get_child_property</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'_width'</span><span class="op">,</span> <span class="str">'width'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t418" href="#t418">418</a></span><span class="t"> <span class="nam">height</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_get_child_property</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'_height'</span><span class="op">,</span> <span class="str">'height'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t419" href="#t419">419</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t420" href="#t420">420</a></span><span class="t"> <span class="key">if</span> <span class="nam">width</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span> <span class="key">and</span> <span class="nam">height</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t421" href="#t421">421</a></span><span class="t"> <span class="key">return</span> <span class="op">(</span><span class="nam">width</span><span class="op">,</span> <span class="nam">height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t422" href="#t422">422</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t423" href="#t423">423</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t424" href="#t424">424</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t425" href="#t425">425</a></span><span class="t"> <span class="key">def</span> <span class="nam">_make_query_result</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">obj</span><span class="op">,</span> <span class="nam">point</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="nam">QueryResult</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t426" href="#t426">426</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t427" href="#t427">427</a></span><span class="t"><span class="str"> Package an object into a QueryResult with metadata.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t428" href="#t428">428</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t429" href="#t429">429</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t430" href="#t430">430</a></span><span class="t"><span class="str"> obj: The object to package</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t431" href="#t431">431</a></span><span class="t"><span class="str"> point: The query point</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t432" href="#t432">432</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t433" href="#t433">433</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t434" href="#t434">434</a></span><span class="t"><span class="str"> QueryResult with extracted metadata</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t435" href="#t435">435</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t436" href="#t436">436</a></span><span class="t"> <span class="key">from</span> <span class="op">.</span><span class="nam">text</span> <span class="key">import</span> <span class="nam">Text</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t437" href="#t437">437</a></span><span class="t"> <span class="key">from</span> <span class="op">.</span><span class="nam">functional</span> <span class="key">import</span> <span class="nam">LinkText</span><span class="op">,</span> <span class="nam">ButtonText</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t438" href="#t438">438</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t439" href="#t439">439</a></span><span class="t"> <span class="com"># Extract bounds</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t440" href="#t440">440</a></span><span class="t"> <span class="nam">origin</span> <span class="op">=</span> <span class="nam">getattr</span><span class="op">(</span><span class="nam">obj</span><span class="op">,</span> <span class="str">'_origin'</span><span class="op">,</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="op">[</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">]</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t441" href="#t441">441</a></span><span class="t"> <span class="nam">size</span> <span class="op">=</span> <span class="nam">getattr</span><span class="op">(</span><span class="nam">obj</span><span class="op">,</span> <span class="str">'size'</span><span class="op">,</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="op">[</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">]</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t442" href="#t442">442</a></span><span class="t"> <span class="nam">bounds</span> <span class="op">=</span> <span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t443" href="#t443">443</a></span><span class="t"> <span class="nam">int</span><span class="op">(</span><span class="nam">origin</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t444" href="#t444">444</a></span><span class="t"> <span class="nam">int</span><span class="op">(</span><span class="nam">origin</span><span class="op">[</span><span class="num">1</span><span class="op">]</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t445" href="#t445">445</a></span><span class="t"> <span class="nam">int</span><span class="op">(</span><span class="nam">size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">)</span> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">size</span><span class="op">,</span> <span class="str">'__getitem__'</span><span class="op">)</span> <span class="key">else</span> <span class="num">0</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t446" href="#t446">446</a></span><span class="t"> <span class="nam">int</span><span class="op">(</span><span class="nam">size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span><span class="op">)</span> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">size</span><span class="op">,</span> <span class="str">'__getitem__'</span><span class="op">)</span> <span class="key">else</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t447" href="#t447">447</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t448" href="#t448">448</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t449" href="#t449">449</a></span><span class="t"> <span class="com"># Determine type and extract metadata</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t450" href="#t450">450</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">obj</span><span class="op">,</span> <span class="nam">LinkText</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t451" href="#t451">451</a></span><span class="t"> <span class="key">return</span> <span class="nam">QueryResult</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t452" href="#t452">452</a></span><span class="t"> <span class="nam">object</span><span class="op">=</span><span class="nam">obj</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t453" href="#t453">453</a></span><span class="t"> <span class="nam">object_type</span><span class="op">=</span><span class="str">"link"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t454" href="#t454">454</a></span><span class="t"> <span class="nam">bounds</span><span class="op">=</span><span class="nam">bounds</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t455" href="#t455">455</a></span><span class="t"> <span class="nam">text</span><span class="op">=</span><span class="nam">obj</span><span class="op">.</span><span class="nam">_text</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t456" href="#t456">456</a></span><span class="t"> <span class="nam">is_interactive</span><span class="op">=</span><span class="key">True</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t457" href="#t457">457</a></span><span class="t"> <span class="nam">link_target</span><span class="op">=</span><span class="nam">obj</span><span class="op">.</span><span class="nam">_link</span><span class="op">.</span><span class="nam">location</span> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">obj</span><span class="op">,</span> <span class="str">'_link'</span><span class="op">)</span> <span class="key">else</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t458" href="#t458">458</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t459" href="#t459">459</a></span><span class="t"> <span class="key">elif</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">obj</span><span class="op">,</span> <span class="nam">ButtonText</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">459&#x202F;&#x219B;&#x202F;460</span><span class="annotate long">line 459 didn't jump to line 460 because the condition on line 459 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t460" href="#t460">460</a></span><span class="t"> <span class="key">return</span> <span class="nam">QueryResult</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t461" href="#t461">461</a></span><span class="t"> <span class="nam">object</span><span class="op">=</span><span class="nam">obj</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t462" href="#t462">462</a></span><span class="t"> <span class="nam">object_type</span><span class="op">=</span><span class="str">"button"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t463" href="#t463">463</a></span><span class="t"> <span class="nam">bounds</span><span class="op">=</span><span class="nam">bounds</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t464" href="#t464">464</a></span><span class="t"> <span class="nam">text</span><span class="op">=</span><span class="nam">obj</span><span class="op">.</span><span class="nam">_text</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t465" href="#t465">465</a></span><span class="t"> <span class="nam">is_interactive</span><span class="op">=</span><span class="key">True</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t466" href="#t466">466</a></span><span class="t"> <span class="nam">callback</span><span class="op">=</span><span class="nam">obj</span><span class="op">.</span><span class="nam">_callback</span> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">obj</span><span class="op">,</span> <span class="str">'_callback'</span><span class="op">)</span> <span class="key">else</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t467" href="#t467">467</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t468" href="#t468">468</a></span><span class="t"> <span class="key">elif</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">obj</span><span class="op">,</span> <span class="nam">Text</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t469" href="#t469">469</a></span><span class="t"> <span class="key">return</span> <span class="nam">QueryResult</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t470" href="#t470">470</a></span><span class="t"> <span class="nam">object</span><span class="op">=</span><span class="nam">obj</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t471" href="#t471">471</a></span><span class="t"> <span class="nam">object_type</span><span class="op">=</span><span class="str">"text"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t472" href="#t472">472</a></span><span class="t"> <span class="nam">bounds</span><span class="op">=</span><span class="nam">bounds</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t473" href="#t473">473</a></span><span class="t"> <span class="nam">text</span><span class="op">=</span><span class="nam">obj</span><span class="op">.</span><span class="nam">_text</span> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">obj</span><span class="op">,</span> <span class="str">'_text'</span><span class="op">)</span> <span class="key">else</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t474" href="#t474">474</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t475" href="#t475">475</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t476" href="#t476">476</a></span><span class="t"> <span class="key">return</span> <span class="nam">QueryResult</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t477" href="#t477">477</a></span><span class="t"> <span class="nam">object</span><span class="op">=</span><span class="nam">obj</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t478" href="#t478">478</a></span><span class="t"> <span class="nam">object_type</span><span class="op">=</span><span class="str">"unknown"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t479" href="#t479">479</a></span><span class="t"> <span class="nam">bounds</span><span class="op">=</span><span class="nam">bounds</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t480" href="#t480">480</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t481" href="#t481">481</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t482" href="#t482">482</a></span><span class="t"> <span class="key">def</span> <span class="nam">query_range</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">start</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t483" href="#t483">483</a></span><span class="t"> <span class="nam">end</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="nam">SelectionRange</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t484" href="#t484">484</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t485" href="#t485">485</a></span><span class="t"><span class="str"> Query all text objects between two points (for text selection).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t486" href="#t486">486</a></span><span class="t"><span class="str"> Uses Queriable.in_object() to determine which objects are in range.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t487" href="#t487">487</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t488" href="#t488">488</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t489" href="#t489">489</a></span><span class="t"><span class="str"> start: Starting (x, y) point</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t490" href="#t490">490</a></span><span class="t"><span class="str"> end: Ending (x, y) point</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t491" href="#t491">491</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t492" href="#t492">492</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t493" href="#t493">493</a></span><span class="t"><span class="str"> SelectionRange with all text objects between the points</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t494" href="#t494">494</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t495" href="#t495">495</a></span><span class="t"> <span class="nam">results</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t496" href="#t496">496</a></span><span class="t"> <span class="nam">in_selection</span> <span class="op">=</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t497" href="#t497">497</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t498" href="#t498">498</a></span><span class="t"> <span class="nam">start_result</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">query_point</span><span class="op">(</span><span class="nam">start</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t499" href="#t499">499</a></span><span class="t"> <span class="nam">end_result</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">query_point</span><span class="op">(</span><span class="nam">end</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t500" href="#t500">500</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t501" href="#t501">501</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">start_result</span> <span class="key">or</span> <span class="key">not</span> <span class="nam">end_result</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">501&#x202F;&#x219B;&#x202F;502</span><span class="annotate long">line 501 didn't jump to line 502 because the condition on line 501 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t502" href="#t502">502</a></span><span class="t"> <span class="key">return</span> <span class="nam">SelectionRange</span><span class="op">(</span><span class="nam">start</span><span class="op">,</span> <span class="nam">end</span><span class="op">,</span> <span class="op">[</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t503" href="#t503">503</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t504" href="#t504">504</a></span><span class="t"> <span class="com"># Walk through all children (Lines) and their text objects</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t505" href="#t505">505</a></span><span class="t"> <span class="key">from</span> <span class="op">.</span><span class="nam">text</span> <span class="key">import</span> <span class="nam">Line</span><span class="op">,</span> <span class="nam">Text</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t506" href="#t506">506</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t507" href="#t507">507</a></span><span class="t"> <span class="key">for</span> <span class="nam">child</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_children</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t508" href="#t508">508</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="nam">Line</span><span class="op">)</span> <span class="key">and</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">child</span><span class="op">,</span> <span class="str">'_text_objects'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">508&#x202F;&#x219B;&#x202F;507</span><span class="annotate long">line 508 didn't jump to line 507 because the condition on line 508 was always true</span></span></p>
<p class="par run show_par"><span class="n"><a id="t509" href="#t509">509</a></span><span class="t"> <span class="key">for</span> <span class="nam">text_obj</span> <span class="key">in</span> <span class="nam">child</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">509&#x202F;&#x219B;&#x202F;507</span><span class="annotate long">line 509 didn't jump to line 507 because the loop on line 509 didn't complete</span></span></p>
<p class="pln"><span class="n"><a id="t510" href="#t510">510</a></span><span class="t"> <span class="com"># Check if this text is the start or is between start and end</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t511" href="#t511">511</a></span><span class="t"> <span class="key">if</span> <span class="nam">text_obj</span> <span class="op">==</span> <span class="nam">start_result</span><span class="op">.</span><span class="nam">object</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t512" href="#t512">512</a></span><span class="t"> <span class="nam">in_selection</span> <span class="op">=</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t513" href="#t513">513</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t514" href="#t514">514</a></span><span class="t"> <span class="key">if</span> <span class="nam">in_selection</span> <span class="key">and</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">text_obj</span><span class="op">,</span> <span class="nam">Text</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">514&#x202F;&#x219B;&#x202F;518</span><span class="annotate long">line 514 didn't jump to line 518 because the condition on line 514 was always true</span></span></p>
<p class="run"><span class="n"><a id="t515" href="#t515">515</a></span><span class="t"> <span class="nam">result</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_make_query_result</span><span class="op">(</span><span class="nam">text_obj</span><span class="op">,</span> <span class="nam">start</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t516" href="#t516">516</a></span><span class="t"> <span class="nam">results</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">result</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t517" href="#t517">517</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t518" href="#t518">518</a></span><span class="t"> <span class="key">if</span> <span class="nam">text_obj</span> <span class="op">==</span> <span class="nam">end_result</span><span class="op">.</span><span class="nam">object</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t519" href="#t519">519</a></span><span class="t"> <span class="nam">in_selection</span> <span class="op">=</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t520" href="#t520">520</a></span><span class="t"> <span class="key">break</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t521" href="#t521">521</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t522" href="#t522">522</a></span><span class="t"> <span class="key">return</span> <span class="nam">SelectionRange</span><span class="op">(</span><span class="nam">start</span><span class="op">,</span> <span class="nam">end</span><span class="op">,</span> <span class="nam">results</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t523" href="#t523">523</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t524" href="#t524">524</a></span><span class="t"> <span class="key">def</span> <span class="nam">in_object</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">point</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t525" href="#t525">525</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t526" href="#t526">526</a></span><span class="t"><span class="str"> Check if a point is within this page's bounds.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t527" href="#t527">527</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t528" href="#t528">528</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t529" href="#t529">529</a></span><span class="t"><span class="str"> point: The (x, y) coordinates to check</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t530" href="#t530">530</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t531" href="#t531">531</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t532" href="#t532">532</a></span><span class="t"><span class="str"> True if the point is within the page bounds</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t533" href="#t533">533</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t534" href="#t534">534</a></span><span class="t"> <span class="key">return</span> <span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t535" href="#t535">535</a></span><span class="t"> <span class="num">0</span> <span class="op">&lt;=</span> <span class="nam">point</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">&lt;</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="key">and</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t536" href="#t536">536</a></span><span class="t"> <span class="num">0</span> <span class="op">&lt;=</span> <span class="nam">point</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">&lt;</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t537" href="#t537">537</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_7d48e1f4c6486fa2_interaction_handler_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_7d48e1f4c6486fa2_table_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,805 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/concrete/table.py: 70%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/concrete/table.py</b>:
<span class="pc_cov">70%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">303 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">227<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">76<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">19<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">20<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_7d48e1f4c6486fa2_page_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_7d48e1f4c6486fa2_text_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">Concrete table rendering implementation for pyWebLayout.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">This module provides the concrete rendering classes for tables, including:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">- TableRenderer: Main table rendering with borders and spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="str">- TableRowRenderer: Individual row rendering</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="str">- TableCellRenderer: Cell rendering with support for nested content (text, images, links)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="key">from</span> <span class="nam">__future__</span> <span class="key">import</span> <span class="nam">annotations</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">Tuple</span><span class="op">,</span> <span class="nam">List</span><span class="op">,</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">Dict</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="key">from</span> <span class="nam">PIL</span> <span class="key">import</span> <span class="nam">Image</span><span class="op">,</span> <span class="nam">ImageDraw</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"><span class="key">from</span> <span class="nam">dataclasses</span> <span class="key">import</span> <span class="nam">dataclass</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">core</span><span class="op">.</span><span class="nam">base</span> <span class="key">import</span> <span class="nam">Renderable</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span><span class="op">.</span><span class="nam">box</span> <span class="key">import</span> <span class="nam">Box</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">block</span> <span class="key">import</span> <span class="nam">Table</span><span class="op">,</span> <span class="nam">TableRow</span><span class="op">,</span> <span class="nam">TableCell</span><span class="op">,</span> <span class="nam">Paragraph</span><span class="op">,</span> <span class="nam">Heading</span><span class="op">,</span> <span class="nam">Image</span> <span class="key">as</span> <span class="nam">AbstractImage</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">interactive_image</span> <span class="key">import</span> <span class="nam">InteractiveImage</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"><span class="op">@</span><span class="nam">dataclass</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"><span class="key">class</span> <span class="nam">TableStyle</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"> <span class="str">"""Styling configuration for table rendering."""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"> <span class="com"># Border configuration</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"> <span class="nam">border_width</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"> <span class="nam">border_color</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"> <span class="com"># Cell padding</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"> <span class="nam">cell_padding</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="op">(</span><span class="num">5</span><span class="op">,</span> <span class="num">5</span><span class="op">,</span> <span class="num">5</span><span class="op">,</span> <span class="num">5</span><span class="op">)</span> <span class="com"># top, right, bottom, left</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"> <span class="com"># Header styling</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"> <span class="nam">header_bg_color</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="op">(</span><span class="num">240</span><span class="op">,</span> <span class="num">240</span><span class="op">,</span> <span class="num">240</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"> <span class="nam">header_text_bold</span><span class="op">:</span> <span class="nam">bool</span> <span class="op">=</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"> <span class="com"># Cell background</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"> <span class="nam">cell_bg_color</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="op">(</span><span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t"> <span class="nam">alternate_row_color</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="op">(</span><span class="num">250</span><span class="op">,</span> <span class="num">250</span><span class="op">,</span> <span class="num">250</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"> <span class="com"># Spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t"> <span class="nam">cell_spacing</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">0</span> <span class="com"># Space between cells (for separated borders model)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"><span class="key">class</span> <span class="nam">TableCellRenderer</span><span class="op">(</span><span class="nam">Box</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"><span class="str"> Renders a single table cell with its content.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"><span class="str"> Supports paragraphs, headings, images, and links within cells.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t"> <span class="nam">cell</span><span class="op">:</span> <span class="nam">TableCell</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t"> <span class="nam">origin</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"> <span class="nam">int</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t"> <span class="nam">size</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"> <span class="nam">int</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t"> <span class="nam">draw</span><span class="op">:</span> <span class="nam">ImageDraw</span><span class="op">.</span><span class="nam">Draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t"> <span class="nam">style</span><span class="op">:</span> <span class="nam">TableStyle</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t"> <span class="nam">is_header_section</span><span class="op">:</span> <span class="nam">bool</span> <span class="op">=</span> <span class="key">False</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"> <span class="nam">canvas</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Image</span><span class="op">.</span><span class="nam">Image</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"><span class="str"> Initialize a table cell renderer.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"><span class="str"> cell: The abstract TableCell to render</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"><span class="str"> origin: Top-left position of the cell</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t"><span class="str"> size: Width and height of the cell</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t"><span class="str"> draw: PIL ImageDraw object for rendering</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"><span class="str"> style: Table styling configuration</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"><span class="str"> is_header_section: Whether this cell is in the header section</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t"><span class="str"> canvas: Optional PIL Image for pasting images (required for image rendering)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="nam">origin</span><span class="op">,</span> <span class="nam">size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_cell</span> <span class="op">=</span> <span class="nam">cell</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span> <span class="op">=</span> <span class="nam">draw</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span> <span class="op">=</span> <span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_is_header_section</span> <span class="op">=</span> <span class="nam">is_header_section</span> <span class="key">or</span> <span class="nam">cell</span><span class="op">.</span><span class="nam">is_header</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span> <span class="op">=</span> <span class="nam">canvas</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_children</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">Renderable</span><span class="op">]</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t"> <span class="key">def</span> <span class="nam">render</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Image</span><span class="op">.</span><span class="nam">Image</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t"> <span class="str">"""Render the table cell."""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t"> <span class="com"># Determine background color</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_is_header_section</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"> <span class="nam">bg_color</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">header_bg_color</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t"> <span class="nam">bg_color</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">cell_bg_color</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t"> <span class="com"># Draw cell background</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"> <span class="nam">x</span><span class="op">,</span> <span class="nam">y</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t"> <span class="nam">w</span><span class="op">,</span> <span class="nam">h</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">rectangle</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t"> <span class="op">[</span><span class="nam">x</span><span class="op">,</span> <span class="nam">y</span><span class="op">,</span> <span class="nam">x</span> <span class="op">+</span> <span class="nam">w</span><span class="op">,</span> <span class="nam">y</span> <span class="op">+</span> <span class="nam">h</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t"> <span class="nam">fill</span><span class="op">=</span><span class="nam">bg_color</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t"> <span class="nam">outline</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">border_color</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t"> <span class="nam">width</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">border_width</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t"> <span class="com"># Calculate content area (inside padding)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"> <span class="nam">padding</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">cell_padding</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t"> <span class="nam">content_x</span> <span class="op">=</span> <span class="nam">x</span> <span class="op">+</span> <span class="nam">padding</span><span class="op">[</span><span class="num">3</span><span class="op">]</span> <span class="com"># left padding</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"> <span class="nam">content_y</span> <span class="op">=</span> <span class="nam">y</span> <span class="op">+</span> <span class="nam">padding</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="com"># top padding</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"> <span class="nam">content_width</span> <span class="op">=</span> <span class="nam">w</span> <span class="op">-</span> <span class="op">(</span><span class="nam">padding</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">+</span> <span class="nam">padding</span><span class="op">[</span><span class="num">3</span><span class="op">]</span><span class="op">)</span> <span class="com"># minus left and right padding</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t"> <span class="nam">content_height</span> <span class="op">=</span> <span class="nam">h</span> <span class="op">-</span> <span class="op">(</span><span class="nam">padding</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">+</span> <span class="nam">padding</span><span class="op">[</span><span class="num">2</span><span class="op">]</span><span class="op">)</span> <span class="com"># minus top and bottom padding</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t"> <span class="com"># Render cell content (text)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_render_cell_content</span><span class="op">(</span><span class="nam">content_x</span><span class="op">,</span> <span class="nam">content_y</span><span class="op">,</span> <span class="nam">content_width</span><span class="op">,</span> <span class="nam">content_height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span> <span class="com"># Cell rendering is done directly on the page</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"> <span class="key">def</span> <span class="nam">_render_cell_content</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">x</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">y</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">width</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">height</span><span class="op">:</span> <span class="nam">int</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t"> <span class="str">"""Render the content inside the cell (text and images) with line wrapping."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span><span class="op">.</span><span class="nam">text</span> <span class="key">import</span> <span class="nam">Line</span><span class="op">,</span> <span class="nam">Text</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">fonts</span> <span class="key">import</span> <span class="nam">Font</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span> <span class="key">import</span> <span class="nam">FontWeight</span><span class="op">,</span> <span class="nam">Alignment</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"> <span class="nam">current_y</span> <span class="op">=</span> <span class="nam">y</span> <span class="op">+</span> <span class="num">2</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t"> <span class="nam">available_height</span> <span class="op">=</span> <span class="nam">height</span> <span class="op">-</span> <span class="num">4</span> <span class="com"># Account for top/bottom padding</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"> <span class="com"># Create font for the cell</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t"> <span class="nam">font_size</span> <span class="op">=</span> <span class="num">12</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t"> <span class="nam">font_path</span> <span class="op">=</span> <span class="str">"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_is_header_section</span> <span class="key">and</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">header_text_bold</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"> <span class="nam">font_path</span> <span class="op">=</span> <span class="str">"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t"> <span class="nam">font</span> <span class="op">=</span> <span class="nam">Font</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t"> <span class="nam">font_path</span><span class="op">=</span><span class="nam">font_path</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t"> <span class="nam">font_size</span><span class="op">=</span><span class="nam">font_size</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t"> <span class="nam">weight</span><span class="op">=</span><span class="nam">FontWeight</span><span class="op">.</span><span class="nam">BOLD</span> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_is_header_section</span> <span class="key">and</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">header_text_bold</span> <span class="key">else</span> <span class="nam">FontWeight</span><span class="op">.</span><span class="nam">NORMAL</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t"> <span class="com"># Word spacing constraints (min, max)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t"> <span class="nam">min_spacing</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">font_size</span> <span class="op">*</span> <span class="num">0.25</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t"> <span class="nam">max_spacing</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">font_size</span> <span class="op">*</span> <span class="num">0.5</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t"> <span class="nam">word_spacing</span> <span class="op">=</span> <span class="op">(</span><span class="nam">min_spacing</span><span class="op">,</span> <span class="nam">max_spacing</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"> <span class="com"># Line height (baseline spacing)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t"> <span class="nam">line_height</span> <span class="op">=</span> <span class="nam">font_size</span> <span class="op">+</span> <span class="num">4</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"> <span class="nam">ascent</span><span class="op">,</span> <span class="nam">descent</span> <span class="op">=</span> <span class="nam">font</span><span class="op">.</span><span class="nam">font</span><span class="op">.</span><span class="nam">getmetrics</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t"> <span class="com"># Render each block in the cell</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t"> <span class="key">for</span> <span class="nam">block</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_cell</span><span class="op">.</span><span class="nam">blocks</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="nam">AbstractImage</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">142&#x202F;&#x219B;&#x202F;144</span><span class="annotate long">line 142 didn't jump to line 144 because the condition on line 142 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t"> <span class="com"># Render image</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"> <span class="nam">current_y</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_render_image_in_cell</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t"> <span class="nam">block</span><span class="op">,</span> <span class="nam">x</span><span class="op">,</span> <span class="nam">current_y</span><span class="op">,</span> <span class="nam">width</span><span class="op">,</span> <span class="nam">height</span> <span class="op">-</span> <span class="op">(</span><span class="nam">current_y</span> <span class="op">-</span> <span class="nam">y</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t"> <span class="key">elif</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="op">(</span><span class="nam">Paragraph</span><span class="op">,</span> <span class="nam">Heading</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">146&#x202F;&#x219B;&#x202F;225</span><span class="annotate long">line 146 didn't jump to line 225 because the condition on line 146 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"> <span class="com"># Get words from the block</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">inline</span> <span class="key">import</span> <span class="nam">Word</span> <span class="key">as</span> <span class="nam">AbstractWord</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t"> <span class="nam">word_items</span> <span class="op">=</span> <span class="nam">block</span><span class="op">.</span><span class="nam">words</span><span class="op">(</span><span class="op">)</span> <span class="key">if</span> <span class="nam">callable</span><span class="op">(</span><span class="nam">block</span><span class="op">.</span><span class="nam">words</span><span class="op">)</span> <span class="key">else</span> <span class="nam">block</span><span class="op">.</span><span class="nam">words</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t"> <span class="nam">words</span> <span class="op">=</span> <span class="nam">list</span><span class="op">(</span><span class="nam">word_items</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">words</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">153&#x202F;&#x219B;&#x202F;154</span><span class="annotate long">line 153 didn't jump to line 154 because the condition on line 153 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t"> <span class="key">continue</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t"> <span class="com"># Create new Word objects with the table cell's font</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t"> <span class="com"># The words from the paragraph may have AbstractStyle, but we need Font objects</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t"> <span class="nam">wrapped_words</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t"> <span class="key">for</span> <span class="nam">word_item</span> <span class="key">in</span> <span class="nam">words</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"> <span class="com"># Handle word tuples (index, word_obj)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">word_item</span><span class="op">,</span> <span class="nam">tuple</span><span class="op">)</span> <span class="key">and</span> <span class="nam">len</span><span class="op">(</span><span class="nam">word_item</span><span class="op">)</span> <span class="op">>=</span> <span class="num">2</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">161&#x202F;&#x219B;&#x202F;162</span><span class="annotate long">line 161 didn't jump to line 162 because the condition on line 161 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t"> <span class="nam">word_obj</span> <span class="op">=</span> <span class="nam">word_item</span><span class="op">[</span><span class="num">1</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t"> <span class="nam">word_obj</span> <span class="op">=</span> <span class="nam">word_item</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"> <span class="com"># Extract text from the word</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t"> <span class="nam">word_text</span> <span class="op">=</span> <span class="nam">word_obj</span><span class="op">.</span><span class="nam">text</span> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">word_obj</span><span class="op">,</span> <span class="str">'text'</span><span class="op">)</span> <span class="key">else</span> <span class="nam">str</span><span class="op">(</span><span class="nam">word_obj</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t"> <span class="com"># Create a new Word with the cell's Font</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"> <span class="nam">new_word</span> <span class="op">=</span> <span class="nam">AbstractWord</span><span class="op">(</span><span class="nam">word_text</span><span class="op">,</span> <span class="nam">font</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t"> <span class="nam">wrapped_words</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">new_word</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t"> <span class="com"># Layout words using Line objects with wrapping</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t"> <span class="nam">word_index</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t"> <span class="nam">pretext</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t"> <span class="key">while</span> <span class="nam">word_index</span> <span class="op">&lt;</span> <span class="nam">len</span><span class="op">(</span><span class="nam">wrapped_words</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t"> <span class="com"># Check if we have space for another line</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t"> <span class="key">if</span> <span class="nam">current_y</span> <span class="op">+</span> <span class="nam">ascent</span> <span class="op">+</span> <span class="nam">descent</span> <span class="op">></span> <span class="nam">y</span> <span class="op">+</span> <span class="nam">available_height</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">179&#x202F;&#x219B;&#x202F;180</span><span class="annotate long">line 179 didn't jump to line 180 because the condition on line 179 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t"> <span class="key">break</span> <span class="com"># No more space in cell</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t"> <span class="com"># Create a new line</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t"> <span class="nam">line</span> <span class="op">=</span> <span class="nam">Line</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t"> <span class="nam">spacing</span><span class="op">=</span><span class="nam">word_spacing</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t"> <span class="nam">origin</span><span class="op">=</span><span class="op">(</span><span class="nam">x</span> <span class="op">+</span> <span class="num">2</span><span class="op">,</span> <span class="nam">current_y</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t"> <span class="nam">size</span><span class="op">=</span><span class="op">(</span><span class="nam">width</span> <span class="op">-</span> <span class="num">4</span><span class="op">,</span> <span class="nam">line_height</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t"> <span class="nam">draw</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t"> <span class="nam">font</span><span class="op">=</span><span class="nam">font</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t"> <span class="nam">halign</span><span class="op">=</span><span class="nam">Alignment</span><span class="op">.</span><span class="nam">LEFT</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t"> <span class="com"># Add words to this line until it's full</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t"> <span class="nam">line_has_content</span> <span class="op">=</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t"> <span class="key">while</span> <span class="nam">word_index</span> <span class="op">&lt;</span> <span class="nam">len</span><span class="op">(</span><span class="nam">wrapped_words</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t"> <span class="nam">word</span> <span class="op">=</span> <span class="nam">wrapped_words</span><span class="op">[</span><span class="nam">word_index</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"> <span class="com"># Try to add word to line</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t"> <span class="nam">success</span><span class="op">,</span> <span class="nam">overflow</span> <span class="op">=</span> <span class="nam">line</span><span class="op">.</span><span class="nam">add_word</span><span class="op">(</span><span class="nam">word</span><span class="op">,</span> <span class="nam">pretext</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t"> <span class="nam">pretext</span> <span class="op">=</span> <span class="key">None</span> <span class="com"># Clear pretext after use</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t"> <span class="key">if</span> <span class="nam">success</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">201&#x202F;&#x219B;&#x202F;214</span><span class="annotate long">line 201 didn't jump to line 214 because the condition on line 201 was always true</span></span></p>
<p class="run"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t"> <span class="nam">line_has_content</span> <span class="op">=</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t"> <span class="key">if</span> <span class="nam">overflow</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">203&#x202F;&#x219B;&#x202F;207</span><span class="annotate long">line 203 didn't jump to line 207 because the condition on line 203 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t"> <span class="com"># Word was hyphenated, carry over to next line</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t"> <span class="com"># DON'T increment word_index - we need to add the overflow</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t"> <span class="com"># to the next line with the same word</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t"> <span class="nam">pretext</span> <span class="op">=</span> <span class="nam">overflow</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"> <span class="key">break</span> <span class="com"># Move to next line</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t"> <span class="com"># Word fit completely, move to next word</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t"> <span class="nam">word_index</span> <span class="op">+=</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"> <span class="com"># Word doesn't fit on this line</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">line_has_content</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t"> <span class="com"># Even first word doesn't fit, force it anyway and advance</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t"> <span class="com"># This prevents infinite loops with words that truly can't fit</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t"> <span class="nam">word_index</span> <span class="op">+=</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t"> <span class="key">break</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t"> <span class="com"># Render the line if it has content</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t"> <span class="key">if</span> <span class="nam">line_has_content</span> <span class="key">or</span> <span class="nam">len</span><span class="op">(</span><span class="nam">line</span><span class="op">.</span><span class="nam">text_objects</span><span class="op">)</span> <span class="op">></span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">221&#x202F;&#x219B;&#x202F;177</span><span class="annotate long">line 221 didn't jump to line 177 because the condition on line 221 was always true</span></span></p>
<p class="run"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"> <span class="nam">line</span><span class="op">.</span><span class="nam">render</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t"> <span class="nam">current_y</span> <span class="op">+=</span> <span class="nam">line_height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t"> <span class="key">if</span> <span class="nam">current_y</span> <span class="op">></span> <span class="nam">y</span> <span class="op">+</span> <span class="nam">height</span> <span class="op">-</span> <span class="num">10</span><span class="op">:</span> <span class="com"># Don't overflow cell</span>&nbsp;</span><span class="r"><span class="annotate short">225&#x202F;&#x219B;&#x202F;226</span><span class="annotate long">line 225 didn't jump to line 226 because the condition on line 225 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t"> <span class="key">break</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t"> <span class="com"># If no structured content, try to get any text representation</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t"> <span class="key">if</span> <span class="nam">current_y</span> <span class="op">==</span> <span class="nam">y</span> <span class="op">+</span> <span class="num">2</span> <span class="key">and</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_cell</span><span class="op">,</span> <span class="str">'_text_content'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">229&#x202F;&#x219B;&#x202F;231</span><span class="annotate long">line 229 didn't jump to line 231 because the condition on line 229 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t"> <span class="com"># Use simple text rendering for fallback case</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t"> <span class="key">from</span> <span class="nam">PIL</span> <span class="key">import</span> <span class="nam">ImageFont</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t"> <span class="nam">pil_font</span> <span class="op">=</span> <span class="nam">ImageFont</span><span class="op">.</span><span class="nam">truetype</span><span class="op">(</span><span class="nam">font_path</span><span class="op">,</span> <span class="nam">font_size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t"> <span class="key">except</span> <span class="nam">BaseException</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t"> <span class="nam">pil_font</span> <span class="op">=</span> <span class="nam">ImageFont</span><span class="op">.</span><span class="nam">load_default</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">text</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t"> <span class="op">(</span><span class="nam">x</span> <span class="op">+</span> <span class="num">2</span><span class="op">,</span> <span class="nam">current_y</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_cell</span><span class="op">.</span><span class="nam">_text_content</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t"> <span class="nam">fill</span><span class="op">=</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t"> <span class="nam">font</span><span class="op">=</span><span class="nam">pil_font</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t"> <span class="key">def</span> <span class="nam">_render_image_in_cell</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">image_block</span><span class="op">:</span> <span class="nam">AbstractImage</span><span class="op">,</span> <span class="nam">x</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">y</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t"> <span class="nam">max_width</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">max_height</span><span class="op">:</span> <span class="nam">int</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t"><span class="str"> Render an image block inside a table cell.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t"><span class="str"> The new Y position after the image</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t"> <span class="com"># Get the image path from the block</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t"> <span class="nam">image_path</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">image_block</span><span class="op">,</span> <span class="str">'source'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t"> <span class="nam">image_path</span> <span class="op">=</span> <span class="nam">image_block</span><span class="op">.</span><span class="nam">source</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t"> <span class="key">elif</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">image_block</span><span class="op">,</span> <span class="str">'_source'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t"> <span class="nam">image_path</span> <span class="op">=</span> <span class="nam">image_block</span><span class="op">.</span><span class="nam">_source</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t"> <span class="key">elif</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">image_block</span><span class="op">,</span> <span class="str">'path'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t"> <span class="nam">image_path</span> <span class="op">=</span> <span class="nam">image_block</span><span class="op">.</span><span class="nam">path</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t"> <span class="key">elif</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">image_block</span><span class="op">,</span> <span class="str">'src'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t"> <span class="nam">image_path</span> <span class="op">=</span> <span class="nam">image_block</span><span class="op">.</span><span class="nam">src</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t"> <span class="key">elif</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">image_block</span><span class="op">,</span> <span class="str">'_path'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t"> <span class="nam">image_path</span> <span class="op">=</span> <span class="nam">image_block</span><span class="op">.</span><span class="nam">_path</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t"> <span class="key">elif</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">image_block</span><span class="op">,</span> <span class="str">'_src'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t"> <span class="nam">image_path</span> <span class="op">=</span> <span class="nam">image_block</span><span class="op">.</span><span class="nam">_src</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">image_path</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t"> <span class="key">return</span> <span class="nam">y</span> <span class="op">+</span> <span class="num">20</span> <span class="com"># Skip if no image path</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t"> <span class="com"># Load and resize image to fit in cell</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t"> <span class="nam">img</span> <span class="op">=</span> <span class="nam">Image</span><span class="op">.</span><span class="nam">open</span><span class="op">(</span><span class="nam">image_path</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t"> <span class="com"># Calculate scaling to fit within max dimensions</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t"> <span class="com"># Use more of the cell space for images</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t"> <span class="nam">img_width</span><span class="op">,</span> <span class="nam">img_height</span> <span class="op">=</span> <span class="nam">img</span><span class="op">.</span><span class="nam">size</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t"> <span class="nam">scale_w</span> <span class="op">=</span> <span class="nam">max_width</span> <span class="op">/</span> <span class="nam">img_width</span> <span class="key">if</span> <span class="nam">img_width</span> <span class="op">></span> <span class="nam">max_width</span> <span class="key">else</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t"> <span class="nam">scale_h</span> <span class="op">=</span> <span class="op">(</span><span class="nam">max_height</span> <span class="op">-</span> <span class="num">10</span><span class="op">)</span> <span class="op">/</span> <span class="xx">\</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t279" href="#t279">279</a></span><span class="t"> <span class="nam">img_height</span> <span class="key">if</span> <span class="nam">img_height</span> <span class="op">></span> <span class="op">(</span><span class="nam">max_height</span> <span class="op">-</span> <span class="num">10</span><span class="op">)</span> <span class="key">else</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t280" href="#t280">280</a></span><span class="t"> <span class="nam">scale</span> <span class="op">=</span> <span class="nam">min</span><span class="op">(</span><span class="nam">scale_w</span><span class="op">,</span> <span class="nam">scale_h</span><span class="op">,</span> <span class="num">1.0</span><span class="op">)</span> <span class="com"># Don't upscale</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t281" href="#t281">281</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t282" href="#t282">282</a></span><span class="t"> <span class="nam">new_width</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">img_width</span> <span class="op">*</span> <span class="nam">scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t283" href="#t283">283</a></span><span class="t"> <span class="nam">new_height</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">img_height</span> <span class="op">*</span> <span class="nam">scale</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t284" href="#t284">284</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t285" href="#t285">285</a></span><span class="t"> <span class="key">if</span> <span class="nam">scale</span> <span class="op">&lt;</span> <span class="num">1.0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t286" href="#t286">286</a></span><span class="t"> <span class="nam">img</span> <span class="op">=</span> <span class="nam">img</span><span class="op">.</span><span class="nam">resize</span><span class="op">(</span><span class="op">(</span><span class="nam">new_width</span><span class="op">,</span> <span class="nam">new_height</span><span class="op">)</span><span class="op">,</span> <span class="nam">Image</span><span class="op">.</span><span class="nam">Resampling</span><span class="op">.</span><span class="nam">LANCZOS</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t287" href="#t287">287</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t288" href="#t288">288</a></span><span class="t"> <span class="com"># Center image horizontally in cell</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t289" href="#t289">289</a></span><span class="t"> <span class="nam">img_x</span> <span class="op">=</span> <span class="nam">x</span> <span class="op">+</span> <span class="op">(</span><span class="nam">max_width</span> <span class="op">-</span> <span class="nam">new_width</span><span class="op">)</span> <span class="op">//</span> <span class="num">2</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t290" href="#t290">290</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t291" href="#t291">291</a></span><span class="t"> <span class="com"># Paste the image onto the canvas if available</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t292" href="#t292">292</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t293" href="#t293">293</a></span><span class="t"> <span class="key">if</span> <span class="nam">img</span><span class="op">.</span><span class="nam">mode</span> <span class="op">==</span> <span class="str">'RGBA'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t294" href="#t294">294</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span><span class="op">.</span><span class="nam">paste</span><span class="op">(</span><span class="nam">img</span><span class="op">,</span> <span class="op">(</span><span class="nam">img_x</span><span class="op">,</span> <span class="nam">y</span><span class="op">)</span><span class="op">,</span> <span class="nam">img</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t295" href="#t295">295</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t296" href="#t296">296</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span><span class="op">.</span><span class="nam">paste</span><span class="op">(</span><span class="nam">img</span><span class="op">,</span> <span class="op">(</span><span class="nam">img_x</span><span class="op">,</span> <span class="nam">y</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t297" href="#t297">297</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t298" href="#t298">298</a></span><span class="t"> <span class="com"># Fallback: draw a placeholder if no canvas provided</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t299" href="#t299">299</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">rectangle</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t300" href="#t300">300</a></span><span class="t"> <span class="op">[</span><span class="nam">img_x</span><span class="op">,</span> <span class="nam">y</span><span class="op">,</span> <span class="nam">img_x</span> <span class="op">+</span> <span class="nam">new_width</span><span class="op">,</span> <span class="nam">y</span> <span class="op">+</span> <span class="nam">new_height</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t301" href="#t301">301</a></span><span class="t"> <span class="nam">fill</span><span class="op">=</span><span class="op">(</span><span class="num">200</span><span class="op">,</span> <span class="num">200</span><span class="op">,</span> <span class="num">200</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t302" href="#t302">302</a></span><span class="t"> <span class="nam">outline</span><span class="op">=</span><span class="op">(</span><span class="num">150</span><span class="op">,</span> <span class="num">150</span><span class="op">,</span> <span class="num">150</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t303" href="#t303">303</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t304" href="#t304">304</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t305" href="#t305">305</a></span><span class="t"> <span class="com"># Draw image indicator text</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t306" href="#t306">306</a></span><span class="t"> <span class="key">from</span> <span class="nam">PIL</span> <span class="key">import</span> <span class="nam">ImageFont</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t307" href="#t307">307</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t308" href="#t308">308</a></span><span class="t"> <span class="nam">small_font</span> <span class="op">=</span> <span class="nam">ImageFont</span><span class="op">.</span><span class="nam">truetype</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t309" href="#t309">309</a></span><span class="t"> <span class="str">"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"</span><span class="op">,</span> <span class="num">9</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t310" href="#t310">310</a></span><span class="t"> <span class="key">except</span> <span class="nam">BaseException</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t311" href="#t311">311</a></span><span class="t"> <span class="nam">small_font</span> <span class="op">=</span> <span class="nam">ImageFont</span><span class="op">.</span><span class="nam">load_default</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t312" href="#t312">312</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t313" href="#t313">313</a></span><span class="t"> <span class="nam">text</span> <span class="op">=</span> <span class="fst">f"</span><span class="fst">[Image: </span><span class="op">{</span><span class="nam">new_width</span><span class="op">}</span><span class="fst">x</span><span class="op">{</span><span class="nam">new_height</span><span class="op">}</span><span class="fst">]</span><span class="fst">"</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t314" href="#t314">314</a></span><span class="t"> <span class="nam">bbox</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">textbbox</span><span class="op">(</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">,</span> <span class="nam">text</span><span class="op">,</span> <span class="nam">font</span><span class="op">=</span><span class="nam">small_font</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t315" href="#t315">315</a></span><span class="t"> <span class="nam">text_width</span> <span class="op">=</span> <span class="nam">bbox</span><span class="op">[</span><span class="num">2</span><span class="op">]</span> <span class="op">-</span> <span class="nam">bbox</span><span class="op">[</span><span class="num">0</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t316" href="#t316">316</a></span><span class="t"> <span class="nam">text_x</span> <span class="op">=</span> <span class="nam">img_x</span> <span class="op">+</span> <span class="op">(</span><span class="nam">new_width</span> <span class="op">-</span> <span class="nam">text_width</span><span class="op">)</span> <span class="op">//</span> <span class="num">2</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t317" href="#t317">317</a></span><span class="t"> <span class="nam">text_y</span> <span class="op">=</span> <span class="nam">y</span> <span class="op">+</span> <span class="op">(</span><span class="nam">new_height</span> <span class="op">-</span> <span class="num">12</span><span class="op">)</span> <span class="op">//</span> <span class="num">2</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t318" href="#t318">318</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">text</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t319" href="#t319">319</a></span><span class="t"> <span class="op">(</span><span class="nam">text_x</span><span class="op">,</span> <span class="nam">text_y</span><span class="op">)</span><span class="op">,</span> <span class="nam">text</span><span class="op">,</span> <span class="nam">fill</span><span class="op">=</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t320" href="#t320">320</a></span><span class="t"> <span class="num">100</span><span class="op">,</span> <span class="num">100</span><span class="op">,</span> <span class="num">100</span><span class="op">)</span><span class="op">,</span> <span class="nam">font</span><span class="op">=</span><span class="nam">small_font</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t321" href="#t321">321</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t322" href="#t322">322</a></span><span class="t"> <span class="com"># Set bounds on InteractiveImage objects for tap detection</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t323" href="#t323">323</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">image_block</span><span class="op">,</span> <span class="nam">InteractiveImage</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t324" href="#t324">324</a></span><span class="t"> <span class="nam">image_block</span><span class="op">.</span><span class="nam">set_rendered_bounds</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t325" href="#t325">325</a></span><span class="t"> <span class="nam">origin</span><span class="op">=</span><span class="op">(</span><span class="nam">img_x</span><span class="op">,</span> <span class="nam">y</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t326" href="#t326">326</a></span><span class="t"> <span class="nam">size</span><span class="op">=</span><span class="op">(</span><span class="nam">new_width</span><span class="op">,</span> <span class="nam">new_height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t327" href="#t327">327</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t328" href="#t328">328</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t329" href="#t329">329</a></span><span class="t"> <span class="key">return</span> <span class="nam">y</span> <span class="op">+</span> <span class="nam">new_height</span> <span class="op">+</span> <span class="num">5</span> <span class="com"># Add some spacing after image</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t330" href="#t330">330</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t331" href="#t331">331</a></span><span class="t"> <span class="key">except</span> <span class="nam">Exception</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t332" href="#t332">332</a></span><span class="t"> <span class="com"># If image loading fails, just return current position</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t333" href="#t333">333</a></span><span class="t"> <span class="key">return</span> <span class="nam">y</span> <span class="op">+</span> <span class="num">20</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t334" href="#t334">334</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t335" href="#t335">335</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t336" href="#t336">336</a></span><span class="t"><span class="key">class</span> <span class="nam">TableRowRenderer</span><span class="op">(</span><span class="nam">Box</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t337" href="#t337">337</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t338" href="#t338">338</a></span><span class="t"><span class="str"> Renders a single table row containing multiple cells.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t339" href="#t339">339</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t340" href="#t340">340</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t341" href="#t341">341</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t342" href="#t342">342</a></span><span class="t"> <span class="nam">row</span><span class="op">:</span> <span class="nam">TableRow</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t343" href="#t343">343</a></span><span class="t"> <span class="nam">origin</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t344" href="#t344">344</a></span><span class="t"> <span class="nam">int</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t345" href="#t345">345</a></span><span class="t"> <span class="nam">column_widths</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t346" href="#t346">346</a></span><span class="t"> <span class="nam">row_height</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t347" href="#t347">347</a></span><span class="t"> <span class="nam">draw</span><span class="op">:</span> <span class="nam">ImageDraw</span><span class="op">.</span><span class="nam">Draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t348" href="#t348">348</a></span><span class="t"> <span class="nam">style</span><span class="op">:</span> <span class="nam">TableStyle</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t349" href="#t349">349</a></span><span class="t"> <span class="nam">is_header_section</span><span class="op">:</span> <span class="nam">bool</span> <span class="op">=</span> <span class="key">False</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t350" href="#t350">350</a></span><span class="t"> <span class="nam">canvas</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Image</span><span class="op">.</span><span class="nam">Image</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t351" href="#t351">351</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t352" href="#t352">352</a></span><span class="t"><span class="str"> Initialize a table row renderer.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t353" href="#t353">353</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t354" href="#t354">354</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t355" href="#t355">355</a></span><span class="t"><span class="str"> row: The abstract TableRow to render</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t356" href="#t356">356</a></span><span class="t"><span class="str"> origin: Top-left position of the row</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t357" href="#t357">357</a></span><span class="t"><span class="str"> column_widths: List of widths for each column</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t358" href="#t358">358</a></span><span class="t"><span class="str"> row_height: Height of this row</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t359" href="#t359">359</a></span><span class="t"><span class="str"> draw: PIL ImageDraw object for rendering</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t360" href="#t360">360</a></span><span class="t"><span class="str"> style: Table styling configuration</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t361" href="#t361">361</a></span><span class="t"><span class="str"> is_header_section: Whether this row is in the header section</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t362" href="#t362">362</a></span><span class="t"><span class="str"> canvas: Optional PIL Image for pasting images</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t363" href="#t363">363</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t364" href="#t364">364</a></span><span class="t"> <span class="nam">width</span> <span class="op">=</span> <span class="nam">sum</span><span class="op">(</span><span class="nam">column_widths</span><span class="op">)</span> <span class="op">+</span> <span class="nam">style</span><span class="op">.</span><span class="nam">border_width</span> <span class="op">*</span> <span class="op">(</span><span class="nam">len</span><span class="op">(</span><span class="nam">column_widths</span><span class="op">)</span> <span class="op">+</span> <span class="num">1</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t365" href="#t365">365</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="nam">origin</span><span class="op">,</span> <span class="op">(</span><span class="nam">width</span><span class="op">,</span> <span class="nam">row_height</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t366" href="#t366">366</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_row</span> <span class="op">=</span> <span class="nam">row</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t367" href="#t367">367</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_column_widths</span> <span class="op">=</span> <span class="nam">column_widths</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t368" href="#t368">368</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_row_height</span> <span class="op">=</span> <span class="nam">row_height</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t369" href="#t369">369</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span> <span class="op">=</span> <span class="nam">draw</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t370" href="#t370">370</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span> <span class="op">=</span> <span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t371" href="#t371">371</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_is_header_section</span> <span class="op">=</span> <span class="nam">is_header_section</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t372" href="#t372">372</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span> <span class="op">=</span> <span class="nam">canvas</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t373" href="#t373">373</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_cell_renderers</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">TableCellRenderer</span><span class="op">]</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t374" href="#t374">374</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t375" href="#t375">375</a></span><span class="t"> <span class="key">def</span> <span class="nam">render</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Image</span><span class="op">.</span><span class="nam">Image</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t376" href="#t376">376</a></span><span class="t"> <span class="str">"""Render the table row by rendering each cell."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t377" href="#t377">377</a></span><span class="t"> <span class="nam">x</span><span class="op">,</span> <span class="nam">y</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t378" href="#t378">378</a></span><span class="t"> <span class="nam">current_x</span> <span class="op">=</span> <span class="nam">x</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t379" href="#t379">379</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t380" href="#t380">380</a></span><span class="t"> <span class="com"># Render each cell</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t381" href="#t381">381</a></span><span class="t"> <span class="nam">cells</span> <span class="op">=</span> <span class="nam">list</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_row</span><span class="op">.</span><span class="nam">cells</span><span class="op">(</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t382" href="#t382">382</a></span><span class="t"> <span class="key">for</span> <span class="nam">i</span><span class="op">,</span> <span class="nam">cell</span> <span class="key">in</span> <span class="nam">enumerate</span><span class="op">(</span><span class="nam">cells</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t383" href="#t383">383</a></span><span class="t"> <span class="key">if</span> <span class="nam">i</span> <span class="op">&lt;</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_column_widths</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">383&#x202F;&#x219B;&#x202F;382</span><span class="annotate long">line 383 didn't jump to line 382 because the condition on line 383 was always true</span></span></p>
<p class="run"><span class="n"><a id="t384" href="#t384">384</a></span><span class="t"> <span class="nam">cell_width</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_column_widths</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t385" href="#t385">385</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t386" href="#t386">386</a></span><span class="t"> <span class="com"># Handle colspan</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t387" href="#t387">387</a></span><span class="t"> <span class="key">if</span> <span class="nam">cell</span><span class="op">.</span><span class="nam">colspan</span> <span class="op">></span> <span class="num">1</span> <span class="key">and</span> <span class="nam">i</span> <span class="op">+</span> <span class="nam">cell</span><span class="op">.</span><span class="nam">colspan</span> <span class="op">&lt;=</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_column_widths</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t388" href="#t388">388</a></span><span class="t"> <span class="com"># Sum up widths for spanned columns</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t389" href="#t389">389</a></span><span class="t"> <span class="nam">cell_width</span> <span class="op">=</span> <span class="nam">sum</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_column_widths</span><span class="op">[</span><span class="nam">i</span><span class="op">:</span><span class="nam">i</span> <span class="op">+</span> <span class="nam">cell</span><span class="op">.</span><span class="nam">colspan</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t390" href="#t390">390</a></span><span class="t"> <span class="nam">cell_width</span> <span class="op">+=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">border_width</span> <span class="op">*</span> <span class="op">(</span><span class="nam">cell</span><span class="op">.</span><span class="nam">colspan</span> <span class="op">-</span> <span class="num">1</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t391" href="#t391">391</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t392" href="#t392">392</a></span><span class="t"> <span class="com"># Create and render cell</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t393" href="#t393">393</a></span><span class="t"> <span class="nam">cell_renderer</span> <span class="op">=</span> <span class="nam">TableCellRenderer</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t394" href="#t394">394</a></span><span class="t"> <span class="nam">cell</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t395" href="#t395">395</a></span><span class="t"> <span class="op">(</span><span class="nam">current_x</span><span class="op">,</span> <span class="nam">y</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t396" href="#t396">396</a></span><span class="t"> <span class="op">(</span><span class="nam">cell_width</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_row_height</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t397" href="#t397">397</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t398" href="#t398">398</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t399" href="#t399">399</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_is_header_section</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t400" href="#t400">400</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t401" href="#t401">401</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t402" href="#t402">402</a></span><span class="t"> <span class="nam">cell_renderer</span><span class="op">.</span><span class="nam">render</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t403" href="#t403">403</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_cell_renderers</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">cell_renderer</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t404" href="#t404">404</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t405" href="#t405">405</a></span><span class="t"> <span class="nam">current_x</span> <span class="op">+=</span> <span class="nam">cell_width</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">border_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t406" href="#t406">406</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t407" href="#t407">407</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span> <span class="com"># Row rendering is done directly on the page</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t408" href="#t408">408</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t409" href="#t409">409</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t410" href="#t410">410</a></span><span class="t"><span class="key">class</span> <span class="nam">TableRenderer</span><span class="op">(</span><span class="nam">Box</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t411" href="#t411">411</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t412" href="#t412">412</a></span><span class="t"><span class="str"> Main table renderer that orchestrates the rendering of an entire table.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t413" href="#t413">413</a></span><span class="t"><span class="str"> Handles layout calculation, row/cell placement, and overall table structure.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t414" href="#t414">414</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t415" href="#t415">415</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t416" href="#t416">416</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t417" href="#t417">417</a></span><span class="t"> <span class="nam">table</span><span class="op">:</span> <span class="nam">Table</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t418" href="#t418">418</a></span><span class="t"> <span class="nam">origin</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t419" href="#t419">419</a></span><span class="t"> <span class="nam">int</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t420" href="#t420">420</a></span><span class="t"> <span class="nam">available_width</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t421" href="#t421">421</a></span><span class="t"> <span class="nam">draw</span><span class="op">:</span> <span class="nam">ImageDraw</span><span class="op">.</span><span class="nam">Draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t422" href="#t422">422</a></span><span class="t"> <span class="nam">style</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">TableStyle</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t423" href="#t423">423</a></span><span class="t"> <span class="nam">canvas</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Image</span><span class="op">.</span><span class="nam">Image</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t424" href="#t424">424</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t425" href="#t425">425</a></span><span class="t"><span class="str"> Initialize a table renderer.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t426" href="#t426">426</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t427" href="#t427">427</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t428" href="#t428">428</a></span><span class="t"><span class="str"> table: The abstract Table to render</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t429" href="#t429">429</a></span><span class="t"><span class="str"> origin: Top-left position where the table should be rendered</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t430" href="#t430">430</a></span><span class="t"><span class="str"> available_width: Maximum width available for the table</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t431" href="#t431">431</a></span><span class="t"><span class="str"> draw: PIL ImageDraw object for rendering</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t432" href="#t432">432</a></span><span class="t"><span class="str"> style: Optional table styling configuration</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t433" href="#t433">433</a></span><span class="t"><span class="str"> canvas: Optional PIL Image for pasting images</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t434" href="#t434">434</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t435" href="#t435">435</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_table</span> <span class="op">=</span> <span class="nam">table</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t436" href="#t436">436</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span> <span class="op">=</span> <span class="nam">draw</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t437" href="#t437">437</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span> <span class="op">=</span> <span class="nam">style</span> <span class="key">or</span> <span class="nam">TableStyle</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t438" href="#t438">438</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_available_width</span> <span class="op">=</span> <span class="nam">available_width</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t439" href="#t439">439</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span> <span class="op">=</span> <span class="nam">canvas</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t440" href="#t440">440</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t441" href="#t441">441</a></span><span class="t"> <span class="com"># Calculate table dimensions</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t442" href="#t442">442</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_column_widths</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_row_heights</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_calculate_dimensions</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t443" href="#t443">443</a></span><span class="t"> <span class="nam">total_width</span> <span class="op">=</span> <span class="nam">sum</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_column_widths</span><span class="op">)</span> <span class="op">+</span> <span class="xx">\</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t444" href="#t444">444</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">border_width</span> <span class="op">*</span> <span class="op">(</span><span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_column_widths</span><span class="op">)</span> <span class="op">+</span> <span class="num">1</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t445" href="#t445">445</a></span><span class="t"> <span class="nam">total_height</span> <span class="op">=</span> <span class="nam">sum</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_row_heights</span><span class="op">.</span><span class="nam">values</span><span class="op">(</span><span class="op">)</span><span class="op">)</span> <span class="op">+</span> <span class="xx">\</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t446" href="#t446">446</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">border_width</span> <span class="op">*</span> <span class="op">(</span><span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_row_heights</span><span class="op">)</span> <span class="op">+</span> <span class="num">1</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t447" href="#t447">447</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t448" href="#t448">448</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="nam">origin</span><span class="op">,</span> <span class="op">(</span><span class="nam">total_width</span><span class="op">,</span> <span class="nam">total_height</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t449" href="#t449">449</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_row_renderers</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">TableRowRenderer</span><span class="op">]</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t450" href="#t450">450</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t451" href="#t451">451</a></span><span class="t"> <span class="key">def</span> <span class="nam">_calculate_dimensions</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">List</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span><span class="op">,</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t452" href="#t452">452</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t453" href="#t453">453</a></span><span class="t"><span class="str"> Calculate column widths and row heights for the table.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t454" href="#t454">454</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t455" href="#t455">455</a></span><span class="t"><span class="str"> Uses the table optimizer for intelligent column width distribution.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t456" href="#t456">456</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t457" href="#t457">457</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t458" href="#t458">458</a></span><span class="t"><span class="str"> Tuple of (column_widths, row_heights_dict)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t459" href="#t459">459</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t460" href="#t460">460</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">layout</span><span class="op">.</span><span class="nam">table_optimizer</span> <span class="key">import</span> <span class="nam">optimize_table_layout</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t461" href="#t461">461</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t462" href="#t462">462</a></span><span class="t"> <span class="nam">all_rows</span> <span class="op">=</span> <span class="nam">list</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_table</span><span class="op">.</span><span class="nam">all_rows</span><span class="op">(</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t463" href="#t463">463</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t464" href="#t464">464</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">all_rows</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t465" href="#t465">465</a></span><span class="t"> <span class="key">return</span> <span class="op">(</span><span class="op">[</span><span class="num">100</span><span class="op">]</span><span class="op">,</span> <span class="op">{</span><span class="str">"header"</span><span class="op">:</span> <span class="num">30</span><span class="op">,</span> <span class="str">"body"</span><span class="op">:</span> <span class="num">30</span><span class="op">,</span> <span class="str">"footer"</span><span class="op">:</span> <span class="num">30</span><span class="op">}</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t466" href="#t466">466</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t467" href="#t467">467</a></span><span class="t"> <span class="com"># Use optimizer for column widths!</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t468" href="#t468">468</a></span><span class="t"> <span class="nam">column_widths</span> <span class="op">=</span> <span class="nam">optimize_table_layout</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t469" href="#t469">469</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_table</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t470" href="#t470">470</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_available_width</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t471" href="#t471">471</a></span><span class="t"> <span class="nam">sample_size</span><span class="op">=</span><span class="num">5</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t472" href="#t472">472</a></span><span class="t"> <span class="nam">style</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">_style</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t473" href="#t473">473</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t474" href="#t474">474</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t475" href="#t475">475</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">column_widths</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">475&#x202F;&#x219B;&#x202F;477</span><span class="annotate long">line 475 didn't jump to line 477 because the condition on line 475 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t476" href="#t476">476</a></span><span class="t"> <span class="com"># Fallback if table is empty</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t477" href="#t477">477</a></span><span class="t"> <span class="nam">column_widths</span> <span class="op">=</span> <span class="op">[</span><span class="num">100</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t478" href="#t478">478</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t479" href="#t479">479</a></span><span class="t"> <span class="com"># Calculate row heights dynamically based on optimized column widths</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t480" href="#t480">480</a></span><span class="t"> <span class="nam">header_height</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_calculate_row_height_for_section</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t481" href="#t481">481</a></span><span class="t"> <span class="nam">all_rows</span><span class="op">,</span> <span class="str">"header"</span><span class="op">,</span> <span class="nam">column_widths</span><span class="op">)</span> <span class="key">if</span> <span class="nam">any</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t482" href="#t482">482</a></span><span class="t"> <span class="num">1</span> <span class="key">for</span> <span class="nam">section</span><span class="op">,</span> <span class="nam">_</span> <span class="key">in</span> <span class="nam">all_rows</span> <span class="key">if</span> <span class="nam">section</span> <span class="op">==</span> <span class="str">"header"</span><span class="op">)</span> <span class="key">else</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t483" href="#t483">483</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t484" href="#t484">484</a></span><span class="t"> <span class="nam">body_height</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_calculate_row_height_for_section</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t485" href="#t485">485</a></span><span class="t"> <span class="nam">all_rows</span><span class="op">,</span> <span class="str">"body"</span><span class="op">,</span> <span class="nam">column_widths</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t486" href="#t486">486</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t487" href="#t487">487</a></span><span class="t"> <span class="nam">footer_height</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_calculate_row_height_for_section</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t488" href="#t488">488</a></span><span class="t"> <span class="nam">all_rows</span><span class="op">,</span> <span class="str">"footer"</span><span class="op">,</span> <span class="nam">column_widths</span><span class="op">)</span> <span class="key">if</span> <span class="nam">any</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t489" href="#t489">489</a></span><span class="t"> <span class="num">1</span> <span class="key">for</span> <span class="nam">section</span><span class="op">,</span> <span class="nam">_</span> <span class="key">in</span> <span class="nam">all_rows</span> <span class="key">if</span> <span class="nam">section</span> <span class="op">==</span> <span class="str">"footer"</span><span class="op">)</span> <span class="key">else</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t490" href="#t490">490</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t491" href="#t491">491</a></span><span class="t"> <span class="nam">row_heights</span> <span class="op">=</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t492" href="#t492">492</a></span><span class="t"> <span class="str">"header"</span><span class="op">:</span> <span class="nam">header_height</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t493" href="#t493">493</a></span><span class="t"> <span class="str">"body"</span><span class="op">:</span> <span class="nam">body_height</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t494" href="#t494">494</a></span><span class="t"> <span class="str">"footer"</span><span class="op">:</span> <span class="nam">footer_height</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t495" href="#t495">495</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t496" href="#t496">496</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t497" href="#t497">497</a></span><span class="t"> <span class="key">return</span> <span class="op">(</span><span class="nam">column_widths</span><span class="op">,</span> <span class="nam">row_heights</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t498" href="#t498">498</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t499" href="#t499">499</a></span><span class="t"> <span class="key">def</span> <span class="nam">_calculate_row_height_for_section</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t500" href="#t500">500</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t501" href="#t501">501</a></span><span class="t"> <span class="nam">all_rows</span><span class="op">:</span> <span class="nam">List</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t502" href="#t502">502</a></span><span class="t"> <span class="nam">section</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t503" href="#t503">503</a></span><span class="t"> <span class="nam">column_widths</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t504" href="#t504">504</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t505" href="#t505">505</a></span><span class="t"><span class="str"> Calculate the maximum required height for rows in a specific section.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t506" href="#t506">506</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t507" href="#t507">507</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t508" href="#t508">508</a></span><span class="t"><span class="str"> all_rows: List of all rows in the table</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t509" href="#t509">509</a></span><span class="t"><span class="str"> section: Section name ('header', 'body', or 'footer')</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t510" href="#t510">510</a></span><span class="t"><span class="str"> column_widths: List of column widths</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t511" href="#t511">511</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t512" href="#t512">512</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t513" href="#t513">513</a></span><span class="t"><span class="str"> Maximum height needed for rows in this section</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t514" href="#t514">514</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t515" href="#t515">515</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span><span class="op">.</span><span class="nam">text</span> <span class="key">import</span> <span class="nam">Text</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t516" href="#t516">516</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">fonts</span> <span class="key">import</span> <span class="nam">Font</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t517" href="#t517">517</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">inline</span> <span class="key">import</span> <span class="nam">Word</span> <span class="key">as</span> <span class="nam">AbstractWord</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t518" href="#t518">518</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t519" href="#t519">519</a></span><span class="t"> <span class="com"># Font configuration</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t520" href="#t520">520</a></span><span class="t"> <span class="nam">font_size</span> <span class="op">=</span> <span class="num">12</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t521" href="#t521">521</a></span><span class="t"> <span class="nam">line_height</span> <span class="op">=</span> <span class="nam">font_size</span> <span class="op">+</span> <span class="num">4</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t522" href="#t522">522</a></span><span class="t"> <span class="nam">padding</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">cell_padding</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t523" href="#t523">523</a></span><span class="t"> <span class="nam">vertical_padding</span> <span class="op">=</span> <span class="nam">padding</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">+</span> <span class="nam">padding</span><span class="op">[</span><span class="num">2</span><span class="op">]</span> <span class="com"># top + bottom</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t524" href="#t524">524</a></span><span class="t"> <span class="nam">horizontal_padding</span> <span class="op">=</span> <span class="nam">padding</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">+</span> <span class="nam">padding</span><span class="op">[</span><span class="num">3</span><span class="op">]</span> <span class="com"># left + right</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t525" href="#t525">525</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t526" href="#t526">526</a></span><span class="t"> <span class="nam">max_height</span> <span class="op">=</span> <span class="num">40</span> <span class="com"># Minimum height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t527" href="#t527">527</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t528" href="#t528">528</a></span><span class="t"> <span class="key">for</span> <span class="nam">row_section</span><span class="op">,</span> <span class="nam">row</span> <span class="key">in</span> <span class="nam">all_rows</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t529" href="#t529">529</a></span><span class="t"> <span class="key">if</span> <span class="nam">row_section</span> <span class="op">!=</span> <span class="nam">section</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t530" href="#t530">530</a></span><span class="t"> <span class="key">continue</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t531" href="#t531">531</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t532" href="#t532">532</a></span><span class="t"> <span class="nam">row_max_height</span> <span class="op">=</span> <span class="num">40</span> <span class="com"># Minimum for this row</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t533" href="#t533">533</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t534" href="#t534">534</a></span><span class="t"> <span class="key">for</span> <span class="nam">cell_idx</span><span class="op">,</span> <span class="nam">cell</span> <span class="key">in</span> <span class="nam">enumerate</span><span class="op">(</span><span class="nam">row</span><span class="op">.</span><span class="nam">cells</span><span class="op">(</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t535" href="#t535">535</a></span><span class="t"> <span class="key">if</span> <span class="nam">cell_idx</span> <span class="op">>=</span> <span class="nam">len</span><span class="op">(</span><span class="nam">column_widths</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">535&#x202F;&#x219B;&#x202F;536</span><span class="annotate long">line 535 didn't jump to line 536 because the condition on line 535 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t536" href="#t536">536</a></span><span class="t"> <span class="key">continue</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t537" href="#t537">537</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t538" href="#t538">538</a></span><span class="t"> <span class="com"># Get cell width (accounting for colspan)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t539" href="#t539">539</a></span><span class="t"> <span class="nam">cell_width</span> <span class="op">=</span> <span class="nam">column_widths</span><span class="op">[</span><span class="nam">cell_idx</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t540" href="#t540">540</a></span><span class="t"> <span class="key">if</span> <span class="nam">cell</span><span class="op">.</span><span class="nam">colspan</span> <span class="op">></span> <span class="num">1</span> <span class="key">and</span> <span class="nam">cell_idx</span> <span class="op">+</span> <span class="xx">\</span>&nbsp;</span><span class="r"><span class="annotate short">540&#x202F;&#x219B;&#x202F;542</span><span class="annotate long">line 540 didn't jump to line 542 because the condition on line 540 was never true</span></span></p>
<p class="par par2 ru2 show_par"><span class="n"><a id="t541" href="#t541">541</a></span><span class="t"> <span class="nam">cell</span><span class="op">.</span><span class="nam">colspan</span> <span class="op">&lt;=</span> <span class="nam">len</span><span class="op">(</span><span class="nam">column_widths</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t542" href="#t542">542</a></span><span class="t"> <span class="nam">cell_width</span> <span class="op">=</span> <span class="nam">sum</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t543" href="#t543">543</a></span><span class="t"> <span class="nam">column_widths</span><span class="op">[</span><span class="nam">cell_idx</span><span class="op">:</span><span class="nam">cell_idx</span> <span class="op">+</span> <span class="nam">cell</span><span class="op">.</span><span class="nam">colspan</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t544" href="#t544">544</a></span><span class="t"> <span class="nam">cell_width</span> <span class="op">+=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">border_width</span> <span class="op">*</span> <span class="op">(</span><span class="nam">cell</span><span class="op">.</span><span class="nam">colspan</span> <span class="op">-</span> <span class="num">1</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t545" href="#t545">545</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t546" href="#t546">546</a></span><span class="t"> <span class="com"># Calculate content width (minus padding)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t547" href="#t547">547</a></span><span class="t"> <span class="nam">content_width</span> <span class="op">=</span> <span class="nam">cell_width</span> <span class="op">-</span> <span class="nam">horizontal_padding</span> <span class="op">-</span> <span class="num">4</span> <span class="com"># Extra margin</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t548" href="#t548">548</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t549" href="#t549">549</a></span><span class="t"> <span class="nam">cell_height</span> <span class="op">=</span> <span class="nam">vertical_padding</span> <span class="op">+</span> <span class="num">4</span> <span class="com"># Base height with padding</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t550" href="#t550">550</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t551" href="#t551">551</a></span><span class="t"> <span class="com"># Analyze each block in the cell</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t552" href="#t552">552</a></span><span class="t"> <span class="key">for</span> <span class="nam">block</span> <span class="key">in</span> <span class="nam">cell</span><span class="op">.</span><span class="nam">blocks</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t553" href="#t553">553</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="nam">AbstractImage</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">553&#x202F;&#x219B;&#x202F;555</span><span class="annotate long">line 553 didn't jump to line 555 because the condition on line 553 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t554" href="#t554">554</a></span><span class="t"> <span class="com"># Images need more space</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t555" href="#t555">555</a></span><span class="t"> <span class="nam">cell_height</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">cell_height</span><span class="op">,</span> <span class="num">120</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t556" href="#t556">556</a></span><span class="t"> <span class="key">elif</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="op">(</span><span class="nam">Paragraph</span><span class="op">,</span> <span class="nam">Heading</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">556&#x202F;&#x219B;&#x202F;552</span><span class="annotate long">line 556 didn't jump to line 552 because the condition on line 556 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t557" href="#t557">557</a></span><span class="t"> <span class="com"># Calculate text wrapping height</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t558" href="#t558">558</a></span><span class="t"> <span class="nam">word_items</span> <span class="op">=</span> <span class="nam">block</span><span class="op">.</span><span class="nam">words</span><span class="op">(</span><span class="op">)</span> <span class="key">if</span> <span class="nam">callable</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t559" href="#t559">559</a></span><span class="t"> <span class="nam">block</span><span class="op">.</span><span class="nam">words</span><span class="op">)</span> <span class="key">else</span> <span class="nam">block</span><span class="op">.</span><span class="nam">words</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t560" href="#t560">560</a></span><span class="t"> <span class="nam">words</span> <span class="op">=</span> <span class="nam">list</span><span class="op">(</span><span class="nam">word_items</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t561" href="#t561">561</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t562" href="#t562">562</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">words</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">562&#x202F;&#x219B;&#x202F;563</span><span class="annotate long">line 562 didn't jump to line 563 because the condition on line 562 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t563" href="#t563">563</a></span><span class="t"> <span class="key">continue</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t564" href="#t564">564</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t565" href="#t565">565</a></span><span class="t"> <span class="com"># Simulate text wrapping to count lines</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t566" href="#t566">566</a></span><span class="t"> <span class="nam">lines_needed</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_estimate_wrapped_lines</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t567" href="#t567">567</a></span><span class="t"> <span class="nam">words</span><span class="op">,</span> <span class="nam">content_width</span><span class="op">,</span> <span class="nam">font_size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t568" href="#t568">568</a></span><span class="t"> <span class="nam">text_height</span> <span class="op">=</span> <span class="nam">lines_needed</span> <span class="op">*</span> <span class="nam">line_height</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t569" href="#t569">569</a></span><span class="t"> <span class="nam">cell_height</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t570" href="#t570">570</a></span><span class="t"> <span class="nam">cell_height</span><span class="op">,</span> <span class="nam">text_height</span> <span class="op">+</span> <span class="nam">vertical_padding</span> <span class="op">+</span> <span class="num">4</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t571" href="#t571">571</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t572" href="#t572">572</a></span><span class="t"> <span class="nam">row_max_height</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">row_max_height</span><span class="op">,</span> <span class="nam">cell_height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t573" href="#t573">573</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t574" href="#t574">574</a></span><span class="t"> <span class="nam">max_height</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">max_height</span><span class="op">,</span> <span class="nam">row_max_height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t575" href="#t575">575</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t576" href="#t576">576</a></span><span class="t"> <span class="key">return</span> <span class="nam">max_height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t577" href="#t577">577</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t578" href="#t578">578</a></span><span class="t"> <span class="key">def</span> <span class="nam">_estimate_wrapped_lines</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t579" href="#t579">579</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t580" href="#t580">580</a></span><span class="t"> <span class="nam">words</span><span class="op">:</span> <span class="nam">List</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t581" href="#t581">581</a></span><span class="t"> <span class="nam">available_width</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t582" href="#t582">582</a></span><span class="t"> <span class="nam">font_size</span><span class="op">:</span> <span class="nam">int</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t583" href="#t583">583</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t584" href="#t584">584</a></span><span class="t"><span class="str"> Estimate how many lines are needed to render the given words.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t585" href="#t585">585</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t586" href="#t586">586</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t587" href="#t587">587</a></span><span class="t"><span class="str"> words: List of word objects</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t588" href="#t588">588</a></span><span class="t"><span class="str"> available_width: Available width for text</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t589" href="#t589">589</a></span><span class="t"><span class="str"> font_size: Font size in pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t590" href="#t590">590</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t591" href="#t591">591</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t592" href="#t592">592</a></span><span class="t"><span class="str"> Number of lines needed</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t593" href="#t593">593</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t594" href="#t594">594</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">concrete</span><span class="op">.</span><span class="nam">text</span> <span class="key">import</span> <span class="nam">Text</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t595" href="#t595">595</a></span><span class="t"> <span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">fonts</span> <span class="key">import</span> <span class="nam">Font</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t596" href="#t596">596</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t597" href="#t597">597</a></span><span class="t"> <span class="com"># Create a temporary font for measurement</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t598" href="#t598">598</a></span><span class="t"> <span class="nam">font_path</span> <span class="op">=</span> <span class="str">"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t599" href="#t599">599</a></span><span class="t"> <span class="nam">font</span> <span class="op">=</span> <span class="nam">Font</span><span class="op">(</span><span class="nam">font_path</span><span class="op">=</span><span class="nam">font_path</span><span class="op">,</span> <span class="nam">font_size</span><span class="op">=</span><span class="nam">font_size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t600" href="#t600">600</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t601" href="#t601">601</a></span><span class="t"> <span class="com"># Word spacing (approximate)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t602" href="#t602">602</a></span><span class="t"> <span class="nam">word_spacing</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">font_size</span> <span class="op">*</span> <span class="num">0.25</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t603" href="#t603">603</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t604" href="#t604">604</a></span><span class="t"> <span class="nam">lines</span> <span class="op">=</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t605" href="#t605">605</a></span><span class="t"> <span class="nam">current_line_width</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t606" href="#t606">606</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t607" href="#t607">607</a></span><span class="t"> <span class="key">for</span> <span class="nam">word_item</span> <span class="key">in</span> <span class="nam">words</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t608" href="#t608">608</a></span><span class="t"> <span class="com"># Handle word tuples (index, word_obj)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t609" href="#t609">609</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">word_item</span><span class="op">,</span> <span class="nam">tuple</span><span class="op">)</span> <span class="key">and</span> <span class="nam">len</span><span class="op">(</span><span class="nam">word_item</span><span class="op">)</span> <span class="op">>=</span> <span class="num">2</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">609&#x202F;&#x219B;&#x202F;610</span><span class="annotate long">line 609 didn't jump to line 610 because the condition on line 609 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t610" href="#t610">610</a></span><span class="t"> <span class="nam">word_obj</span> <span class="op">=</span> <span class="nam">word_item</span><span class="op">[</span><span class="num">1</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t611" href="#t611">611</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t612" href="#t612">612</a></span><span class="t"> <span class="nam">word_obj</span> <span class="op">=</span> <span class="nam">word_item</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t613" href="#t613">613</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t614" href="#t614">614</a></span><span class="t"> <span class="com"># Extract text from the word</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t615" href="#t615">615</a></span><span class="t"> <span class="nam">word_text</span> <span class="op">=</span> <span class="nam">word_obj</span><span class="op">.</span><span class="nam">text</span> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t616" href="#t616">616</a></span><span class="t"> <span class="nam">word_obj</span><span class="op">,</span> <span class="str">'text'</span><span class="op">)</span> <span class="key">else</span> <span class="nam">str</span><span class="op">(</span><span class="nam">word_obj</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t617" href="#t617">617</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t618" href="#t618">618</a></span><span class="t"> <span class="com"># Measure word width</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t619" href="#t619">619</a></span><span class="t"> <span class="nam">word_width</span> <span class="op">=</span> <span class="nam">font</span><span class="op">.</span><span class="nam">font</span><span class="op">.</span><span class="nam">getlength</span><span class="op">(</span><span class="nam">word_text</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t620" href="#t620">620</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t621" href="#t621">621</a></span><span class="t"> <span class="com"># Check if word fits on current line</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t622" href="#t622">622</a></span><span class="t"> <span class="key">if</span> <span class="nam">current_line_width</span> <span class="op">></span> <span class="num">0</span><span class="op">:</span> <span class="com"># Not first word on line</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t623" href="#t623">623</a></span><span class="t"> <span class="nam">needed_width</span> <span class="op">=</span> <span class="nam">current_line_width</span> <span class="op">+</span> <span class="nam">word_spacing</span> <span class="op">+</span> <span class="nam">word_width</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t624" href="#t624">624</a></span><span class="t"> <span class="key">if</span> <span class="nam">needed_width</span> <span class="op">></span> <span class="nam">available_width</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">624&#x202F;&#x219B;&#x202F;626</span><span class="annotate long">line 624 didn't jump to line 626 because the condition on line 624 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t625" href="#t625">625</a></span><span class="t"> <span class="com"># Need new line</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t626" href="#t626">626</a></span><span class="t"> <span class="nam">lines</span> <span class="op">+=</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t627" href="#t627">627</a></span><span class="t"> <span class="nam">current_line_width</span> <span class="op">=</span> <span class="nam">word_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t628" href="#t628">628</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t629" href="#t629">629</a></span><span class="t"> <span class="nam">current_line_width</span> <span class="op">=</span> <span class="nam">needed_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t630" href="#t630">630</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t631" href="#t631">631</a></span><span class="t"> <span class="com"># First word on line</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t632" href="#t632">632</a></span><span class="t"> <span class="key">if</span> <span class="nam">word_width</span> <span class="op">></span> <span class="nam">available_width</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">632&#x202F;&#x219B;&#x202F;634</span><span class="annotate long">line 632 didn't jump to line 634 because the condition on line 632 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t633" href="#t633">633</a></span><span class="t"> <span class="com"># Word needs to be hyphenated, assume it takes 1 line</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t634" href="#t634">634</a></span><span class="t"> <span class="nam">lines</span> <span class="op">+=</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t635" href="#t635">635</a></span><span class="t"> <span class="nam">current_line_width</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t636" href="#t636">636</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t637" href="#t637">637</a></span><span class="t"> <span class="nam">current_line_width</span> <span class="op">=</span> <span class="nam">word_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t638" href="#t638">638</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t639" href="#t639">639</a></span><span class="t"> <span class="key">return</span> <span class="nam">lines</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t640" href="#t640">640</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t641" href="#t641">641</a></span><span class="t"> <span class="key">def</span> <span class="nam">render</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Image</span><span class="op">.</span><span class="nam">Image</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t642" href="#t642">642</a></span><span class="t"> <span class="str">"""Render the complete table."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t643" href="#t643">643</a></span><span class="t"> <span class="nam">x</span><span class="op">,</span> <span class="nam">y</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t644" href="#t644">644</a></span><span class="t"> <span class="nam">current_y</span> <span class="op">=</span> <span class="nam">y</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t645" href="#t645">645</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t646" href="#t646">646</a></span><span class="t"> <span class="com"># Render caption if present</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t647" href="#t647">647</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_table</span><span class="op">.</span><span class="nam">caption</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t648" href="#t648">648</a></span><span class="t"> <span class="nam">current_y</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_render_caption</span><span class="op">(</span><span class="nam">x</span><span class="op">,</span> <span class="nam">current_y</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t649" href="#t649">649</a></span><span class="t"> <span class="nam">current_y</span> <span class="op">+=</span> <span class="num">10</span> <span class="com"># Space after caption</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t650" href="#t650">650</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t651" href="#t651">651</a></span><span class="t"> <span class="com"># Render header rows</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t652" href="#t652">652</a></span><span class="t"> <span class="key">for</span> <span class="nam">section</span><span class="op">,</span> <span class="nam">row</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_table</span><span class="op">.</span><span class="nam">all_rows</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t653" href="#t653">653</a></span><span class="t"> <span class="key">if</span> <span class="nam">section</span> <span class="op">==</span> <span class="str">"header"</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t654" href="#t654">654</a></span><span class="t"> <span class="nam">row_height</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_row_heights</span><span class="op">[</span><span class="str">"header"</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t655" href="#t655">655</a></span><span class="t"> <span class="key">elif</span> <span class="nam">section</span> <span class="op">==</span> <span class="str">"footer"</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t656" href="#t656">656</a></span><span class="t"> <span class="nam">row_height</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_row_heights</span><span class="op">[</span><span class="str">"footer"</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t657" href="#t657">657</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t658" href="#t658">658</a></span><span class="t"> <span class="nam">row_height</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_row_heights</span><span class="op">[</span><span class="str">"body"</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t659" href="#t659">659</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t660" href="#t660">660</a></span><span class="t"> <span class="nam">is_header</span> <span class="op">=</span> <span class="op">(</span><span class="nam">section</span> <span class="op">==</span> <span class="str">"header"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t661" href="#t661">661</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t662" href="#t662">662</a></span><span class="t"> <span class="nam">row_renderer</span> <span class="op">=</span> <span class="nam">TableRowRenderer</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t663" href="#t663">663</a></span><span class="t"> <span class="nam">row</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t664" href="#t664">664</a></span><span class="t"> <span class="op">(</span><span class="nam">x</span><span class="op">,</span> <span class="nam">current_y</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t665" href="#t665">665</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_column_widths</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t666" href="#t666">666</a></span><span class="t"> <span class="nam">row_height</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t667" href="#t667">667</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t668" href="#t668">668</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t669" href="#t669">669</a></span><span class="t"> <span class="nam">is_header</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t670" href="#t670">670</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_canvas</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t671" href="#t671">671</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t672" href="#t672">672</a></span><span class="t"> <span class="nam">row_renderer</span><span class="op">.</span><span class="nam">render</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t673" href="#t673">673</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_row_renderers</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">row_renderer</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t674" href="#t674">674</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t675" href="#t675">675</a></span><span class="t"> <span class="nam">current_y</span> <span class="op">+=</span> <span class="nam">row_height</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">border_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t676" href="#t676">676</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t677" href="#t677">677</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span> <span class="com"># Table rendering is done directly on the page</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t678" href="#t678">678</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t679" href="#t679">679</a></span><span class="t"> <span class="key">def</span> <span class="nam">_render_caption</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">x</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">y</span><span class="op">:</span> <span class="nam">int</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t680" href="#t680">680</a></span><span class="t"> <span class="str">"""Render the table caption and return the new Y position."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t681" href="#t681">681</a></span><span class="t"> <span class="key">from</span> <span class="nam">PIL</span> <span class="key">import</span> <span class="nam">ImageFont</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t682" href="#t682">682</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t683" href="#t683">683</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t684" href="#t684">684</a></span><span class="t"> <span class="nam">font</span> <span class="op">=</span> <span class="nam">ImageFont</span><span class="op">.</span><span class="nam">truetype</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t685" href="#t685">685</a></span><span class="t"> <span class="str">"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"</span><span class="op">,</span> <span class="num">13</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t686" href="#t686">686</a></span><span class="t"> <span class="key">except</span> <span class="nam">BaseException</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t687" href="#t687">687</a></span><span class="t"> <span class="nam">font</span> <span class="op">=</span> <span class="nam">ImageFont</span><span class="op">.</span><span class="nam">load_default</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t688" href="#t688">688</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t689" href="#t689">689</a></span><span class="t"> <span class="com"># Center the caption</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t690" href="#t690">690</a></span><span class="t"> <span class="nam">bbox</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">textbbox</span><span class="op">(</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_table</span><span class="op">.</span><span class="nam">caption</span><span class="op">,</span> <span class="nam">font</span><span class="op">=</span><span class="nam">font</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t691" href="#t691">691</a></span><span class="t"> <span class="nam">text_width</span> <span class="op">=</span> <span class="nam">bbox</span><span class="op">[</span><span class="num">2</span><span class="op">]</span> <span class="op">-</span> <span class="nam">bbox</span><span class="op">[</span><span class="num">0</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t692" href="#t692">692</a></span><span class="t"> <span class="nam">caption_x</span> <span class="op">=</span> <span class="nam">x</span> <span class="op">+</span> <span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">-</span> <span class="nam">text_width</span><span class="op">)</span> <span class="op">//</span> <span class="num">2</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t693" href="#t693">693</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t694" href="#t694">694</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">text</span><span class="op">(</span><span class="op">(</span><span class="nam">caption_x</span><span class="op">,</span> <span class="nam">y</span><span class="op">)</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_table</span><span class="op">.</span><span class="nam">caption</span><span class="op">,</span> <span class="nam">fill</span><span class="op">=</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">,</span> <span class="nam">font</span><span class="op">=</span><span class="nam">font</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t695" href="#t695">695</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t696" href="#t696">696</a></span><span class="t"> <span class="key">return</span> <span class="nam">y</span> <span class="op">+</span> <span class="num">20</span> <span class="com"># Caption height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t697" href="#t697">697</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t698" href="#t698">698</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t699" href="#t699">699</a></span><span class="t"> <span class="key">def</span> <span class="nam">height</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t700" href="#t700">700</a></span><span class="t"> <span class="str">"""Get the total height of the rendered table."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t701" href="#t701">701</a></span><span class="t"> <span class="key">return</span> <span class="nam">int</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t702" href="#t702">702</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t703" href="#t703">703</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t704" href="#t704">704</a></span><span class="t"> <span class="key">def</span> <span class="nam">width</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t705" href="#t705">705</a></span><span class="t"> <span class="str">"""Get the total width of the rendered table."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t706" href="#t706">706</a></span><span class="t"> <span class="key">return</span> <span class="nam">int</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_7d48e1f4c6486fa2_page_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_7d48e1f4c6486fa2_text_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,846 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/concrete/text.py: 90%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/concrete/text.py</b>:
<span class="pc_cov">90%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">283 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">261<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">22<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">31<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">11<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_7d48e1f4c6486fa2_table_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_40407af872b0cf37___init___py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="run"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="key">from</span> <span class="nam">__future__</span> <span class="key">import</span> <span class="nam">annotations</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">core</span><span class="op">.</span><span class="nam">base</span> <span class="key">import</span> <span class="nam">Renderable</span><span class="op">,</span> <span class="nam">Queriable</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">core</span><span class="op">.</span><span class="nam">query</span> <span class="key">import</span> <span class="nam">QueryResult</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">box</span> <span class="key">import</span> <span class="nam">Box</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span> <span class="key">import</span> <span class="nam">Alignment</span><span class="op">,</span> <span class="nam">Font</span><span class="op">,</span> <span class="nam">TextDecoration</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span> <span class="key">import</span> <span class="nam">Word</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">inline</span> <span class="key">import</span> <span class="nam">LinkedWord</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">functional</span> <span class="key">import</span> <span class="nam">Link</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="key">from</span> <span class="nam">PIL</span> <span class="key">import</span> <span class="nam">ImageDraw</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">Tuple</span><span class="op">,</span> <span class="nam">List</span><span class="op">,</span> <span class="nam">Optional</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="key">import</span> <span class="nam">numpy</span> <span class="key">as</span> <span class="nam">np</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="key">from</span> <span class="nam">abc</span> <span class="key">import</span> <span class="nam">ABC</span><span class="op">,</span> <span class="nam">abstractmethod</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"><span class="key">class</span> <span class="nam">AlignmentHandler</span><span class="op">(</span><span class="nam">ABC</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"><span class="str"> Abstract base class for text alignment handlers.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"><span class="str"> Each handler implements a specific alignment strategy.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"> <span class="op">@</span><span class="nam">abstractmethod</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"> <span class="key">def</span> <span class="nam">calculate_spacing_and_position</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">text_objects</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="str">'Text'</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"> <span class="nam">available_width</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">min_spacing</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"> <span class="nam">max_spacing</span><span class="op">:</span> <span class="nam">int</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">bool</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"><span class="str"> Calculate the spacing between words and starting position for the line.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"><span class="str"> text_objects: List of Text objects in the line</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"><span class="str"> available_width: Total width available for the line</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"><span class="str"> min_spacing: Minimum spacing between words</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"><span class="str"> max_spacing: Maximum spacing between words</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"><span class="str"> Tuple of (spacing_between_words, starting_x_position)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"><span class="key">class</span> <span class="nam">LeftAlignmentHandler</span><span class="op">(</span><span class="nam">AlignmentHandler</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"> <span class="str">"""Handler for left-aligned text."""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t"> <span class="key">def</span> <span class="nam">calculate_spacing_and_position</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t"> <span class="nam">text_objects</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="str">'Text'</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"> <span class="nam">available_width</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t"> <span class="nam">min_spacing</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"> <span class="nam">max_spacing</span><span class="op">:</span> <span class="nam">int</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">bool</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"><span class="str"> Calculate spacing and position for left-aligned text objects.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t"><span class="str"> CREngine-inspired: never allow negative spacing, always use minimum spacing for overflow.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t"><span class="str"> text_objects (List[Text]): A list of text objects to be laid out.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"><span class="str"> available_width (int): The total width available for layout.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t"><span class="str"> min_spacing (int): Minimum spacing between text objects.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"><span class="str"> max_spacing (int): Maximum spacing between text objects.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t"><span class="str"> Tuple[int, int, bool]: Spacing, start position, and overflow flag.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"> <span class="com"># Handle single word case</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"> <span class="key">if</span> <span class="nam">len</span><span class="op">(</span><span class="nam">text_objects</span><span class="op">)</span> <span class="op">&lt;=</span> <span class="num">1</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t"> <span class="key">return</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"> <span class="com"># Calculate the total length of all text objects</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"> <span class="nam">text_length</span> <span class="op">=</span> <span class="nam">sum</span><span class="op">(</span><span class="op">[</span><span class="nam">text</span><span class="op">.</span><span class="nam">width</span> <span class="key">for</span> <span class="nam">text</span> <span class="key">in</span> <span class="nam">text_objects</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t"> <span class="com"># Calculate number of gaps between texts</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"> <span class="nam">num_gaps</span> <span class="op">=</span> <span class="nam">len</span><span class="op">(</span><span class="nam">text_objects</span><span class="op">)</span> <span class="op">-</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t"> <span class="com"># Calculate minimum space needed (text + minimum gaps)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t"> <span class="nam">min_total_width</span> <span class="op">=</span> <span class="nam">text_length</span> <span class="op">+</span> <span class="op">(</span><span class="nam">min_spacing</span> <span class="op">*</span> <span class="nam">num_gaps</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"> <span class="com"># Check if we have overflow (CREngine pattern: always use min_spacing for</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t"> <span class="com"># overflow)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"> <span class="key">if</span> <span class="nam">min_total_width</span> <span class="op">></span> <span class="nam">available_width</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t"> <span class="key">return</span> <span class="nam">min_spacing</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="key">True</span> <span class="com"># Overflow - but use safe minimum spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"> <span class="com"># Calculate residual space left after accounting for text lengths</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t"> <span class="nam">residual_space</span> <span class="op">=</span> <span class="nam">available_width</span> <span class="op">-</span> <span class="nam">text_length</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t"> <span class="com"># Calculate ideal spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t"> <span class="nam">actual_spacing</span> <span class="op">=</span> <span class="nam">residual_space</span> <span class="op">//</span> <span class="nam">num_gaps</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t"> <span class="com"># Clamp within bounds (CREngine pattern: respect max_spacing)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"> <span class="key">if</span> <span class="nam">actual_spacing</span> <span class="op">></span> <span class="nam">max_spacing</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t"> <span class="key">return</span> <span class="nam">max_spacing</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t"> <span class="key">elif</span> <span class="nam">actual_spacing</span> <span class="op">&lt;</span> <span class="nam">min_spacing</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">86&#x202F;&#x219B;&#x202F;88</span><span class="annotate long">line 86 didn't jump to line 88 because the condition on line 86 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t"> <span class="com"># Ensure we never return spacing less than min_spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t"> <span class="key">return</span> <span class="nam">min_spacing</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t"> <span class="key">return</span> <span class="nam">actual_spacing</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="key">False</span> <span class="com"># Use calculated spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t"><span class="key">class</span> <span class="nam">CenterRightAlignmentHandler</span><span class="op">(</span><span class="nam">AlignmentHandler</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t"> <span class="str">"""Handler for center and right-aligned text."""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">alignment</span><span class="op">:</span> <span class="nam">Alignment</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_alignment</span> <span class="op">=</span> <span class="nam">alignment</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"> <span class="key">def</span> <span class="nam">calculate_spacing_and_position</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">text_objects</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="str">'Text'</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t"> <span class="nam">available_width</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">min_spacing</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"> <span class="nam">max_spacing</span><span class="op">:</span> <span class="nam">int</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">bool</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"> <span class="str">"""Center/right alignment uses minimum spacing with calculated start position."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t"> <span class="nam">word_length</span> <span class="op">=</span> <span class="nam">sum</span><span class="op">(</span><span class="op">[</span><span class="nam">word</span><span class="op">.</span><span class="nam">width</span> <span class="key">for</span> <span class="nam">word</span> <span class="key">in</span> <span class="nam">text_objects</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t"> <span class="nam">residual_space</span> <span class="op">=</span> <span class="nam">available_width</span> <span class="op">-</span> <span class="nam">word_length</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t"> <span class="com"># Handle single word case</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t"> <span class="key">if</span> <span class="nam">len</span><span class="op">(</span><span class="nam">text_objects</span><span class="op">)</span> <span class="op">&lt;=</span> <span class="num">1</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_alignment</span> <span class="op">==</span> <span class="nam">Alignment</span><span class="op">.</span><span class="nam">CENTER</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t"> <span class="nam">start_position</span> <span class="op">=</span> <span class="op">(</span><span class="nam">available_width</span> <span class="op">-</span> <span class="nam">word_length</span><span class="op">)</span> <span class="op">//</span> <span class="num">2</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"> <span class="key">else</span><span class="op">:</span> <span class="com"># RIGHT</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t"> <span class="nam">start_position</span> <span class="op">=</span> <span class="nam">available_width</span> <span class="op">-</span> <span class="nam">word_length</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"> <span class="key">return</span> <span class="num">0</span><span class="op">,</span> <span class="nam">max</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="nam">start_position</span><span class="op">)</span><span class="op">,</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t"> <span class="nam">actual_spacing</span> <span class="op">=</span> <span class="nam">residual_space</span> <span class="op">//</span> <span class="op">(</span><span class="nam">len</span><span class="op">(</span><span class="nam">text_objects</span><span class="op">)</span> <span class="op">-</span> <span class="num">1</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t"> <span class="nam">ideal_space</span> <span class="op">=</span> <span class="op">(</span><span class="nam">min_spacing</span> <span class="op">+</span> <span class="nam">max_spacing</span><span class="op">)</span> <span class="op">/</span> <span class="num">2</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"> <span class="key">if</span> <span class="nam">actual_spacing</span> <span class="op">></span> <span class="num">0.5</span> <span class="op">*</span> <span class="op">(</span><span class="nam">min_spacing</span> <span class="op">+</span> <span class="nam">max_spacing</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t"> <span class="nam">actual_spacing</span> <span class="op">=</span> <span class="num">0.5</span> <span class="op">*</span> <span class="op">(</span><span class="nam">min_spacing</span> <span class="op">+</span> <span class="nam">max_spacing</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"> <span class="nam">content_length</span> <span class="op">=</span> <span class="nam">word_length</span> <span class="op">+</span> <span class="op">(</span><span class="nam">len</span><span class="op">(</span><span class="nam">text_objects</span><span class="op">)</span> <span class="op">-</span> <span class="num">1</span><span class="op">)</span> <span class="op">*</span> <span class="nam">actual_spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_alignment</span> <span class="op">==</span> <span class="nam">Alignment</span><span class="op">.</span><span class="nam">CENTER</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t"> <span class="nam">start_position</span> <span class="op">=</span> <span class="op">(</span><span class="nam">available_width</span> <span class="op">-</span> <span class="nam">content_length</span><span class="op">)</span> <span class="op">//</span> <span class="num">2</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"> <span class="nam">start_position</span> <span class="op">=</span> <span class="nam">available_width</span> <span class="op">-</span> <span class="nam">content_length</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t"> <span class="key">if</span> <span class="nam">actual_spacing</span> <span class="op">&lt;</span> <span class="nam">min_spacing</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t"> <span class="key">return</span> <span class="nam">actual_spacing</span><span class="op">,</span> <span class="nam">max</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="nam">start_position</span><span class="op">)</span><span class="op">,</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t"> <span class="key">return</span> <span class="nam">ideal_space</span><span class="op">,</span> <span class="nam">max</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="nam">start_position</span><span class="op">)</span><span class="op">,</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t"><span class="key">class</span> <span class="nam">JustifyAlignmentHandler</span><span class="op">(</span><span class="nam">AlignmentHandler</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t"> <span class="str">"""Handler for justified text with full justification."""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t"> <span class="com"># Store variable spacing for each gap to distribute remainder pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_gap_spacings</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"> <span class="key">def</span> <span class="nam">calculate_spacing_and_position</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">text_objects</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="str">'Text'</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t"> <span class="nam">available_width</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">min_spacing</span><span class="op">:</span> <span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t"> <span class="nam">max_spacing</span><span class="op">:</span> <span class="nam">int</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">bool</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t"><span class="str"> Justified alignment distributes space to fill the entire line width.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"><span class="str"> For justified text, we ALWAYS try to fill the entire width by distributing</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t"><span class="str"> space between words, regardless of max_spacing constraints. The only limit</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t"><span class="str"> is min_spacing to ensure readability.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t"> <span class="nam">word_length</span> <span class="op">=</span> <span class="nam">sum</span><span class="op">(</span><span class="op">[</span><span class="nam">word</span><span class="op">.</span><span class="nam">width</span> <span class="key">for</span> <span class="nam">word</span> <span class="key">in</span> <span class="nam">text_objects</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t"> <span class="nam">residual_space</span> <span class="op">=</span> <span class="nam">available_width</span> <span class="op">-</span> <span class="nam">word_length</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t"> <span class="nam">num_gaps</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="num">1</span><span class="op">,</span> <span class="nam">len</span><span class="op">(</span><span class="nam">text_objects</span><span class="op">)</span> <span class="op">-</span> <span class="num">1</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t"> <span class="com"># For justified text, calculate the actual spacing needed to fill the line</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t"> <span class="nam">base_spacing</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">residual_space</span> <span class="op">//</span> <span class="nam">num_gaps</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t"> <span class="nam">remainder</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">residual_space</span> <span class="op">%</span> <span class="nam">num_gaps</span><span class="op">)</span> <span class="com"># The extra pixels to distribute</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t"> <span class="com"># Check if we have enough space for minimum spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t"> <span class="key">if</span> <span class="nam">base_spacing</span> <span class="op">&lt;</span> <span class="nam">min_spacing</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">158&#x202F;&#x219B;&#x202F;160</span><span class="annotate long">line 158 didn't jump to line 160 because the condition on line 158 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t"> <span class="com"># Not enough space - this is overflow</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_gap_spacings</span> <span class="op">=</span> <span class="op">[</span><span class="nam">min_spacing</span><span class="op">]</span> <span class="op">*</span> <span class="nam">num_gaps</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t"> <span class="key">return</span> <span class="nam">min_spacing</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="key">True</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"> <span class="com"># Distribute remainder pixels across the first 'remainder' gaps</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t"> <span class="com"># This ensures the line fills the entire width exactly</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_gap_spacings</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"> <span class="key">for</span> <span class="nam">i</span> <span class="key">in</span> <span class="nam">range</span><span class="op">(</span><span class="nam">num_gaps</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t"> <span class="key">if</span> <span class="nam">i</span> <span class="op">&lt;</span> <span class="nam">remainder</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">167&#x202F;&#x219B;&#x202F;168</span><span class="annotate long">line 167 didn't jump to line 168 because the condition on line 167 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_gap_spacings</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">base_spacing</span> <span class="op">+</span> <span class="num">1</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_gap_spacings</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">base_spacing</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t"> <span class="key">return</span> <span class="nam">base_spacing</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t"><span class="key">class</span> <span class="nam">Text</span><span class="op">(</span><span class="nam">Renderable</span><span class="op">,</span> <span class="nam">Queriable</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t"><span class="str"> Concrete implementation for rendering text.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t"><span class="str"> This class handles the visual representation of text fragments.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t"> <span class="nam">text</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t"> <span class="nam">style</span><span class="op">:</span> <span class="nam">Font</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t"> <span class="nam">draw</span><span class="op">:</span> <span class="nam">ImageDraw</span><span class="op">.</span><span class="nam">Draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t"> <span class="nam">source</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Word</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t"> <span class="nam">line</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Line</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t"><span class="str"> Initialize a Text object.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t"><span class="str"> text: The text content to render</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t"><span class="str"> style: The font style to use for rendering</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_text</span> <span class="op">=</span> <span class="nam">text</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span> <span class="op">=</span> <span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_line</span> <span class="op">=</span> <span class="nam">line</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_source</span> <span class="op">=</span> <span class="nam">source</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="op">[</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span> <span class="op">=</span> <span class="nam">draw</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t"> <span class="com"># Calculate dimensions</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_calculate_dimensions</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t"> <span class="key">def</span> <span class="nam">_calculate_dimensions</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t"> <span class="str">"""Calculate the width and height of the text based on the font metrics"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"> <span class="com"># Get the size using PIL's text size functionality</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t"> <span class="nam">font</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">font</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_width</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">textlength</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_text</span><span class="op">,</span> <span class="nam">font</span><span class="op">=</span><span class="nam">font</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t"> <span class="nam">ascent</span><span class="op">,</span> <span class="nam">descent</span> <span class="op">=</span> <span class="nam">font</span><span class="op">.</span><span class="nam">getmetrics</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_ascent</span> <span class="op">=</span> <span class="nam">ascent</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_middle_y</span> <span class="op">=</span> <span class="nam">ascent</span> <span class="op">-</span> <span class="nam">descent</span> <span class="op">/</span> <span class="num">2</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t"> <span class="op">@</span><span class="nam">classmethod</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t"> <span class="key">def</span> <span class="nam">from_word</span><span class="op">(</span><span class="nam">cls</span><span class="op">,</span> <span class="nam">word</span><span class="op">:</span> <span class="nam">Word</span><span class="op">,</span> <span class="nam">draw</span><span class="op">:</span> <span class="nam">ImageDraw</span><span class="op">.</span><span class="nam">Draw</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t"> <span class="key">return</span> <span class="nam">cls</span><span class="op">(</span><span class="nam">word</span><span class="op">.</span><span class="nam">text</span><span class="op">,</span> <span class="nam">word</span><span class="op">.</span><span class="nam">style</span><span class="op">,</span> <span class="nam">draw</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t"> <span class="key">def</span> <span class="nam">text</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">str</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t"> <span class="str">"""Get the text content"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_text</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t"> <span class="key">def</span> <span class="nam">style</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Font</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t"> <span class="str">"""Get the text style"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t"> <span class="key">def</span> <span class="nam">origin</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">np</span><span class="op">.</span><span class="nam">ndarray</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t"> <span class="str">"""Get the origin of the text"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t"> <span class="key">def</span> <span class="nam">line</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Line</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t"> <span class="str">"""Get the line containing this text"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_line</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t"> <span class="op">@</span><span class="nam">line</span><span class="op">.</span><span class="nam">setter</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t"> <span class="key">def</span> <span class="nam">line</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">line</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t"> <span class="str">"""Set the line containing this text"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_line</span> <span class="op">=</span> <span class="nam">line</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t"> <span class="key">def</span> <span class="nam">width</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t"> <span class="str">"""Get the width of the text"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t"> <span class="key">def</span> <span class="nam">size</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t"> <span class="str">"""Get the width and height of the text"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t"> <span class="com"># Return actual rendered height (ascent + descent) not just font_size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t"> <span class="nam">ascent</span><span class="op">,</span> <span class="nam">descent</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">font</span><span class="op">.</span><span class="nam">getmetrics</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t"> <span class="nam">actual_height</span> <span class="op">=</span> <span class="nam">ascent</span> <span class="op">+</span> <span class="nam">descent</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t"> <span class="key">return</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_width</span><span class="op">,</span> <span class="nam">actual_height</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_origin</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">origin</span><span class="op">:</span> <span class="nam">np</span><span class="op">.</span><span class="nam">generic</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t"> <span class="str">"""Set the origin (left baseline ("ls")) of this text element"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span> <span class="op">=</span> <span class="nam">origin</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t"> <span class="key">def</span> <span class="nam">add_line</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">line</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t"> <span class="str">"""Add this text to a line"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_line</span> <span class="op">=</span> <span class="nam">line</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t"> <span class="key">def</span> <span class="nam">in_object</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">point</span><span class="op">:</span> <span class="nam">np</span><span class="op">.</span><span class="nam">generic</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t"><span class="str"> Check if a point is in the text object.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t"><span class="str"> Override Queriable.in_object() because Text uses baseline-anchored positioning.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t"><span class="str"> The origin is at the baseline (anchor="ls"), not the top-left corner.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t"><span class="str"> point: The coordinates to check</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t"><span class="str"> True if the point is within the text bounds</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t"> <span class="nam">point_array</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="nam">point</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t279" href="#t279">279</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t280" href="#t280">280</a></span><span class="t"> <span class="com"># Text origin is at baseline, so visual top is origin[1] - ascent</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t281" href="#t281">281</a></span><span class="t"> <span class="nam">visual_top</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">-</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_ascent</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t282" href="#t282">282</a></span><span class="t"> <span class="nam">visual_bottom</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">+</span> <span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">-</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_ascent</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t283" href="#t283">283</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t284" href="#t284">284</a></span><span class="t"> <span class="com"># Check if point is within bounds</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t285" href="#t285">285</a></span><span class="t"> <span class="com"># X: origin[0] to origin[0] + width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t286" href="#t286">286</a></span><span class="t"> <span class="com"># Y: visual_top to visual_bottom</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t287" href="#t287">287</a></span><span class="t"> <span class="key">return</span> <span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">&lt;=</span> <span class="nam">point_array</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">&lt;</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="key">and</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t288" href="#t288">288</a></span><span class="t"> <span class="nam">visual_top</span> <span class="op">&lt;=</span> <span class="nam">point_array</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">&lt;</span> <span class="nam">visual_bottom</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t289" href="#t289">289</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t290" href="#t290">290</a></span><span class="t"> <span class="key">def</span> <span class="nam">_apply_decoration</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">next_text</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="str">'Text'</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span> <span class="nam">spacing</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">0</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t291" href="#t291">291</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t292" href="#t292">292</a></span><span class="t"><span class="str"> Apply text decoration (underline or strikethrough).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t293" href="#t293">293</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t294" href="#t294">294</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t295" href="#t295">295</a></span><span class="t"><span class="str"> next_text: The next Text object in the line (if any)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t296" href="#t296">296</a></span><span class="t"><span class="str"> spacing: The spacing to the next text object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t297" href="#t297">297</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t298" href="#t298">298</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">decoration</span> <span class="op">==</span> <span class="nam">TextDecoration</span><span class="op">.</span><span class="nam">UNDERLINE</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t299" href="#t299">299</a></span><span class="t"> <span class="com"># Draw underline at about 90% of the height</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t300" href="#t300">300</a></span><span class="t"> <span class="nam">y_position</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">-</span> <span class="num">0.1</span> <span class="op">*</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">font_size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t301" href="#t301">301</a></span><span class="t"> <span class="nam">line_width</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="num">1</span><span class="op">,</span> <span class="nam">int</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">font_size</span> <span class="op">/</span> <span class="num">15</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t302" href="#t302">302</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t303" href="#t303">303</a></span><span class="t"> <span class="com"># Determine end x-coordinate</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t304" href="#t304">304</a></span><span class="t"> <span class="nam">end_x</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t305" href="#t305">305</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t306" href="#t306">306</a></span><span class="t"> <span class="com"># If next text also has underline decoration, extend to connect them</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t307" href="#t307">307</a></span><span class="t"> <span class="key">if</span> <span class="op">(</span><span class="nam">next_text</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span> <span class="key">and</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t308" href="#t308">308</a></span><span class="t"> <span class="nam">next_text</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">decoration</span> <span class="op">==</span> <span class="nam">TextDecoration</span><span class="op">.</span><span class="nam">UNDERLINE</span> <span class="key">and</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t309" href="#t309">309</a></span><span class="t"> <span class="nam">next_text</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">colour</span> <span class="op">==</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">colour</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t310" href="#t310">310</a></span><span class="t"> <span class="com"># Extend the underline through the spacing to connect with next word</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t311" href="#t311">311</a></span><span class="t"> <span class="nam">end_x</span> <span class="op">+=</span> <span class="nam">spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t312" href="#t312">312</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t313" href="#t313">313</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">line</span><span class="op">(</span><span class="op">[</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">,</span> <span class="nam">y_position</span><span class="op">)</span><span class="op">,</span> <span class="op">(</span><span class="nam">end_x</span><span class="op">,</span> <span class="nam">y_position</span><span class="op">)</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t314" href="#t314">314</a></span><span class="t"> <span class="nam">fill</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">colour</span><span class="op">,</span> <span class="nam">width</span><span class="op">=</span><span class="nam">line_width</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t315" href="#t315">315</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t316" href="#t316">316</a></span><span class="t"> <span class="key">elif</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">decoration</span> <span class="op">==</span> <span class="nam">TextDecoration</span><span class="op">.</span><span class="nam">STRIKETHROUGH</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">316&#x202F;&#x219B;&#x202F;318</span><span class="annotate long">line 316 didn't jump to line 318 because the condition on line 316 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t317" href="#t317">317</a></span><span class="t"> <span class="com"># Draw strikethrough at about 50% of the height</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t318" href="#t318">318</a></span><span class="t"> <span class="nam">y_position</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_middle_y</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t319" href="#t319">319</a></span><span class="t"> <span class="nam">line_width</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="num">1</span><span class="op">,</span> <span class="nam">int</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">font_size</span> <span class="op">/</span> <span class="num">15</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t320" href="#t320">320</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t321" href="#t321">321</a></span><span class="t"> <span class="com"># Determine end x-coordinate</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t322" href="#t322">322</a></span><span class="t"> <span class="nam">end_x</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t323" href="#t323">323</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t324" href="#t324">324</a></span><span class="t"> <span class="com"># If next text also has strikethrough decoration, extend to connect them</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t325" href="#t325">325</a></span><span class="t"> <span class="key">if</span> <span class="op">(</span><span class="nam">next_text</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span> <span class="key">and</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t326" href="#t326">326</a></span><span class="t"> <span class="nam">next_text</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">decoration</span> <span class="op">==</span> <span class="nam">TextDecoration</span><span class="op">.</span><span class="nam">STRIKETHROUGH</span> <span class="key">and</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t327" href="#t327">327</a></span><span class="t"> <span class="nam">next_text</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">colour</span> <span class="op">==</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">colour</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t328" href="#t328">328</a></span><span class="t"> <span class="com"># Extend the strikethrough through the spacing to connect with next word</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t329" href="#t329">329</a></span><span class="t"> <span class="nam">end_x</span> <span class="op">+=</span> <span class="nam">spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t330" href="#t330">330</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t331" href="#t331">331</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">line</span><span class="op">(</span><span class="op">[</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">,</span> <span class="nam">y_position</span><span class="op">)</span><span class="op">,</span> <span class="op">(</span><span class="nam">end_x</span><span class="op">,</span> <span class="nam">y_position</span><span class="op">)</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t332" href="#t332">332</a></span><span class="t"> <span class="nam">fill</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">colour</span><span class="op">,</span> <span class="nam">width</span><span class="op">=</span><span class="nam">line_width</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t333" href="#t333">333</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t334" href="#t334">334</a></span><span class="t"> <span class="key">def</span> <span class="nam">render</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">next_text</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="str">'Text'</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span> <span class="nam">spacing</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">0</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t335" href="#t335">335</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t336" href="#t336">336</a></span><span class="t"><span class="str"> Render the text to an image.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t337" href="#t337">337</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t338" href="#t338">338</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t339" href="#t339">339</a></span><span class="t"><span class="str"> next_text: The next Text object in the line (if any)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t340" href="#t340">340</a></span><span class="t"><span class="str"> spacing: The spacing to the next text object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t341" href="#t341">341</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t342" href="#t342">342</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t343" href="#t343">343</a></span><span class="t"><span class="str"> A PIL Image containing the rendered text</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t344" href="#t344">344</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t345" href="#t345">345</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t346" href="#t346">346</a></span><span class="t"> <span class="com"># Draw the text background if specified</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t347" href="#t347">347</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">background</span> <span class="key">and</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">background</span><span class="op">[</span><span class="num">3</span><span class="op">]</span> <span class="op">></span> <span class="num">0</span><span class="op">:</span> <span class="com"># If alpha > 0</span>&nbsp;</span><span class="r"><span class="annotate short">347&#x202F;&#x219B;&#x202F;348</span><span class="annotate long">line 347 didn't jump to line 348 because the condition on line 347 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t348" href="#t348">348</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">rectangle</span><span class="op">(</span><span class="op">[</span><span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span> <span class="op">+</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t349" href="#t349">349</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">]</span><span class="op">,</span> <span class="nam">fill</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">background</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t350" href="#t350">350</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t351" href="#t351">351</a></span><span class="t"> <span class="com"># Draw the text using baseline as anchor point ("ls" = left-baseline)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t352" href="#t352">352</a></span><span class="t"> <span class="com"># This ensures the origin represents the baseline, not the top-left</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t353" href="#t353">353</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">.</span><span class="nam">text</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t354" href="#t354">354</a></span><span class="t"> <span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">origin</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t355" href="#t355">355</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">1</span><span class="op">]</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t356" href="#t356">356</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_text</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t357" href="#t357">357</a></span><span class="t"> <span class="nam">font</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">font</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t358" href="#t358">358</a></span><span class="t"> <span class="nam">fill</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">colour</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t359" href="#t359">359</a></span><span class="t"> <span class="nam">anchor</span><span class="op">=</span><span class="str">"ls"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t360" href="#t360">360</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t361" href="#t361">361</a></span><span class="t"> <span class="com"># Apply any text decorations with knowledge of next text</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t362" href="#t362">362</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_apply_decoration</span><span class="op">(</span><span class="nam">next_text</span><span class="op">,</span> <span class="nam">spacing</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t363" href="#t363">363</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t364" href="#t364">364</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t365" href="#t365">365</a></span><span class="t"><span class="key">class</span> <span class="nam">Line</span><span class="op">(</span><span class="nam">Box</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t366" href="#t366">366</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t367" href="#t367">367</a></span><span class="t"><span class="str"> A line of text consisting of Text objects with consistent spacing.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t368" href="#t368">368</a></span><span class="t"><span class="str"> Each Text represents a word or word fragment that can be rendered.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t369" href="#t369">369</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t370" href="#t370">370</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t371" href="#t371">371</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t372" href="#t372">372</a></span><span class="t"> <span class="nam">spacing</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t373" href="#t373">373</a></span><span class="t"> <span class="nam">int</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t374" href="#t374">374</a></span><span class="t"> <span class="nam">origin</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t375" href="#t375">375</a></span><span class="t"> <span class="nam">size</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t376" href="#t376">376</a></span><span class="t"> <span class="nam">draw</span><span class="op">:</span> <span class="nam">ImageDraw</span><span class="op">.</span><span class="nam">Draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t377" href="#t377">377</a></span><span class="t"> <span class="nam">font</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Font</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t378" href="#t378">378</a></span><span class="t"> <span class="nam">callback</span><span class="op">=</span><span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t379" href="#t379">379</a></span><span class="t"> <span class="nam">sheet</span><span class="op">=</span><span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t380" href="#t380">380</a></span><span class="t"> <span class="nam">mode</span><span class="op">=</span><span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t381" href="#t381">381</a></span><span class="t"> <span class="nam">halign</span><span class="op">=</span><span class="nam">Alignment</span><span class="op">.</span><span class="nam">CENTER</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t382" href="#t382">382</a></span><span class="t"> <span class="nam">valign</span><span class="op">=</span><span class="nam">Alignment</span><span class="op">.</span><span class="nam">CENTER</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t383" href="#t383">383</a></span><span class="t"> <span class="nam">previous</span><span class="op">=</span><span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t384" href="#t384">384</a></span><span class="t"> <span class="nam">min_word_length_for_brute_force</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">8</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t385" href="#t385">385</a></span><span class="t"> <span class="nam">min_chars_before_hyphen</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">2</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t386" href="#t386">386</a></span><span class="t"> <span class="nam">min_chars_after_hyphen</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">2</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t387" href="#t387">387</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t388" href="#t388">388</a></span><span class="t"><span class="str"> Initialize a new line.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t389" href="#t389">389</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t390" href="#t390">390</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t391" href="#t391">391</a></span><span class="t"><span class="str"> spacing: A tuple of (min_spacing, max_spacing) between words</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t392" href="#t392">392</a></span><span class="t"><span class="str"> origin: The top-left position of the line</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t393" href="#t393">393</a></span><span class="t"><span class="str"> size: The width and height of the line</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t394" href="#t394">394</a></span><span class="t"><span class="str"> font: The default font to use for text in this line</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t395" href="#t395">395</a></span><span class="t"><span class="str"> callback: Optional callback function</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t396" href="#t396">396</a></span><span class="t"><span class="str"> sheet: Optional image sheet</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t397" href="#t397">397</a></span><span class="t"><span class="str"> mode: Optional image mode</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t398" href="#t398">398</a></span><span class="t"><span class="str"> halign: Horizontal alignment of text within the line</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t399" href="#t399">399</a></span><span class="t"><span class="str"> valign: Vertical alignment of text within the line</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t400" href="#t400">400</a></span><span class="t"><span class="str"> previous: Reference to the previous line</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t401" href="#t401">401</a></span><span class="t"><span class="str"> min_word_length_for_brute_force: Minimum word length to attempt brute force hyphenation (default: 8)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t402" href="#t402">402</a></span><span class="t"><span class="str"> min_chars_before_hyphen: Minimum characters before hyphen in any split (default: 2)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t403" href="#t403">403</a></span><span class="t"><span class="str"> min_chars_after_hyphen: Minimum characters after hyphen in any split (default: 2)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t404" href="#t404">404</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t405" href="#t405">405</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="nam">origin</span><span class="op">,</span> <span class="nam">size</span><span class="op">,</span> <span class="nam">callback</span><span class="op">,</span> <span class="nam">sheet</span><span class="op">,</span> <span class="nam">mode</span><span class="op">,</span> <span class="nam">halign</span><span class="op">,</span> <span class="nam">valign</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t406" href="#t406">406</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="str">'Text'</span><span class="op">]</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span> <span class="com"># Store Text objects directly</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t407" href="#t407">407</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_spacing</span> <span class="op">=</span> <span class="nam">spacing</span> <span class="com"># (min_spacing, max_spacing)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t408" href="#t408">408</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_font</span> <span class="op">=</span> <span class="nam">font</span> <span class="key">if</span> <span class="nam">font</span> <span class="key">else</span> <span class="nam">Font</span><span class="op">(</span><span class="op">)</span> <span class="com"># Use default font if none provided</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t409" href="#t409">409</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_current_width</span> <span class="op">=</span> <span class="num">0</span> <span class="com"># Track the current width used</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t410" href="#t410">410</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_words</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="str">'Word'</span><span class="op">]</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t411" href="#t411">411</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_previous</span> <span class="op">=</span> <span class="nam">previous</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t412" href="#t412">412</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_next</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t413" href="#t413">413</a></span><span class="t"> <span class="nam">ascent</span><span class="op">,</span> <span class="nam">descent</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_font</span><span class="op">.</span><span class="nam">font</span><span class="op">.</span><span class="nam">getmetrics</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t414" href="#t414">414</a></span><span class="t"> <span class="com"># Store baseline as offset from line origin (top), not absolute position</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t415" href="#t415">415</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_baseline</span> <span class="op">=</span> <span class="nam">ascent</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t416" href="#t416">416</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span> <span class="op">=</span> <span class="nam">draw</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t417" href="#t417">417</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_spacing_render</span> <span class="op">=</span> <span class="op">(</span><span class="nam">spacing</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">+</span> <span class="nam">spacing</span><span class="op">[</span><span class="num">1</span><span class="op">]</span><span class="op">)</span> <span class="op">//</span> <span class="num">2</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t418" href="#t418">418</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_position_render</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t419" href="#t419">419</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t420" href="#t420">420</a></span><span class="t"> <span class="com"># Hyphenation configuration parameters</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t421" href="#t421">421</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_min_word_length_for_brute_force</span> <span class="op">=</span> <span class="nam">min_word_length_for_brute_force</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t422" href="#t422">422</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_min_chars_before_hyphen</span> <span class="op">=</span> <span class="nam">min_chars_before_hyphen</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t423" href="#t423">423</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_min_chars_after_hyphen</span> <span class="op">=</span> <span class="nam">min_chars_after_hyphen</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t424" href="#t424">424</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t425" href="#t425">425</a></span><span class="t"> <span class="com"># Create the appropriate alignment handler</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t426" href="#t426">426</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_alignment_handler</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_create_alignment_handler</span><span class="op">(</span><span class="nam">halign</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t427" href="#t427">427</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t428" href="#t428">428</a></span><span class="t"> <span class="key">def</span> <span class="nam">_create_alignment_handler</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">alignment</span><span class="op">:</span> <span class="nam">Alignment</span><span class="op">)</span> <span class="op">-></span> <span class="nam">AlignmentHandler</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t429" href="#t429">429</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t430" href="#t430">430</a></span><span class="t"><span class="str"> Create the appropriate alignment handler based on the alignment type.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t431" href="#t431">431</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t432" href="#t432">432</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t433" href="#t433">433</a></span><span class="t"><span class="str"> alignment: The alignment type</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t434" href="#t434">434</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t435" href="#t435">435</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t436" href="#t436">436</a></span><span class="t"><span class="str"> The appropriate alignment handler instance</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t437" href="#t437">437</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t438" href="#t438">438</a></span><span class="t"> <span class="key">if</span> <span class="nam">alignment</span> <span class="op">==</span> <span class="nam">Alignment</span><span class="op">.</span><span class="nam">LEFT</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t439" href="#t439">439</a></span><span class="t"> <span class="key">return</span> <span class="nam">LeftAlignmentHandler</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t440" href="#t440">440</a></span><span class="t"> <span class="key">elif</span> <span class="nam">alignment</span> <span class="op">==</span> <span class="nam">Alignment</span><span class="op">.</span><span class="nam">JUSTIFY</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t441" href="#t441">441</a></span><span class="t"> <span class="key">return</span> <span class="nam">JustifyAlignmentHandler</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t442" href="#t442">442</a></span><span class="t"> <span class="key">else</span><span class="op">:</span> <span class="com"># CENTER or RIGHT</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t443" href="#t443">443</a></span><span class="t"> <span class="key">return</span> <span class="nam">CenterRightAlignmentHandler</span><span class="op">(</span><span class="nam">alignment</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t444" href="#t444">444</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t445" href="#t445">445</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t446" href="#t446">446</a></span><span class="t"> <span class="key">def</span> <span class="nam">text_objects</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">Text</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t447" href="#t447">447</a></span><span class="t"> <span class="str">"""Get the list of Text objects in this line"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t448" href="#t448">448</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t449" href="#t449">449</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t450" href="#t450">450</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_next</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">line</span><span class="op">:</span> <span class="nam">Line</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t451" href="#t451">451</a></span><span class="t"> <span class="str">"""Set the next line in sequence"""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t452" href="#t452">452</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_next</span> <span class="op">=</span> <span class="nam">line</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t453" href="#t453">453</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t454" href="#t454">454</a></span><span class="t"> <span class="key">def</span> <span class="nam">add_word</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t455" href="#t455">455</a></span><span class="t"> <span class="nam">word</span><span class="op">:</span> <span class="str">'Word'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t456" href="#t456">456</a></span><span class="t"> <span class="nam">part</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Text</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">bool</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t457" href="#t457">457</a></span><span class="t"> <span class="nam">Optional</span><span class="op">[</span><span class="str">'Text'</span><span class="op">]</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t458" href="#t458">458</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t459" href="#t459">459</a></span><span class="t"><span class="str"> Add a word to this line using intelligent word fitting strategies.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t460" href="#t460">460</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t461" href="#t461">461</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t462" href="#t462">462</a></span><span class="t"><span class="str"> word: The word to add to the line</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t463" href="#t463">463</a></span><span class="t"><span class="str"> part: Optional pretext from a previous hyphenated word</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t464" href="#t464">464</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t465" href="#t465">465</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t466" href="#t466">466</a></span><span class="t"><span class="str"> Tuple of (success, overflow_text):</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t467" href="#t467">467</a></span><span class="t"><span class="str"> - success: True if word/part was added, False if it couldn't fit</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t468" href="#t468">468</a></span><span class="t"><span class="str"> - overflow_text: Remaining text if word was hyphenated, None otherwise</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t469" href="#t469">469</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t470" href="#t470">470</a></span><span class="t"> <span class="com"># First, add any pretext from previous hyphenation</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t471" href="#t471">471</a></span><span class="t"> <span class="key">if</span> <span class="nam">part</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t472" href="#t472">472</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">part</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t473" href="#t473">473</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_words</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">word</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t474" href="#t474">474</a></span><span class="t"> <span class="nam">part</span><span class="op">.</span><span class="nam">add_line</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t475" href="#t475">475</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t476" href="#t476">476</a></span><span class="t"> <span class="com"># Try to add the full word - create LinkText for LinkedWord, regular Text</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t477" href="#t477">477</a></span><span class="t"> <span class="com"># otherwise</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t478" href="#t478">478</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">word</span><span class="op">,</span> <span class="nam">LinkedWord</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t479" href="#t479">479</a></span><span class="t"> <span class="com"># Import here to avoid circular dependency</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t480" href="#t480">480</a></span><span class="t"> <span class="key">from</span> <span class="op">.</span><span class="nam">functional</span> <span class="key">import</span> <span class="nam">LinkText</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t481" href="#t481">481</a></span><span class="t"> <span class="com"># Create a LinkText which includes the link functionality</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t482" href="#t482">482</a></span><span class="t"> <span class="com"># LinkText constructor needs: (link, text, font, draw, source, line)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t483" href="#t483">483</a></span><span class="t"> <span class="com"># But LinkedWord itself contains the link properties</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t484" href="#t484">484</a></span><span class="t"> <span class="com"># We'll create a Link object from the LinkedWord properties</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t485" href="#t485">485</a></span><span class="t"> <span class="nam">link</span> <span class="op">=</span> <span class="nam">Link</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t486" href="#t486">486</a></span><span class="t"> <span class="nam">location</span><span class="op">=</span><span class="nam">word</span><span class="op">.</span><span class="nam">location</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t487" href="#t487">487</a></span><span class="t"> <span class="nam">link_type</span><span class="op">=</span><span class="nam">word</span><span class="op">.</span><span class="nam">link_type</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t488" href="#t488">488</a></span><span class="t"> <span class="nam">callback</span><span class="op">=</span><span class="nam">word</span><span class="op">.</span><span class="nam">link_callback</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t489" href="#t489">489</a></span><span class="t"> <span class="nam">params</span><span class="op">=</span><span class="nam">word</span><span class="op">.</span><span class="nam">params</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t490" href="#t490">490</a></span><span class="t"> <span class="nam">title</span><span class="op">=</span><span class="nam">word</span><span class="op">.</span><span class="nam">link_title</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t491" href="#t491">491</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t492" href="#t492">492</a></span><span class="t"> <span class="nam">text</span> <span class="op">=</span> <span class="nam">LinkText</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t493" href="#t493">493</a></span><span class="t"> <span class="nam">link</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t494" href="#t494">494</a></span><span class="t"> <span class="nam">word</span><span class="op">.</span><span class="nam">text</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t495" href="#t495">495</a></span><span class="t"> <span class="nam">word</span><span class="op">.</span><span class="nam">style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t496" href="#t496">496</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t497" href="#t497">497</a></span><span class="t"> <span class="nam">source</span><span class="op">=</span><span class="nam">word</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t498" href="#t498">498</a></span><span class="t"> <span class="nam">line</span><span class="op">=</span><span class="nam">self</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t499" href="#t499">499</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t500" href="#t500">500</a></span><span class="t"> <span class="nam">text</span> <span class="op">=</span> <span class="nam">Text</span><span class="op">.</span><span class="nam">from_word</span><span class="op">(</span><span class="nam">word</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t501" href="#t501">501</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">text</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t502" href="#t502">502</a></span><span class="t"> <span class="nam">spacing</span><span class="op">,</span> <span class="nam">position</span><span class="op">,</span> <span class="nam">overflow</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_alignment_handler</span><span class="op">.</span><span class="nam">calculate_spacing_and_position</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t503" href="#t503">503</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_spacing</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_spacing</span><span class="op">[</span><span class="num">1</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t504" href="#t504">504</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t505" href="#t505">505</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">overflow</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t506" href="#t506">506</a></span><span class="t"> <span class="com"># Word fits! Add it completely</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t507" href="#t507">507</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_words</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">word</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t508" href="#t508">508</a></span><span class="t"> <span class="nam">word</span><span class="op">.</span><span class="nam">add_concete</span><span class="op">(</span><span class="nam">text</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t509" href="#t509">509</a></span><span class="t"> <span class="nam">text</span><span class="op">.</span><span class="nam">add_line</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t510" href="#t510">510</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_position_render</span> <span class="op">=</span> <span class="nam">position</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t511" href="#t511">511</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_spacing_render</span> <span class="op">=</span> <span class="nam">spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t512" href="#t512">512</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span><span class="op">,</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t513" href="#t513">513</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t514" href="#t514">514</a></span><span class="t"> <span class="com"># Word doesn't fit, remove it and try hyphenation</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t515" href="#t515">515</a></span><span class="t"> <span class="nam">_</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">.</span><span class="nam">pop</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t516" href="#t516">516</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t517" href="#t517">517</a></span><span class="t"> <span class="com"># Step 1: Try pyphen hyphenation</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t518" href="#t518">518</a></span><span class="t"> <span class="nam">pyphen_splits</span> <span class="op">=</span> <span class="nam">word</span><span class="op">.</span><span class="nam">possible_hyphenation</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t519" href="#t519">519</a></span><span class="t"> <span class="nam">valid_splits</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t520" href="#t520">520</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t521" href="#t521">521</a></span><span class="t"> <span class="key">if</span> <span class="nam">pyphen_splits</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t522" href="#t522">522</a></span><span class="t"> <span class="com"># Create Text objects for each possible split and check if they fit</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t523" href="#t523">523</a></span><span class="t"> <span class="key">for</span> <span class="nam">pair</span> <span class="key">in</span> <span class="nam">pyphen_splits</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t524" href="#t524">524</a></span><span class="t"> <span class="nam">first_part_text</span> <span class="op">=</span> <span class="nam">pair</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">+</span> <span class="str">"-"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t525" href="#t525">525</a></span><span class="t"> <span class="nam">second_part_text</span> <span class="op">=</span> <span class="nam">pair</span><span class="op">[</span><span class="num">1</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t526" href="#t526">526</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t527" href="#t527">527</a></span><span class="t"> <span class="com"># Validate minimum character requirements</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t528" href="#t528">528</a></span><span class="t"> <span class="key">if</span> <span class="nam">len</span><span class="op">(</span><span class="nam">pair</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">)</span> <span class="op">&lt;</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_min_chars_before_hyphen</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">528&#x202F;&#x219B;&#x202F;529</span><span class="annotate long">line 528 didn't jump to line 529 because the condition on line 528 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t529" href="#t529">529</a></span><span class="t"> <span class="key">continue</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t530" href="#t530">530</a></span><span class="t"> <span class="key">if</span> <span class="nam">len</span><span class="op">(</span><span class="nam">pair</span><span class="op">[</span><span class="num">1</span><span class="op">]</span><span class="op">)</span> <span class="op">&lt;</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_min_chars_after_hyphen</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">530&#x202F;&#x219B;&#x202F;531</span><span class="annotate long">line 530 didn't jump to line 531 because the condition on line 530 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t531" href="#t531">531</a></span><span class="t"> <span class="key">continue</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t532" href="#t532">532</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t533" href="#t533">533</a></span><span class="t"> <span class="com"># Create Text objects</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t534" href="#t534">534</a></span><span class="t"> <span class="nam">first_text</span> <span class="op">=</span> <span class="nam">Text</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t535" href="#t535">535</a></span><span class="t"> <span class="nam">first_part_text</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t536" href="#t536">536</a></span><span class="t"> <span class="nam">word</span><span class="op">.</span><span class="nam">style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t537" href="#t537">537</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t538" href="#t538">538</a></span><span class="t"> <span class="nam">line</span><span class="op">=</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t539" href="#t539">539</a></span><span class="t"> <span class="nam">source</span><span class="op">=</span><span class="nam">word</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t540" href="#t540">540</a></span><span class="t"> <span class="nam">second_text</span> <span class="op">=</span> <span class="nam">Text</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t541" href="#t541">541</a></span><span class="t"> <span class="nam">second_part_text</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t542" href="#t542">542</a></span><span class="t"> <span class="nam">word</span><span class="op">.</span><span class="nam">style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t543" href="#t543">543</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t544" href="#t544">544</a></span><span class="t"> <span class="nam">line</span><span class="op">=</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t545" href="#t545">545</a></span><span class="t"> <span class="nam">source</span><span class="op">=</span><span class="nam">word</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t546" href="#t546">546</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t547" href="#t547">547</a></span><span class="t"> <span class="com"># Check if first part fits</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t548" href="#t548">548</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">first_text</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t549" href="#t549">549</a></span><span class="t"> <span class="nam">spacing</span><span class="op">,</span> <span class="nam">position</span><span class="op">,</span> <span class="nam">overflow</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_alignment_handler</span><span class="op">.</span><span class="nam">calculate_spacing_and_position</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t550" href="#t550">550</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_spacing</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_spacing</span><span class="op">[</span><span class="num">1</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t551" href="#t551">551</a></span><span class="t"> <span class="nam">_</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">.</span><span class="nam">pop</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t552" href="#t552">552</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t553" href="#t553">553</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">overflow</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t554" href="#t554">554</a></span><span class="t"> <span class="com"># This split fits! Add it to valid options</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t555" href="#t555">555</a></span><span class="t"> <span class="nam">valid_splits</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="op">(</span><span class="nam">first_text</span><span class="op">,</span> <span class="nam">second_text</span><span class="op">,</span> <span class="nam">spacing</span><span class="op">,</span> <span class="nam">position</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t556" href="#t556">556</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t557" href="#t557">557</a></span><span class="t"> <span class="com"># Step 2: If we have valid pyphen splits, choose the best one</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t558" href="#t558">558</a></span><span class="t"> <span class="key">if</span> <span class="nam">valid_splits</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t559" href="#t559">559</a></span><span class="t"> <span class="com"># Select the split with the best (minimum) spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t560" href="#t560">560</a></span><span class="t"> <span class="nam">best_split</span> <span class="op">=</span> <span class="nam">min</span><span class="op">(</span><span class="nam">valid_splits</span><span class="op">,</span> <span class="nam">key</span><span class="op">=</span><span class="key">lambda</span> <span class="nam">x</span><span class="op">:</span> <span class="nam">x</span><span class="op">[</span><span class="num">2</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t561" href="#t561">561</a></span><span class="t"> <span class="nam">first_text</span><span class="op">,</span> <span class="nam">second_text</span><span class="op">,</span> <span class="nam">spacing</span><span class="op">,</span> <span class="nam">position</span> <span class="op">=</span> <span class="nam">best_split</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t562" href="#t562">562</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t563" href="#t563">563</a></span><span class="t"> <span class="com"># Apply the split</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t564" href="#t564">564</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">first_text</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t565" href="#t565">565</a></span><span class="t"> <span class="nam">first_text</span><span class="op">.</span><span class="nam">line</span> <span class="op">=</span> <span class="nam">self</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t566" href="#t566">566</a></span><span class="t"> <span class="nam">word</span><span class="op">.</span><span class="nam">add_concete</span><span class="op">(</span><span class="op">(</span><span class="nam">first_text</span><span class="op">,</span> <span class="nam">second_text</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t567" href="#t567">567</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_spacing_render</span> <span class="op">=</span> <span class="nam">spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t568" href="#t568">568</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_position_render</span> <span class="op">=</span> <span class="nam">position</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t569" href="#t569">569</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_words</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">word</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t570" href="#t570">570</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span><span class="op">,</span> <span class="nam">second_text</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t571" href="#t571">571</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t572" href="#t572">572</a></span><span class="t"> <span class="com"># Step 3: Try brute force hyphenation (only for long words)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t573" href="#t573">573</a></span><span class="t"> <span class="key">if</span> <span class="nam">len</span><span class="op">(</span><span class="nam">word</span><span class="op">.</span><span class="nam">text</span><span class="op">)</span> <span class="op">>=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_min_word_length_for_brute_force</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t574" href="#t574">574</a></span><span class="t"> <span class="com"># Calculate available space for the word</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t575" href="#t575">575</a></span><span class="t"> <span class="nam">word_length</span> <span class="op">=</span> <span class="nam">sum</span><span class="op">(</span><span class="op">[</span><span class="nam">text</span><span class="op">.</span><span class="nam">width</span> <span class="key">for</span> <span class="nam">text</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t576" href="#t576">576</a></span><span class="t"> <span class="nam">spacing_length</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_spacing</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">*</span> <span class="nam">max</span><span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">)</span> <span class="op">-</span> <span class="num">1</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t577" href="#t577">577</a></span><span class="t"> <span class="nam">remaining</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">-</span> <span class="nam">word_length</span> <span class="op">-</span> <span class="nam">spacing_length</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t578" href="#t578">578</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t579" href="#t579">579</a></span><span class="t"> <span class="key">if</span> <span class="nam">remaining</span> <span class="op">></span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t580" href="#t580">580</a></span><span class="t"> <span class="com"># Create a hyphenated version to measure</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t581" href="#t581">581</a></span><span class="t"> <span class="nam">test_text</span> <span class="op">=</span> <span class="nam">Text</span><span class="op">(</span><span class="nam">word</span><span class="op">.</span><span class="nam">text</span> <span class="op">+</span> <span class="str">"-"</span><span class="op">,</span> <span class="nam">word</span><span class="op">.</span><span class="nam">style</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t582" href="#t582">582</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t583" href="#t583">583</a></span><span class="t"> <span class="key">if</span> <span class="nam">test_text</span><span class="op">.</span><span class="nam">width</span> <span class="op">></span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">583&#x202F;&#x219B;&#x202F;637</span><span class="annotate long">line 583 didn't jump to line 637 because the condition on line 583 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t584" href="#t584">584</a></span><span class="t"> <span class="com"># Calculate what fraction of the hyphenated word fits</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t585" href="#t585">585</a></span><span class="t"> <span class="nam">fraction</span> <span class="op">=</span> <span class="nam">remaining</span> <span class="op">/</span> <span class="nam">test_text</span><span class="op">.</span><span class="nam">width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t586" href="#t586">586</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t587" href="#t587">587</a></span><span class="t"> <span class="com"># Convert fraction to character position</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t588" href="#t588">588</a></span><span class="t"> <span class="com"># We need at least min_chars_before_hyphen and leave at least</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t589" href="#t589">589</a></span><span class="t"> <span class="com"># min_chars_after_hyphen</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t590" href="#t590">590</a></span><span class="t"> <span class="nam">max_split_pos</span> <span class="op">=</span> <span class="nam">len</span><span class="op">(</span><span class="nam">word</span><span class="op">.</span><span class="nam">text</span><span class="op">)</span> <span class="op">-</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_min_chars_after_hyphen</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t591" href="#t591">591</a></span><span class="t"> <span class="nam">min_split_pos</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_min_chars_before_hyphen</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t592" href="#t592">592</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t593" href="#t593">593</a></span><span class="t"> <span class="com"># Calculate ideal split position based on available space</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t594" href="#t594">594</a></span><span class="t"> <span class="nam">ideal_split</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">fraction</span> <span class="op">*</span> <span class="nam">len</span><span class="op">(</span><span class="nam">word</span><span class="op">.</span><span class="nam">text</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t595" href="#t595">595</a></span><span class="t"> <span class="nam">split_pos</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">min_split_pos</span><span class="op">,</span> <span class="nam">min</span><span class="op">(</span><span class="nam">ideal_split</span><span class="op">,</span> <span class="nam">max_split_pos</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t596" href="#t596">596</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t597" href="#t597">597</a></span><span class="t"> <span class="com"># Ensure we meet minimum requirements</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t598" href="#t598">598</a></span><span class="t"> <span class="key">if</span> <span class="op">(</span><span class="nam">split_pos</span> <span class="op">>=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_min_chars_before_hyphen</span> <span class="key">and</span>&nbsp;</span><span class="r"><span class="annotate short">598&#x202F;&#x219B;&#x202F;637</span><span class="annotate long">line 598 didn't jump to line 637 because the condition on line 598 was always true</span></span></p>
<p class="par par2 ru2 show_par"><span class="n"><a id="t599" href="#t599">599</a></span><span class="t"> <span class="nam">len</span><span class="op">(</span><span class="nam">word</span><span class="op">.</span><span class="nam">text</span><span class="op">)</span> <span class="op">-</span> <span class="nam">split_pos</span> <span class="op">>=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_min_chars_after_hyphen</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t600" href="#t600">600</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t601" href="#t601">601</a></span><span class="t"> <span class="com"># Create the split</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t602" href="#t602">602</a></span><span class="t"> <span class="nam">first_part_text</span> <span class="op">=</span> <span class="nam">word</span><span class="op">.</span><span class="nam">text</span><span class="op">[</span><span class="op">:</span><span class="nam">split_pos</span><span class="op">]</span> <span class="op">+</span> <span class="str">"-"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t603" href="#t603">603</a></span><span class="t"> <span class="nam">second_part_text</span> <span class="op">=</span> <span class="nam">word</span><span class="op">.</span><span class="nam">text</span><span class="op">[</span><span class="nam">split_pos</span><span class="op">:</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t604" href="#t604">604</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t605" href="#t605">605</a></span><span class="t"> <span class="nam">first_text</span> <span class="op">=</span> <span class="nam">Text</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t606" href="#t606">606</a></span><span class="t"> <span class="nam">first_part_text</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t607" href="#t607">607</a></span><span class="t"> <span class="nam">word</span><span class="op">.</span><span class="nam">style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t608" href="#t608">608</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t609" href="#t609">609</a></span><span class="t"> <span class="nam">line</span><span class="op">=</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t610" href="#t610">610</a></span><span class="t"> <span class="nam">source</span><span class="op">=</span><span class="nam">word</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t611" href="#t611">611</a></span><span class="t"> <span class="nam">second_text</span> <span class="op">=</span> <span class="nam">Text</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t612" href="#t612">612</a></span><span class="t"> <span class="nam">second_part_text</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t613" href="#t613">613</a></span><span class="t"> <span class="nam">word</span><span class="op">.</span><span class="nam">style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t614" href="#t614">614</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t615" href="#t615">615</a></span><span class="t"> <span class="nam">line</span><span class="op">=</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t616" href="#t616">616</a></span><span class="t"> <span class="nam">source</span><span class="op">=</span><span class="nam">word</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t617" href="#t617">617</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t618" href="#t618">618</a></span><span class="t"> <span class="com"># Verify the first part actually fits</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t619" href="#t619">619</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">first_text</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t620" href="#t620">620</a></span><span class="t"> <span class="nam">spacing</span><span class="op">,</span> <span class="nam">position</span><span class="op">,</span> <span class="nam">overflow</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_alignment_handler</span><span class="op">.</span><span class="nam">calculate_spacing_and_position</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t621" href="#t621">621</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_spacing</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_spacing</span><span class="op">[</span><span class="num">1</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t622" href="#t622">622</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t623" href="#t623">623</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">overflow</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">623&#x202F;&#x219B;&#x202F;625</span><span class="annotate long">line 623 didn't jump to line 625 because the condition on line 623 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t624" href="#t624">624</a></span><span class="t"> <span class="com"># Brute force split works!</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t625" href="#t625">625</a></span><span class="t"> <span class="nam">first_text</span><span class="op">.</span><span class="nam">line</span> <span class="op">=</span> <span class="nam">self</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t626" href="#t626">626</a></span><span class="t"> <span class="nam">second_text</span><span class="op">.</span><span class="nam">line</span> <span class="op">=</span> <span class="nam">self</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t627" href="#t627">627</a></span><span class="t"> <span class="nam">word</span><span class="op">.</span><span class="nam">add_concete</span><span class="op">(</span><span class="op">(</span><span class="nam">first_text</span><span class="op">,</span> <span class="nam">second_text</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t628" href="#t628">628</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_spacing_render</span> <span class="op">=</span> <span class="nam">spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t629" href="#t629">629</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_position_render</span> <span class="op">=</span> <span class="nam">position</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t630" href="#t630">630</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_words</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">word</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t631" href="#t631">631</a></span><span class="t"> <span class="key">return</span> <span class="key">True</span><span class="op">,</span> <span class="nam">second_text</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t632" href="#t632">632</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t633" href="#t633">633</a></span><span class="t"> <span class="com"># Doesn't fit, remove it</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t634" href="#t634">634</a></span><span class="t"> <span class="nam">_</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">.</span><span class="nam">pop</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t635" href="#t635">635</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t636" href="#t636">636</a></span><span class="t"> <span class="com"># Step 4: Word cannot be hyphenated or split, move to next line</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t637" href="#t637">637</a></span><span class="t"> <span class="key">return</span> <span class="key">False</span><span class="op">,</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t638" href="#t638">638</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t639" href="#t639">639</a></span><span class="t"> <span class="key">def</span> <span class="nam">render</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t640" href="#t640">640</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t641" href="#t641">641</a></span><span class="t"><span class="str"> Render the line with all its text objects using the alignment handler system.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t642" href="#t642">642</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t643" href="#t643">643</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t644" href="#t644">644</a></span><span class="t"><span class="str"> A PIL Image containing the rendered line</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t645" href="#t645">645</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t646" href="#t646">646</a></span><span class="t"> <span class="com"># Recalculate spacing and position for current text objects to ensure accuracy</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t647" href="#t647">647</a></span><span class="t"> <span class="key">if</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">)</span> <span class="op">></span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t648" href="#t648">648</a></span><span class="t"> <span class="nam">spacing</span><span class="op">,</span> <span class="nam">position</span><span class="op">,</span> <span class="nam">overflow</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_alignment_handler</span><span class="op">.</span><span class="nam">calculate_spacing_and_position</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t649" href="#t649">649</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_spacing</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_spacing</span><span class="op">[</span><span class="num">1</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t650" href="#t650">650</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_spacing_render</span> <span class="op">=</span> <span class="nam">spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t651" href="#t651">651</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_position_render</span> <span class="op">=</span> <span class="nam">position</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t652" href="#t652">652</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t653" href="#t653">653</a></span><span class="t"> <span class="nam">y_cursor</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_baseline</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t654" href="#t654">654</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t655" href="#t655">655</a></span><span class="t"> <span class="com"># Start x_cursor at line origin plus any alignment offset</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t656" href="#t656">656</a></span><span class="t"> <span class="nam">x_cursor</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span><span class="op">[</span><span class="num">0</span><span class="op">]</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_position_render</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t657" href="#t657">657</a></span><span class="t"> <span class="key">for</span> <span class="nam">i</span><span class="op">,</span> <span class="nam">text</span> <span class="key">in</span> <span class="nam">enumerate</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t658" href="#t658">658</a></span><span class="t"> <span class="com"># Update text draw context to current draw context</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t659" href="#t659">659</a></span><span class="t"> <span class="nam">text</span><span class="op">.</span><span class="nam">_draw</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_draw</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t660" href="#t660">660</a></span><span class="t"> <span class="nam">text</span><span class="op">.</span><span class="nam">set_origin</span><span class="op">(</span><span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="op">[</span><span class="nam">x_cursor</span><span class="op">,</span> <span class="nam">y_cursor</span><span class="op">]</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t661" href="#t661">661</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t662" href="#t662">662</a></span><span class="t"> <span class="com"># Determine next text object for continuous decoration</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t663" href="#t663">663</a></span><span class="t"> <span class="nam">next_text</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">[</span><span class="nam">i</span> <span class="op">+</span> <span class="num">1</span><span class="op">]</span> <span class="key">if</span> <span class="nam">i</span> <span class="op">+</span> <span class="xx">\</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t664" href="#t664">664</a></span><span class="t"> <span class="num">1</span> <span class="op">&lt;</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">)</span> <span class="key">else</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t665" href="#t665">665</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t666" href="#t666">666</a></span><span class="t"> <span class="com"># Get the spacing for this specific gap (variable for justified text)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t667" href="#t667">667</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_alignment_handler</span><span class="op">,</span> <span class="nam">JustifyAlignmentHandler</span><span class="op">)</span> <span class="key">and</span> <span class="xx">\</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t668" href="#t668">668</a></span><span class="t"> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_alignment_handler</span><span class="op">,</span> <span class="str">'_gap_spacings'</span><span class="op">)</span> <span class="key">and</span> <span class="xx">\</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t669" href="#t669">669</a></span><span class="t"> <span class="nam">i</span> <span class="op">&lt;</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_alignment_handler</span><span class="op">.</span><span class="nam">_gap_spacings</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t670" href="#t670">670</a></span><span class="t"> <span class="nam">current_spacing</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_alignment_handler</span><span class="op">.</span><span class="nam">_gap_spacings</span><span class="op">[</span><span class="nam">i</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t671" href="#t671">671</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t672" href="#t672">672</a></span><span class="t"> <span class="nam">current_spacing</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_spacing_render</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t673" href="#t673">673</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t674" href="#t674">674</a></span><span class="t"> <span class="com"># Render with next text information for continuous underline/strikethrough</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t675" href="#t675">675</a></span><span class="t"> <span class="nam">text</span><span class="op">.</span><span class="nam">render</span><span class="op">(</span><span class="nam">next_text</span><span class="op">,</span> <span class="nam">current_spacing</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t676" href="#t676">676</a></span><span class="t"> <span class="com"># Add text width, then spacing only if there are more words</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t677" href="#t677">677</a></span><span class="t"> <span class="nam">x_cursor</span> <span class="op">+=</span> <span class="nam">text</span><span class="op">.</span><span class="nam">width</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t678" href="#t678">678</a></span><span class="t"> <span class="key">if</span> <span class="nam">i</span> <span class="op">&lt;</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">)</span> <span class="op">-</span> <span class="num">1</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t679" href="#t679">679</a></span><span class="t"> <span class="nam">x_cursor</span> <span class="op">+=</span> <span class="nam">current_spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t680" href="#t680">680</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t681" href="#t681">681</a></span><span class="t"> <span class="key">def</span> <span class="nam">query_point</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">point</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="str">'QueryResult'</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t682" href="#t682">682</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t683" href="#t683">683</a></span><span class="t"><span class="str"> Find which Text object contains the given point.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t684" href="#t684">684</a></span><span class="t"><span class="str"> Uses Queriable.in_object() mixin for hit-testing.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t685" href="#t685">685</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t686" href="#t686">686</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t687" href="#t687">687</a></span><span class="t"><span class="str"> point: (x, y) coordinates to query</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t688" href="#t688">688</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t689" href="#t689">689</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t690" href="#t690">690</a></span><span class="t"><span class="str"> QueryResult from the text object at that point, or None</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t691" href="#t691">691</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t692" href="#t692">692</a></span><span class="t"> <span class="nam">point_array</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="nam">point</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t693" href="#t693">693</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t694" href="#t694">694</a></span><span class="t"> <span class="com"># Check each text object in this line</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t695" href="#t695">695</a></span><span class="t"> <span class="key">for</span> <span class="nam">text_obj</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_text_objects</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t696" href="#t696">696</a></span><span class="t"> <span class="com"># Use Queriable mixin's in_object() for hit-testing</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t697" href="#t697">697</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">text_obj</span><span class="op">,</span> <span class="nam">Queriable</span><span class="op">)</span> <span class="key">and</span> <span class="nam">text_obj</span><span class="op">.</span><span class="nam">in_object</span><span class="op">(</span><span class="nam">point_array</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t698" href="#t698">698</a></span><span class="t"> <span class="com"># Extract metadata based on text type</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t699" href="#t699">699</a></span><span class="t"> <span class="nam">origin</span> <span class="op">=</span> <span class="nam">text_obj</span><span class="op">.</span><span class="nam">_origin</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t700" href="#t700">700</a></span><span class="t"> <span class="nam">size</span> <span class="op">=</span> <span class="nam">text_obj</span><span class="op">.</span><span class="nam">size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t701" href="#t701">701</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t702" href="#t702">702</a></span><span class="t"> <span class="com"># Text origin is at baseline (anchor="ls"), so visual top is origin[1] - ascent</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t703" href="#t703">703</a></span><span class="t"> <span class="com"># Bounds should be (x, visual_top, width, height) for proper</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t704" href="#t704">704</a></span><span class="t"> <span class="com"># highlighting</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t705" href="#t705">705</a></span><span class="t"> <span class="nam">visual_top</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">origin</span><span class="op">[</span><span class="num">1</span><span class="op">]</span> <span class="op">-</span> <span class="nam">text_obj</span><span class="op">.</span><span class="nam">_ascent</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t706" href="#t706">706</a></span><span class="t"> <span class="nam">bounds</span> <span class="op">=</span> <span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t707" href="#t707">707</a></span><span class="t"> <span class="nam">int</span><span class="op">(</span><span class="nam">origin</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t708" href="#t708">708</a></span><span class="t"> <span class="nam">visual_top</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t709" href="#t709">709</a></span><span class="t"> <span class="nam">int</span><span class="op">(</span><span class="nam">size</span><span class="op">[</span><span class="num">0</span><span class="op">]</span><span class="op">)</span> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">size</span><span class="op">,</span> <span class="str">'__getitem__'</span><span class="op">)</span> <span class="key">else</span> <span class="num">0</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t710" href="#t710">710</a></span><span class="t"> <span class="nam">int</span><span class="op">(</span><span class="nam">size</span><span class="op">[</span><span class="num">1</span><span class="op">]</span><span class="op">)</span> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">size</span><span class="op">,</span> <span class="str">'__getitem__'</span><span class="op">)</span> <span class="key">else</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t711" href="#t711">711</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t712" href="#t712">712</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t713" href="#t713">713</a></span><span class="t"> <span class="com"># Import here to avoid circular dependency</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t714" href="#t714">714</a></span><span class="t"> <span class="key">from</span> <span class="op">.</span><span class="nam">functional</span> <span class="key">import</span> <span class="nam">LinkText</span><span class="op">,</span> <span class="nam">ButtonText</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t715" href="#t715">715</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t716" href="#t716">716</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">text_obj</span><span class="op">,</span> <span class="nam">LinkText</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t717" href="#t717">717</a></span><span class="t"> <span class="nam">result</span> <span class="op">=</span> <span class="nam">QueryResult</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t718" href="#t718">718</a></span><span class="t"> <span class="nam">object</span><span class="op">=</span><span class="nam">text_obj</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t719" href="#t719">719</a></span><span class="t"> <span class="nam">object_type</span><span class="op">=</span><span class="str">"link"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t720" href="#t720">720</a></span><span class="t"> <span class="nam">bounds</span><span class="op">=</span><span class="nam">bounds</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t721" href="#t721">721</a></span><span class="t"> <span class="nam">text</span><span class="op">=</span><span class="nam">text_obj</span><span class="op">.</span><span class="nam">_text</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t722" href="#t722">722</a></span><span class="t"> <span class="nam">is_interactive</span><span class="op">=</span><span class="key">True</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t723" href="#t723">723</a></span><span class="t"> <span class="nam">link_target</span><span class="op">=</span><span class="nam">text_obj</span><span class="op">.</span><span class="nam">_link</span><span class="op">.</span><span class="nam">location</span> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t724" href="#t724">724</a></span><span class="t"> <span class="nam">text_obj</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t725" href="#t725">725</a></span><span class="t"> <span class="str">'_link'</span><span class="op">)</span> <span class="key">else</span> <span class="key">None</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t726" href="#t726">726</a></span><span class="t"> <span class="key">elif</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">text_obj</span><span class="op">,</span> <span class="nam">ButtonText</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">726&#x202F;&#x219B;&#x202F;727</span><span class="annotate long">line 726 didn't jump to line 727 because the condition on line 726 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t727" href="#t727">727</a></span><span class="t"> <span class="nam">result</span> <span class="op">=</span> <span class="nam">QueryResult</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t728" href="#t728">728</a></span><span class="t"> <span class="nam">object</span><span class="op">=</span><span class="nam">text_obj</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t729" href="#t729">729</a></span><span class="t"> <span class="nam">object_type</span><span class="op">=</span><span class="str">"button"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t730" href="#t730">730</a></span><span class="t"> <span class="nam">bounds</span><span class="op">=</span><span class="nam">bounds</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t731" href="#t731">731</a></span><span class="t"> <span class="nam">text</span><span class="op">=</span><span class="nam">text_obj</span><span class="op">.</span><span class="nam">_text</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t732" href="#t732">732</a></span><span class="t"> <span class="nam">is_interactive</span><span class="op">=</span><span class="key">True</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t733" href="#t733">733</a></span><span class="t"> <span class="nam">callback</span><span class="op">=</span><span class="nam">text_obj</span><span class="op">.</span><span class="nam">_callback</span> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t734" href="#t734">734</a></span><span class="t"> <span class="nam">text_obj</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t735" href="#t735">735</a></span><span class="t"> <span class="str">'_callback'</span><span class="op">)</span> <span class="key">else</span> <span class="key">None</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t736" href="#t736">736</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t737" href="#t737">737</a></span><span class="t"> <span class="nam">result</span> <span class="op">=</span> <span class="nam">QueryResult</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t738" href="#t738">738</a></span><span class="t"> <span class="nam">object</span><span class="op">=</span><span class="nam">text_obj</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t739" href="#t739">739</a></span><span class="t"> <span class="nam">object_type</span><span class="op">=</span><span class="str">"text"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t740" href="#t740">740</a></span><span class="t"> <span class="nam">bounds</span><span class="op">=</span><span class="nam">bounds</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t741" href="#t741">741</a></span><span class="t"> <span class="nam">text</span><span class="op">=</span><span class="nam">text_obj</span><span class="op">.</span><span class="nam">_text</span> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">text_obj</span><span class="op">,</span> <span class="str">'_text'</span><span class="op">)</span> <span class="key">else</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t742" href="#t742">742</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t743" href="#t743">743</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t744" href="#t744">744</a></span><span class="t"> <span class="nam">result</span><span class="op">.</span><span class="nam">parent_line</span> <span class="op">=</span> <span class="nam">self</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t745" href="#t745">745</a></span><span class="t"> <span class="key">return</span> <span class="nam">result</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t746" href="#t746">746</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t747" href="#t747">747</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_7d48e1f4c6486fa2_table_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_40407af872b0cf37___init___py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,121 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/abstract/__init__.py: 100%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/abstract/__init__.py</b>:
<span class="pc_cov">100%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">5 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">5<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">0<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">1<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">0<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_20e398e67121d457___init___py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_af715639580e2d86_block_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">Abstract layer for the pyWebLayout library.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">This package contains abstract representations of document elements that are</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">independent of rendering specifics.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">inline</span> <span class="key">import</span> <span class="nam">Word</span><span class="op">,</span> <span class="nam">FormattedSpan</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">block</span> <span class="key">import</span> <span class="nam">Paragraph</span><span class="op">,</span> <span class="nam">Heading</span><span class="op">,</span> <span class="nam">Image</span><span class="op">,</span> <span class="nam">HeadingLevel</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">document</span> <span class="key">import</span> <span class="nam">Document</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">functional</span> <span class="key">import</span> <span class="nam">LinkType</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"><span class="nam">__all__</span> <span class="op">=</span> <span class="op">[</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t"> <span class="str">'Word'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"> <span class="str">'FormattedSpan'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"> <span class="str">'Paragraph'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"> <span class="str">'Heading'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"> <span class="str">'Image'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"> <span class="str">'HeadingLevel'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"> <span class="str">'Document'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"> <span class="str">'LinkType'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_20e398e67121d457___init___py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_af715639580e2d86_block_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,694 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/abstract/document.py: 78%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/abstract/document.py</b>:
<span class="pc_cov">78%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">194 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">159<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">35<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">47<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">4<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_af715639580e2d86_block_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_af715639580e2d86_functional_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="run"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="key">from</span> <span class="nam">__future__</span> <span class="key">import</span> <span class="nam">annotations</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">List</span><span class="op">,</span> <span class="nam">Dict</span><span class="op">,</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">Tuple</span><span class="op">,</span> <span class="nam">Union</span><span class="op">,</span> <span class="nam">Any</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t"><span class="key">from</span> <span class="nam">enum</span> <span class="key">import</span> <span class="nam">Enum</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">block</span> <span class="key">import</span> <span class="nam">Block</span><span class="op">,</span> <span class="nam">BlockType</span><span class="op">,</span> <span class="nam">Heading</span><span class="op">,</span> <span class="nam">HeadingLevel</span><span class="op">,</span> <span class="nam">Paragraph</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="op">.</span><span class="nam">style</span> <span class="key">import</span> <span class="nam">Font</span><span class="op">,</span> <span class="nam">FontWeight</span><span class="op">,</span> <span class="nam">FontStyle</span><span class="op">,</span> <span class="nam">TextDecoration</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">abstract_style</span> <span class="key">import</span> <span class="nam">AbstractStyle</span><span class="op">,</span> <span class="nam">AbstractStyleRegistry</span><span class="op">,</span> <span class="nam">FontFamily</span><span class="op">,</span> <span class="nam">FontSize</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">concrete_style</span> <span class="key">import</span> <span class="nam">ConcreteStyleRegistry</span><span class="op">,</span> <span class="nam">RenderingContext</span><span class="op">,</span> <span class="nam">StyleResolver</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="op">.</span><span class="nam">core</span> <span class="key">import</span> <span class="nam">FontRegistry</span><span class="op">,</span> <span class="nam">MetadataContainer</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="key">class</span> <span class="nam">MetadataType</span><span class="op">(</span><span class="nam">Enum</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"> <span class="str">"""Types of metadata that can be associated with a document"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"> <span class="nam">TITLE</span> <span class="op">=</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t"> <span class="nam">AUTHOR</span> <span class="op">=</span> <span class="num">2</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"> <span class="nam">DESCRIPTION</span> <span class="op">=</span> <span class="num">3</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"> <span class="nam">KEYWORDS</span> <span class="op">=</span> <span class="num">4</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"> <span class="nam">LANGUAGE</span> <span class="op">=</span> <span class="num">5</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"> <span class="nam">PUBLICATION_DATE</span> <span class="op">=</span> <span class="num">6</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"> <span class="nam">MODIFIED_DATE</span> <span class="op">=</span> <span class="num">7</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"> <span class="nam">PUBLISHER</span> <span class="op">=</span> <span class="num">8</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"> <span class="nam">IDENTIFIER</span> <span class="op">=</span> <span class="num">9</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"> <span class="nam">COVER_IMAGE</span> <span class="op">=</span> <span class="num">10</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"> <span class="nam">CUSTOM</span> <span class="op">=</span> <span class="num">100</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"><span class="key">class</span> <span class="nam">Document</span><span class="op">(</span><span class="nam">FontRegistry</span><span class="op">,</span> <span class="nam">MetadataContainer</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t"><span class="str"> Abstract representation of a complete document like an HTML page or an ebook.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"><span class="str"> This class manages the logical structure of the document without rendering concerns.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"><span class="str"> Uses FontRegistry mixin for font caching.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"><span class="str"> Uses MetadataContainer mixin for metadata management.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"> <span class="nam">title</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t"> <span class="nam">language</span><span class="op">:</span> <span class="nam">str</span> <span class="op">=</span> <span class="str">"en-US"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"> <span class="nam">default_style</span><span class="op">=</span><span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t"><span class="str"> Initialize a new document.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"><span class="str"> title: The document title</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t"><span class="str"> language: The document language code</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"><span class="str"> default_style: Optional default style for child blocks</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_blocks</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">Block</span><span class="op">]</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_anchors</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Block</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span> <span class="com"># Named anchors for navigation</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_resources</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span> <span class="com"># External resources like images</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_stylesheets</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span> <span class="com"># CSS stylesheets</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_scripts</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span> <span class="com"># JavaScript code</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"> <span class="com"># Style management with new abstract/concrete system</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_abstract_style_registry</span> <span class="op">=</span> <span class="nam">AbstractStyleRegistry</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_rendering_context</span> <span class="op">=</span> <span class="nam">RenderingContext</span><span class="op">(</span><span class="nam">default_language</span><span class="op">=</span><span class="nam">language</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style_resolver</span> <span class="op">=</span> <span class="nam">StyleResolver</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_rendering_context</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_concrete_style_registry</span> <span class="op">=</span> <span class="nam">ConcreteStyleRegistry</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_style_resolver</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"> <span class="com"># Set default style</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t"> <span class="key">if</span> <span class="nam">default_style</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">62&#x202F;&#x219B;&#x202F;65</span><span class="annotate long">line 62 didn't jump to line 65 because the condition on line 62 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t"> <span class="com"># Create a default abstract style</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"> <span class="nam">default_style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_abstract_style_registry</span><span class="op">.</span><span class="nam">default_style</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"> <span class="key">elif</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">default_style</span><span class="op">,</span> <span class="nam">Font</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t"> <span class="com"># Convert Font to AbstractStyle for backward compatibility</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t"> <span class="nam">default_style</span> <span class="op">=</span> <span class="nam">AbstractStyle</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"> <span class="nam">font_family</span><span class="op">=</span><span class="nam">FontFamily</span><span class="op">.</span><span class="nam">SERIF</span><span class="op">,</span> <span class="com"># Default assumption</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"> <span class="nam">font_size</span><span class="op">=</span><span class="nam">default_style</span><span class="op">.</span><span class="nam">font_size</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t"> <span class="nam">color</span><span class="op">=</span><span class="nam">default_style</span><span class="op">.</span><span class="nam">colour</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t"> <span class="nam">language</span><span class="op">=</span><span class="nam">default_style</span><span class="op">.</span><span class="nam">language</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"> <span class="nam">style_id</span><span class="op">,</span> <span class="nam">default_style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_abstract_style_registry</span><span class="op">.</span><span class="nam">get_or_create_style</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t"> <span class="nam">default_style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_default_style</span> <span class="op">=</span> <span class="nam">default_style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t"> <span class="com"># Set basic metadata</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"> <span class="key">if</span> <span class="nam">title</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">set_metadata</span><span class="op">(</span><span class="nam">MetadataType</span><span class="op">.</span><span class="nam">TITLE</span><span class="op">,</span> <span class="nam">title</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">set_metadata</span><span class="op">(</span><span class="nam">MetadataType</span><span class="op">.</span><span class="nam">LANGUAGE</span><span class="op">,</span> <span class="nam">language</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t"> <span class="key">def</span> <span class="nam">blocks</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">Block</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"> <span class="str">"""Get the top-level blocks in this document"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_blocks</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t"> <span class="key">def</span> <span class="nam">default_style</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"> <span class="str">"""Get the default style for this document"""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_default_style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t"> <span class="op">@</span><span class="nam">default_style</span><span class="op">.</span><span class="nam">setter</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t"> <span class="key">def</span> <span class="nam">default_style</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">style</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t"> <span class="str">"""Set the default style for this document"""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_default_style</span> <span class="op">=</span> <span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t"> <span class="key">def</span> <span class="nam">add_block</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">block</span><span class="op">:</span> <span class="nam">Block</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"><span class="str"> Add a block to this document.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"><span class="str"> block: The block to add</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_blocks</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">block</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t"> <span class="key">def</span> <span class="nam">create_paragraph</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">style</span><span class="op">=</span><span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Paragraph</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t"><span class="str"> Create a new paragraph and add it to this document.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t"><span class="str"> style: Optional style override. If None, inherits from document</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t"><span class="str"> The newly created Paragraph object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"> <span class="key">if</span> <span class="nam">style</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t"> <span class="nam">style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_default_style</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t"> <span class="nam">paragraph</span> <span class="op">=</span> <span class="nam">Paragraph</span><span class="op">(</span><span class="nam">style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">add_block</span><span class="op">(</span><span class="nam">paragraph</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t"> <span class="key">return</span> <span class="nam">paragraph</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t"> <span class="key">def</span> <span class="nam">create_heading</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t"> <span class="nam">level</span><span class="op">:</span> <span class="nam">HeadingLevel</span> <span class="op">=</span> <span class="nam">HeadingLevel</span><span class="op">.</span><span class="nam">H1</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t"> <span class="nam">style</span><span class="op">=</span><span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Heading</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t"><span class="str"> Create a new heading and add it to this document.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t"><span class="str"> level: The heading level</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t"><span class="str"> style: Optional style override. If None, inherits from document</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t"><span class="str"> The newly created Heading object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"> <span class="key">if</span> <span class="nam">style</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t"> <span class="nam">style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_default_style</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"> <span class="nam">heading</span> <span class="op">=</span> <span class="nam">Heading</span><span class="op">(</span><span class="nam">level</span><span class="op">,</span> <span class="nam">style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">add_block</span><span class="op">(</span><span class="nam">heading</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t"> <span class="key">return</span> <span class="nam">heading</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t"> <span class="key">def</span> <span class="nam">create_chapter</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"> <span class="nam">title</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t"> <span class="nam">level</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">1</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t"> <span class="nam">style</span><span class="op">=</span><span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="str">'Chapter'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"><span class="str"> Create a new chapter with inherited style.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t"><span class="str"> title: The chapter title</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t"><span class="str"> level: The chapter level</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t"><span class="str"> style: Optional style override. If None, inherits from document</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t"><span class="str"> The newly created Chapter object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t"> <span class="key">if</span> <span class="nam">style</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t"> <span class="nam">style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_default_style</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"> <span class="key">return</span> <span class="nam">Chapter</span><span class="op">(</span><span class="nam">title</span><span class="op">,</span> <span class="nam">level</span><span class="op">,</span> <span class="nam">style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t"> <span class="com"># set_metadata() and get_metadata() are provided by MetadataContainer mixin</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t"> <span class="key">def</span> <span class="nam">add_anchor</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">name</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span> <span class="nam">target</span><span class="op">:</span> <span class="nam">Block</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"><span class="str"> Add a named anchor to this document.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t"><span class="str"> name: The anchor name</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"><span class="str"> target: The target block</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_anchors</span><span class="op">[</span><span class="nam">name</span><span class="op">]</span> <span class="op">=</span> <span class="nam">target</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_anchor</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">name</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Block</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t"><span class="str"> Get a named anchor from this document.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t"><span class="str"> name: The anchor name</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t"><span class="str"> The target block, or None if not found</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_anchors</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="nam">name</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t"> <span class="key">def</span> <span class="nam">add_resource</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">name</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span> <span class="nam">resource</span><span class="op">:</span> <span class="nam">Any</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t"><span class="str"> Add a resource to this document.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t"><span class="str"> name: The resource name</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t"><span class="str"> resource: The resource data</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_resources</span><span class="op">[</span><span class="nam">name</span><span class="op">]</span> <span class="op">=</span> <span class="nam">resource</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_resource</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">name</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Any</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t"><span class="str"> Get a resource from this document.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t"><span class="str"> name: The resource name</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t"><span class="str"> The resource data, or None if not found</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_resources</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="nam">name</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"> <span class="key">def</span> <span class="nam">add_stylesheet</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">stylesheet</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t"><span class="str"> Add a stylesheet to this document.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"><span class="str"> stylesheet: The stylesheet data</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_stylesheets</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">stylesheet</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t"> <span class="key">def</span> <span class="nam">add_script</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">script</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t"><span class="str"> Add a script to this document.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"><span class="str"> script: The script code</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_scripts</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">script</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_title</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t"><span class="str"> Get the document title.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t"><span class="str"> The document title, or None if not set</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_metadata</span><span class="op">(</span><span class="nam">MetadataType</span><span class="op">.</span><span class="nam">TITLE</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_title</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">title</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t"><span class="str"> Set the document title.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t"><span class="str"> title: The document title</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">set_metadata</span><span class="op">(</span><span class="nam">MetadataType</span><span class="op">.</span><span class="nam">TITLE</span><span class="op">,</span> <span class="nam">title</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t"> <span class="key">def</span> <span class="nam">title</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t"><span class="str"> Get the document title as a property.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t"><span class="str"> The document title, or None if not set</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_title</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t"> <span class="op">@</span><span class="nam">title</span><span class="op">.</span><span class="nam">setter</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t"> <span class="key">def</span> <span class="nam">title</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">title</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t"><span class="str"> Set the document title as a property.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t"><span class="str"> title: The document title</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">set_title</span><span class="op">(</span><span class="nam">title</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t"> <span class="key">def</span> <span class="nam">find_blocks_by_type</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">block_type</span><span class="op">:</span> <span class="nam">BlockType</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">Block</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t"><span class="str"> Find all blocks of a specific type.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t"><span class="str"> block_type: The type of blocks to find</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t"><span class="str"> A list of matching blocks</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t"> <span class="nam">result</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t"> <span class="key">def</span> <span class="nam">_find_recursive</span><span class="op">(</span><span class="nam">blocks</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">Block</span><span class="op">]</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t"> <span class="key">for</span> <span class="nam">block</span> <span class="key">in</span> <span class="nam">blocks</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t"> <span class="key">if</span> <span class="nam">block</span><span class="op">.</span><span class="nam">block_type</span> <span class="op">==</span> <span class="nam">block_type</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t279" href="#t279">279</a></span><span class="t"> <span class="nam">result</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">block</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t280" href="#t280">280</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t281" href="#t281">281</a></span><span class="t"> <span class="com"># Check for child blocks based on block type</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t282" href="#t282">282</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="str">'_blocks'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">282&#x202F;&#x219B;&#x202F;283</span><span class="annotate long">line 282 didn't jump to line 283 because the condition on line 282 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t283" href="#t283">283</a></span><span class="t"> <span class="nam">_find_recursive</span><span class="op">(</span><span class="nam">block</span><span class="op">.</span><span class="nam">_blocks</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t284" href="#t284">284</a></span><span class="t"> <span class="key">elif</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="str">'_items'</span><span class="op">)</span> <span class="key">and</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">block</span><span class="op">.</span><span class="nam">_items</span><span class="op">,</span> <span class="nam">list</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">284&#x202F;&#x219B;&#x202F;285</span><span class="annotate long">line 284 didn't jump to line 285 because the condition on line 284 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t285" href="#t285">285</a></span><span class="t"> <span class="nam">_find_recursive</span><span class="op">(</span><span class="nam">block</span><span class="op">.</span><span class="nam">_items</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t286" href="#t286">286</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t287" href="#t287">287</a></span><span class="t"> <span class="nam">_find_recursive</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_blocks</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t288" href="#t288">288</a></span><span class="t"> <span class="key">return</span> <span class="nam">result</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t289" href="#t289">289</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t290" href="#t290">290</a></span><span class="t"> <span class="key">def</span> <span class="nam">find_headings</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">Heading</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t291" href="#t291">291</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t292" href="#t292">292</a></span><span class="t"><span class="str"> Find all headings in the document.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t293" href="#t293">293</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t294" href="#t294">294</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t295" href="#t295">295</a></span><span class="t"><span class="str"> A list of heading blocks</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t296" href="#t296">296</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t297" href="#t297">297</a></span><span class="t"> <span class="nam">blocks</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">find_blocks_by_type</span><span class="op">(</span><span class="nam">BlockType</span><span class="op">.</span><span class="nam">HEADING</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t298" href="#t298">298</a></span><span class="t"> <span class="key">return</span> <span class="op">[</span><span class="nam">block</span> <span class="key">for</span> <span class="nam">block</span> <span class="key">in</span> <span class="nam">blocks</span> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">block</span><span class="op">,</span> <span class="nam">Heading</span><span class="op">)</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t299" href="#t299">299</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t300" href="#t300">300</a></span><span class="t"> <span class="key">def</span> <span class="nam">generate_table_of_contents</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">str</span><span class="op">,</span> <span class="nam">Block</span><span class="op">]</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t301" href="#t301">301</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t302" href="#t302">302</a></span><span class="t"><span class="str"> Generate a table of contents from headings.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t303" href="#t303">303</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t304" href="#t304">304</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t305" href="#t305">305</a></span><span class="t"><span class="str"> A list of tuples containing (level, title, heading_block)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t306" href="#t306">306</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t307" href="#t307">307</a></span><span class="t"> <span class="nam">headings</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">find_headings</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t308" href="#t308">308</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t309" href="#t309">309</a></span><span class="t"> <span class="nam">toc</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t310" href="#t310">310</a></span><span class="t"> <span class="key">for</span> <span class="nam">heading</span> <span class="key">in</span> <span class="nam">headings</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t311" href="#t311">311</a></span><span class="t"> <span class="com"># Extract text from the heading</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t312" href="#t312">312</a></span><span class="t"> <span class="nam">title</span> <span class="op">=</span> <span class="str">""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t313" href="#t313">313</a></span><span class="t"> <span class="key">for</span> <span class="nam">_</span><span class="op">,</span> <span class="nam">word</span> <span class="key">in</span> <span class="nam">heading</span><span class="op">.</span><span class="nam">words_iter</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t314" href="#t314">314</a></span><span class="t"> <span class="nam">title</span> <span class="op">+=</span> <span class="nam">word</span><span class="op">.</span><span class="nam">text</span> <span class="op">+</span> <span class="str">" "</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t315" href="#t315">315</a></span><span class="t"> <span class="nam">title</span> <span class="op">=</span> <span class="nam">title</span><span class="op">.</span><span class="nam">strip</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t316" href="#t316">316</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t317" href="#t317">317</a></span><span class="t"> <span class="com"># Add to TOC</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t318" href="#t318">318</a></span><span class="t"> <span class="nam">level</span> <span class="op">=</span> <span class="nam">heading</span><span class="op">.</span><span class="nam">level</span><span class="op">.</span><span class="nam">value</span> <span class="com"># Get numeric value from HeadingLevel enum</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t319" href="#t319">319</a></span><span class="t"> <span class="nam">toc</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="op">(</span><span class="nam">level</span><span class="op">,</span> <span class="nam">title</span><span class="op">,</span> <span class="nam">heading</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t320" href="#t320">320</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t321" href="#t321">321</a></span><span class="t"> <span class="key">return</span> <span class="nam">toc</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t322" href="#t322">322</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t323" href="#t323">323</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_or_create_style</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t324" href="#t324">324</a></span><span class="t"> <span class="nam">font_family</span><span class="op">:</span> <span class="nam">FontFamily</span> <span class="op">=</span> <span class="nam">FontFamily</span><span class="op">.</span><span class="nam">SERIF</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t325" href="#t325">325</a></span><span class="t"> <span class="nam">font_size</span><span class="op">:</span> <span class="nam">Union</span><span class="op">[</span><span class="nam">FontSize</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="nam">FontSize</span><span class="op">.</span><span class="nam">MEDIUM</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t326" href="#t326">326</a></span><span class="t"> <span class="nam">font_weight</span><span class="op">:</span> <span class="nam">FontWeight</span> <span class="op">=</span> <span class="nam">FontWeight</span><span class="op">.</span><span class="nam">NORMAL</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t327" href="#t327">327</a></span><span class="t"> <span class="nam">font_style</span><span class="op">:</span> <span class="nam">FontStyle</span> <span class="op">=</span> <span class="nam">FontStyle</span><span class="op">.</span><span class="nam">NORMAL</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t328" href="#t328">328</a></span><span class="t"> <span class="nam">text_decoration</span><span class="op">:</span> <span class="nam">TextDecoration</span> <span class="op">=</span> <span class="nam">TextDecoration</span><span class="op">.</span><span class="nam">NONE</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t329" href="#t329">329</a></span><span class="t"> <span class="nam">color</span><span class="op">:</span> <span class="nam">Union</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="str">"black"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t330" href="#t330">330</a></span><span class="t"> <span class="nam">background_color</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Union</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t331" href="#t331">331</a></span><span class="t"> <span class="nam">language</span><span class="op">:</span> <span class="nam">str</span> <span class="op">=</span> <span class="str">"en-US"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t332" href="#t332">332</a></span><span class="t"> <span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">AbstractStyle</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t333" href="#t333">333</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t334" href="#t334">334</a></span><span class="t"><span class="str"> Get or create an abstract style with the specified properties.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t335" href="#t335">335</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t336" href="#t336">336</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t337" href="#t337">337</a></span><span class="t"><span class="str"> font_family: Semantic font family</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t338" href="#t338">338</a></span><span class="t"><span class="str"> font_size: Font size (semantic or numeric)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t339" href="#t339">339</a></span><span class="t"><span class="str"> font_weight: Font weight</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t340" href="#t340">340</a></span><span class="t"><span class="str"> font_style: Font style</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t341" href="#t341">341</a></span><span class="t"><span class="str"> text_decoration: Text decoration</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t342" href="#t342">342</a></span><span class="t"><span class="str"> color: Text color (name or RGB tuple)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t343" href="#t343">343</a></span><span class="t"><span class="str"> background_color: Background color</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t344" href="#t344">344</a></span><span class="t"><span class="str"> language: Language code</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t345" href="#t345">345</a></span><span class="t"><span class="str"> **kwargs: Additional style properties</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t346" href="#t346">346</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t347" href="#t347">347</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t348" href="#t348">348</a></span><span class="t"><span class="str"> Tuple of (style_id, AbstractStyle)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t349" href="#t349">349</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t350" href="#t350">350</a></span><span class="t"> <span class="nam">abstract_style</span> <span class="op">=</span> <span class="nam">AbstractStyle</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t351" href="#t351">351</a></span><span class="t"> <span class="nam">font_family</span><span class="op">=</span><span class="nam">font_family</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t352" href="#t352">352</a></span><span class="t"> <span class="nam">font_size</span><span class="op">=</span><span class="nam">font_size</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t353" href="#t353">353</a></span><span class="t"> <span class="nam">font_weight</span><span class="op">=</span><span class="nam">font_weight</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t354" href="#t354">354</a></span><span class="t"> <span class="nam">font_style</span><span class="op">=</span><span class="nam">font_style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t355" href="#t355">355</a></span><span class="t"> <span class="nam">text_decoration</span><span class="op">=</span><span class="nam">text_decoration</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t356" href="#t356">356</a></span><span class="t"> <span class="nam">color</span><span class="op">=</span><span class="nam">color</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t357" href="#t357">357</a></span><span class="t"> <span class="nam">background_color</span><span class="op">=</span><span class="nam">background_color</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t358" href="#t358">358</a></span><span class="t"> <span class="nam">language</span><span class="op">=</span><span class="nam">language</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t359" href="#t359">359</a></span><span class="t"> <span class="op">**</span><span class="nam">kwargs</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t360" href="#t360">360</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t361" href="#t361">361</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t362" href="#t362">362</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_abstract_style_registry</span><span class="op">.</span><span class="nam">get_or_create_style</span><span class="op">(</span><span class="nam">abstract_style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t363" href="#t363">363</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t364" href="#t364">364</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_font_for_style</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">abstract_style</span><span class="op">:</span> <span class="nam">AbstractStyle</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Font</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t365" href="#t365">365</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t366" href="#t366">366</a></span><span class="t"><span class="str"> Get a Font object for an AbstractStyle (for rendering).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t367" href="#t367">367</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t368" href="#t368">368</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t369" href="#t369">369</a></span><span class="t"><span class="str"> abstract_style: The abstract style to get a font for</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t370" href="#t370">370</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t371" href="#t371">371</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t372" href="#t372">372</a></span><span class="t"><span class="str"> Font object ready for rendering</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t373" href="#t373">373</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t374" href="#t374">374</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_concrete_style_registry</span><span class="op">.</span><span class="nam">get_font</span><span class="op">(</span><span class="nam">abstract_style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t375" href="#t375">375</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t376" href="#t376">376</a></span><span class="t"> <span class="key">def</span> <span class="nam">update_rendering_context</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t377" href="#t377">377</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t378" href="#t378">378</a></span><span class="t"><span class="str"> Update the rendering context (user preferences, device settings, etc.).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t379" href="#t379">379</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t380" href="#t380">380</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t381" href="#t381">381</a></span><span class="t"><span class="str"> **kwargs: Context properties to update (base_font_size, font_scale_factor, etc.)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t382" href="#t382">382</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t383" href="#t383">383</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style_resolver</span><span class="op">.</span><span class="nam">update_context</span><span class="op">(</span><span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t384" href="#t384">384</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t385" href="#t385">385</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_style_registry</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">AbstractStyleRegistry</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t386" href="#t386">386</a></span><span class="t"> <span class="str">"""Get the abstract style registry for this document."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t387" href="#t387">387</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_abstract_style_registry</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t388" href="#t388">388</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t389" href="#t389">389</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_concrete_style_registry</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">ConcreteStyleRegistry</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t390" href="#t390">390</a></span><span class="t"> <span class="str">"""Get the concrete style registry for this document."""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t391" href="#t391">391</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_concrete_style_registry</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t392" href="#t392">392</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t393" href="#t393">393</a></span><span class="t"> <span class="com"># get_or_create_font() is provided by FontRegistry mixin</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t394" href="#t394">394</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t395" href="#t395">395</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t396" href="#t396">396</a></span><span class="t"><span class="key">class</span> <span class="nam">Chapter</span><span class="op">(</span><span class="nam">FontRegistry</span><span class="op">,</span> <span class="nam">MetadataContainer</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t397" href="#t397">397</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t398" href="#t398">398</a></span><span class="t"><span class="str"> Represents a chapter or section in a document.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t399" href="#t399">399</a></span><span class="t"><span class="str"> A chapter contains a sequence of blocks and has metadata.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t400" href="#t400">400</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t401" href="#t401">401</a></span><span class="t"><span class="str"> Uses FontRegistry mixin for font caching with parent delegation.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t402" href="#t402">402</a></span><span class="t"><span class="str"> Uses MetadataContainer mixin for metadata management.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t403" href="#t403">403</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t404" href="#t404">404</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t405" href="#t405">405</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t406" href="#t406">406</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t407" href="#t407">407</a></span><span class="t"> <span class="nam">title</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t408" href="#t408">408</a></span><span class="t"> <span class="nam">level</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">1</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t409" href="#t409">409</a></span><span class="t"> <span class="nam">style</span><span class="op">=</span><span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t410" href="#t410">410</a></span><span class="t"> <span class="nam">parent</span><span class="op">=</span><span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t411" href="#t411">411</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t412" href="#t412">412</a></span><span class="t"><span class="str"> Initialize a new chapter.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t413" href="#t413">413</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t414" href="#t414">414</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t415" href="#t415">415</a></span><span class="t"><span class="str"> title: The chapter title</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t416" href="#t416">416</a></span><span class="t"><span class="str"> level: The chapter level (1 = top level, 2 = subsection, etc.)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t417" href="#t417">417</a></span><span class="t"><span class="str"> style: Optional default style for child blocks</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t418" href="#t418">418</a></span><span class="t"><span class="str"> parent: Parent container (e.g., Document or Book)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t419" href="#t419">419</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t420" href="#t420">420</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t421" href="#t421">421</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_title</span> <span class="op">=</span> <span class="nam">title</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t422" href="#t422">422</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_level</span> <span class="op">=</span> <span class="nam">level</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t423" href="#t423">423</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_blocks</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">Block</span><span class="op">]</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t424" href="#t424">424</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span> <span class="op">=</span> <span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t425" href="#t425">425</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_parent</span> <span class="op">=</span> <span class="nam">parent</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t426" href="#t426">426</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t427" href="#t427">427</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t428" href="#t428">428</a></span><span class="t"> <span class="key">def</span> <span class="nam">title</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t429" href="#t429">429</a></span><span class="t"> <span class="str">"""Get the chapter title"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t430" href="#t430">430</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_title</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t431" href="#t431">431</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t432" href="#t432">432</a></span><span class="t"> <span class="op">@</span><span class="nam">title</span><span class="op">.</span><span class="nam">setter</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t433" href="#t433">433</a></span><span class="t"> <span class="key">def</span> <span class="nam">title</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">title</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t434" href="#t434">434</a></span><span class="t"> <span class="str">"""Set the chapter title"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t435" href="#t435">435</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_title</span> <span class="op">=</span> <span class="nam">title</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t436" href="#t436">436</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t437" href="#t437">437</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t438" href="#t438">438</a></span><span class="t"> <span class="key">def</span> <span class="nam">level</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t439" href="#t439">439</a></span><span class="t"> <span class="str">"""Get the chapter level"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t440" href="#t440">440</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_level</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t441" href="#t441">441</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t442" href="#t442">442</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t443" href="#t443">443</a></span><span class="t"> <span class="key">def</span> <span class="nam">blocks</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">Block</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t444" href="#t444">444</a></span><span class="t"> <span class="str">"""Get the blocks in this chapter"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t445" href="#t445">445</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_blocks</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t446" href="#t446">446</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t447" href="#t447">447</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t448" href="#t448">448</a></span><span class="t"> <span class="key">def</span> <span class="nam">style</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t449" href="#t449">449</a></span><span class="t"> <span class="str">"""Get the default style for this chapter"""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t450" href="#t450">450</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t451" href="#t451">451</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t452" href="#t452">452</a></span><span class="t"> <span class="op">@</span><span class="nam">style</span><span class="op">.</span><span class="nam">setter</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t453" href="#t453">453</a></span><span class="t"> <span class="key">def</span> <span class="nam">style</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">style</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t454" href="#t454">454</a></span><span class="t"> <span class="str">"""Set the default style for this chapter"""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t455" href="#t455">455</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span> <span class="op">=</span> <span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t456" href="#t456">456</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t457" href="#t457">457</a></span><span class="t"> <span class="key">def</span> <span class="nam">add_block</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">block</span><span class="op">:</span> <span class="nam">Block</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t458" href="#t458">458</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t459" href="#t459">459</a></span><span class="t"><span class="str"> Add a block to this chapter.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t460" href="#t460">460</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t461" href="#t461">461</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t462" href="#t462">462</a></span><span class="t"><span class="str"> block: The block to add</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t463" href="#t463">463</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t464" href="#t464">464</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_blocks</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">block</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t465" href="#t465">465</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t466" href="#t466">466</a></span><span class="t"> <span class="key">def</span> <span class="nam">create_paragraph</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">style</span><span class="op">=</span><span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Paragraph</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t467" href="#t467">467</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t468" href="#t468">468</a></span><span class="t"><span class="str"> Create a new paragraph and add it to this chapter.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t469" href="#t469">469</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t470" href="#t470">470</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t471" href="#t471">471</a></span><span class="t"><span class="str"> style: Optional style override. If None, inherits from chapter</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t472" href="#t472">472</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t473" href="#t473">473</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t474" href="#t474">474</a></span><span class="t"><span class="str"> The newly created Paragraph object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t475" href="#t475">475</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t476" href="#t476">476</a></span><span class="t"> <span class="key">if</span> <span class="nam">style</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t477" href="#t477">477</a></span><span class="t"> <span class="nam">style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t478" href="#t478">478</a></span><span class="t"> <span class="nam">paragraph</span> <span class="op">=</span> <span class="nam">Paragraph</span><span class="op">(</span><span class="nam">style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t479" href="#t479">479</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">add_block</span><span class="op">(</span><span class="nam">paragraph</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t480" href="#t480">480</a></span><span class="t"> <span class="key">return</span> <span class="nam">paragraph</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t481" href="#t481">481</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t482" href="#t482">482</a></span><span class="t"> <span class="key">def</span> <span class="nam">create_heading</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t483" href="#t483">483</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t484" href="#t484">484</a></span><span class="t"> <span class="nam">level</span><span class="op">:</span> <span class="nam">HeadingLevel</span> <span class="op">=</span> <span class="nam">HeadingLevel</span><span class="op">.</span><span class="nam">H1</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t485" href="#t485">485</a></span><span class="t"> <span class="nam">style</span><span class="op">=</span><span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Heading</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t486" href="#t486">486</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t487" href="#t487">487</a></span><span class="t"><span class="str"> Create a new heading and add it to this chapter.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t488" href="#t488">488</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t489" href="#t489">489</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t490" href="#t490">490</a></span><span class="t"><span class="str"> level: The heading level</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t491" href="#t491">491</a></span><span class="t"><span class="str"> style: Optional style override. If None, inherits from chapter</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t492" href="#t492">492</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t493" href="#t493">493</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t494" href="#t494">494</a></span><span class="t"><span class="str"> The newly created Heading object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t495" href="#t495">495</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t496" href="#t496">496</a></span><span class="t"> <span class="key">if</span> <span class="nam">style</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t497" href="#t497">497</a></span><span class="t"> <span class="nam">style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t498" href="#t498">498</a></span><span class="t"> <span class="nam">heading</span> <span class="op">=</span> <span class="nam">Heading</span><span class="op">(</span><span class="nam">level</span><span class="op">,</span> <span class="nam">style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t499" href="#t499">499</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">add_block</span><span class="op">(</span><span class="nam">heading</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t500" href="#t500">500</a></span><span class="t"> <span class="key">return</span> <span class="nam">heading</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t501" href="#t501">501</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t502" href="#t502">502</a></span><span class="t"> <span class="com"># set_metadata() and get_metadata() are provided by MetadataContainer mixin</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t503" href="#t503">503</a></span><span class="t"> <span class="com"># get_or_create_font() is provided by FontRegistry mixin</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t504" href="#t504">504</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t505" href="#t505">505</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t506" href="#t506">506</a></span><span class="t"><span class="key">class</span> <span class="nam">Book</span><span class="op">(</span><span class="nam">Document</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t507" href="#t507">507</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t508" href="#t508">508</a></span><span class="t"><span class="str"> Abstract representation of an ebook.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t509" href="#t509">509</a></span><span class="t"><span class="str"> A book is a document that contains chapters.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t510" href="#t510">510</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t511" href="#t511">511</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t512" href="#t512">512</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">title</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span> <span class="nam">author</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t513" href="#t513">513</a></span><span class="t"> <span class="nam">language</span><span class="op">:</span> <span class="nam">str</span> <span class="op">=</span> <span class="str">"en-US"</span><span class="op">,</span> <span class="nam">default_style</span><span class="op">=</span><span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t514" href="#t514">514</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t515" href="#t515">515</a></span><span class="t"><span class="str"> Initialize a new book.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t516" href="#t516">516</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t517" href="#t517">517</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t518" href="#t518">518</a></span><span class="t"><span class="str"> title: The book title</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t519" href="#t519">519</a></span><span class="t"><span class="str"> author: The book author</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t520" href="#t520">520</a></span><span class="t"><span class="str"> language: The book language code</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t521" href="#t521">521</a></span><span class="t"><span class="str"> default_style: Optional default style for child chapters and blocks</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t522" href="#t522">522</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t523" href="#t523">523</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="nam">title</span><span class="op">,</span> <span class="nam">language</span><span class="op">,</span> <span class="nam">default_style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t524" href="#t524">524</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_chapters</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">Chapter</span><span class="op">]</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t525" href="#t525">525</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t526" href="#t526">526</a></span><span class="t"> <span class="key">if</span> <span class="nam">author</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t527" href="#t527">527</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">set_metadata</span><span class="op">(</span><span class="nam">MetadataType</span><span class="op">.</span><span class="nam">AUTHOR</span><span class="op">,</span> <span class="nam">author</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t528" href="#t528">528</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t529" href="#t529">529</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t530" href="#t530">530</a></span><span class="t"> <span class="key">def</span> <span class="nam">chapters</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">Chapter</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t531" href="#t531">531</a></span><span class="t"> <span class="str">"""Get the chapters in this book"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t532" href="#t532">532</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_chapters</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t533" href="#t533">533</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t534" href="#t534">534</a></span><span class="t"> <span class="key">def</span> <span class="nam">add_chapter</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">chapter</span><span class="op">:</span> <span class="nam">Chapter</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t535" href="#t535">535</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t536" href="#t536">536</a></span><span class="t"><span class="str"> Add a chapter to this book.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t537" href="#t537">537</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t538" href="#t538">538</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t539" href="#t539">539</a></span><span class="t"><span class="str"> chapter: The chapter to add</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t540" href="#t540">540</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t541" href="#t541">541</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_chapters</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">chapter</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t542" href="#t542">542</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t543" href="#t543">543</a></span><span class="t"> <span class="key">def</span> <span class="nam">create_chapter</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t544" href="#t544">544</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t545" href="#t545">545</a></span><span class="t"> <span class="nam">title</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t546" href="#t546">546</a></span><span class="t"> <span class="nam">level</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">1</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t547" href="#t547">547</a></span><span class="t"> <span class="nam">style</span><span class="op">=</span><span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Chapter</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t548" href="#t548">548</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t549" href="#t549">549</a></span><span class="t"><span class="str"> Create and add a new chapter with inherited style.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t550" href="#t550">550</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t551" href="#t551">551</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t552" href="#t552">552</a></span><span class="t"><span class="str"> title: The chapter title</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t553" href="#t553">553</a></span><span class="t"><span class="str"> level: The chapter level</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t554" href="#t554">554</a></span><span class="t"><span class="str"> style: Optional style override. If None, inherits from book</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t555" href="#t555">555</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t556" href="#t556">556</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t557" href="#t557">557</a></span><span class="t"><span class="str"> The new chapter</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t558" href="#t558">558</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t559" href="#t559">559</a></span><span class="t"> <span class="key">if</span> <span class="nam">style</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">559&#x202F;&#x219B;&#x202F;561</span><span class="annotate long">line 559 didn't jump to line 561 because the condition on line 559 was always true</span></span></p>
<p class="run"><span class="n"><a id="t560" href="#t560">560</a></span><span class="t"> <span class="nam">style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_default_style</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t561" href="#t561">561</a></span><span class="t"> <span class="nam">chapter</span> <span class="op">=</span> <span class="nam">Chapter</span><span class="op">(</span><span class="nam">title</span><span class="op">,</span> <span class="nam">level</span><span class="op">,</span> <span class="nam">style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t562" href="#t562">562</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">add_chapter</span><span class="op">(</span><span class="nam">chapter</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t563" href="#t563">563</a></span><span class="t"> <span class="key">return</span> <span class="nam">chapter</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t564" href="#t564">564</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t565" href="#t565">565</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_author</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t566" href="#t566">566</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t567" href="#t567">567</a></span><span class="t"><span class="str"> Get the book author.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t568" href="#t568">568</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t569" href="#t569">569</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t570" href="#t570">570</a></span><span class="t"><span class="str"> The book author, or None if not set</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t571" href="#t571">571</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t572" href="#t572">572</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_metadata</span><span class="op">(</span><span class="nam">MetadataType</span><span class="op">.</span><span class="nam">AUTHOR</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t573" href="#t573">573</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t574" href="#t574">574</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_author</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">author</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t575" href="#t575">575</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t576" href="#t576">576</a></span><span class="t"><span class="str"> Set the book author.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t577" href="#t577">577</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t578" href="#t578">578</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t579" href="#t579">579</a></span><span class="t"><span class="str"> author: The book author</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t580" href="#t580">580</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t581" href="#t581">581</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">set_metadata</span><span class="op">(</span><span class="nam">MetadataType</span><span class="op">.</span><span class="nam">AUTHOR</span><span class="op">,</span> <span class="nam">author</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t582" href="#t582">582</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t583" href="#t583">583</a></span><span class="t"> <span class="key">def</span> <span class="nam">generate_table_of_contents</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">str</span><span class="op">,</span> <span class="nam">Chapter</span><span class="op">]</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t584" href="#t584">584</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t585" href="#t585">585</a></span><span class="t"><span class="str"> Generate a table of contents from chapters.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t586" href="#t586">586</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t587" href="#t587">587</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t588" href="#t588">588</a></span><span class="t"><span class="str"> A list of tuples containing (level, title, chapter)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t589" href="#t589">589</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t590" href="#t590">590</a></span><span class="t"> <span class="nam">toc</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t591" href="#t591">591</a></span><span class="t"> <span class="key">for</span> <span class="nam">chapter</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_chapters</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t592" href="#t592">592</a></span><span class="t"> <span class="key">if</span> <span class="nam">chapter</span><span class="op">.</span><span class="nam">title</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t593" href="#t593">593</a></span><span class="t"> <span class="nam">toc</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="op">(</span><span class="nam">chapter</span><span class="op">.</span><span class="nam">level</span><span class="op">,</span> <span class="nam">chapter</span><span class="op">.</span><span class="nam">title</span><span class="op">,</span> <span class="nam">chapter</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t594" href="#t594">594</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t595" href="#t595">595</a></span><span class="t"> <span class="key">return</span> <span class="nam">toc</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_af715639580e2d86_block_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_af715639580e2d86_functional_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,444 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/abstract/functional.py: 98%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/abstract/functional.py</b>:
<span class="pc_cov">98%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">144 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">141<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">3<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">39<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">0<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_af715639580e2d86_document_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_af715639580e2d86_inline_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="run"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="key">from</span> <span class="nam">__future__</span> <span class="key">import</span> <span class="nam">annotations</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="key">from</span> <span class="nam">enum</span> <span class="key">import</span> <span class="nam">Enum</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">Callable</span><span class="op">,</span> <span class="nam">Dict</span><span class="op">,</span> <span class="nam">Any</span><span class="op">,</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">List</span><span class="op">,</span> <span class="nam">Tuple</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">core</span><span class="op">.</span><span class="nam">base</span> <span class="key">import</span> <span class="nam">Interactable</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="key">class</span> <span class="nam">LinkType</span><span class="op">(</span><span class="nam">Enum</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"> <span class="str">"""Enumeration of different types of links for classification purposes"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"> <span class="nam">INTERNAL</span> <span class="op">=</span> <span class="num">1</span> <span class="com"># Links within the same document (e.g., chapter references, bookmarks)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"> <span class="nam">EXTERNAL</span> <span class="op">=</span> <span class="num">2</span> <span class="com"># Links to external resources (e.g., websites, other documents)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"> <span class="nam">API</span> <span class="op">=</span> <span class="num">3</span> <span class="com"># Links that trigger API calls (e.g., for settings management)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"> <span class="nam">FUNCTION</span> <span class="op">=</span> <span class="num">4</span> <span class="com"># Links that execute a specific function</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"><span class="key">class</span> <span class="nam">Link</span><span class="op">(</span><span class="nam">Interactable</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"><span class="str"> A link that can navigate to a location or execute a function.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"><span class="str"> Links can be used for navigation within a document, to external resources,</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"><span class="str"> or to trigger API calls for functionality like settings management.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"> <span class="nam">location</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"> <span class="nam">link_type</span><span class="op">:</span> <span class="nam">LinkType</span> <span class="op">=</span> <span class="nam">LinkType</span><span class="op">.</span><span class="nam">INTERNAL</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"> <span class="nam">callback</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Callable</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"> <span class="nam">params</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"> <span class="nam">title</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t"> <span class="nam">html_id</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"><span class="str"> Initialize a link.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"><span class="str"> location: The target location or identifier for this link</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"><span class="str"> link_type: The type of link (internal, external, API, function)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"><span class="str"> callback: Optional callback function to execute when the link is activated</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"><span class="str"> params: Optional parameters to pass to the callback or API</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"><span class="str"> title: Optional title/tooltip for the link</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t"><span class="str"> html_id: Optional HTML id attribute (from &lt;a id="...">) for callback binding</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="nam">callback</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_location</span> <span class="op">=</span> <span class="nam">location</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_link_type</span> <span class="op">=</span> <span class="nam">link_type</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_params</span> <span class="op">=</span> <span class="nam">params</span> <span class="key">or</span> <span class="op">{</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_title</span> <span class="op">=</span> <span class="nam">title</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_html_id</span> <span class="op">=</span> <span class="nam">html_id</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"> <span class="key">def</span> <span class="nam">location</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">str</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t"> <span class="str">"""Get the target location of this link"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_location</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"> <span class="key">def</span> <span class="nam">link_type</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">LinkType</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t"> <span class="str">"""Get the type of this link"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_link_type</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t"> <span class="key">def</span> <span class="nam">params</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"> <span class="str">"""Get the parameters for this link"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_params</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t"> <span class="key">def</span> <span class="nam">title</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"> <span class="str">"""Get the title/tooltip for this link"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_title</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"> <span class="key">def</span> <span class="nam">html_id</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"> <span class="str">"""Get the HTML id attribute for callback binding"""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_html_id</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t"> <span class="key">def</span> <span class="nam">execute</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">point</span><span class="op">=</span><span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Any</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t"><span class="str"> Execute the link action based on its type.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t"><span class="str"> For internal and external links, returns the location.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t"><span class="str"> For API and function links, executes the callback with the provided parameters.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t"><span class="str"> point: Optional interaction point passed from the interact() method</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t"><span class="str"> The result of the link execution, which depends on the link type.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_link_type</span> <span class="key">in</span> <span class="op">(</span><span class="nam">LinkType</span><span class="op">.</span><span class="nam">API</span><span class="op">,</span> <span class="nam">LinkType</span><span class="op">.</span><span class="nam">FUNCTION</span><span class="op">)</span> <span class="key">and</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_callback</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_callback</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_location</span><span class="op">,</span> <span class="nam">point</span><span class="op">,</span> <span class="op">**</span><span class="nam">self</span><span class="op">.</span><span class="nam">_params</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t"> <span class="com"># For INTERNAL and EXTERNAL links, return the location</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"> <span class="com"># The renderer/browser will handle the navigation</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_location</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t"><span class="key">class</span> <span class="nam">Button</span><span class="op">(</span><span class="nam">Interactable</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t"><span class="str"> A button that can be clicked to execute an action.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t"><span class="str"> Buttons are similar to function links but are rendered differently.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t"> <span class="nam">label</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"> <span class="nam">callback</span><span class="op">:</span> <span class="nam">Callable</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"> <span class="nam">params</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t"> <span class="nam">enabled</span><span class="op">:</span> <span class="nam">bool</span> <span class="op">=</span> <span class="key">True</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t"> <span class="nam">html_id</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t"><span class="str"> Initialize a button.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t"><span class="str"> label: The text label for the button</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"><span class="str"> callback: The function to execute when the button is clicked</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t"><span class="str"> params: Optional parameters to pass to the callback</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"><span class="str"> enabled: Whether the button is initially enabled</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t"><span class="str"> html_id: Optional HTML id attribute (from &lt;button id="...">) for callback binding</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="nam">callback</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_label</span> <span class="op">=</span> <span class="nam">label</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_params</span> <span class="op">=</span> <span class="nam">params</span> <span class="key">or</span> <span class="op">{</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_enabled</span> <span class="op">=</span> <span class="nam">enabled</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_html_id</span> <span class="op">=</span> <span class="nam">html_id</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t"> <span class="key">def</span> <span class="nam">label</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">str</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"> <span class="str">"""Get the button label"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_label</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t"> <span class="op">@</span><span class="nam">label</span><span class="op">.</span><span class="nam">setter</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t"> <span class="key">def</span> <span class="nam">label</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">label</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t"> <span class="str">"""Set the button label"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_label</span> <span class="op">=</span> <span class="nam">label</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t"> <span class="key">def</span> <span class="nam">enabled</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t"> <span class="str">"""Check if the button is enabled"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_enabled</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"> <span class="op">@</span><span class="nam">enabled</span><span class="op">.</span><span class="nam">setter</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t"> <span class="key">def</span> <span class="nam">enabled</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">enabled</span><span class="op">:</span> <span class="nam">bool</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"> <span class="str">"""Enable or disable the button"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_enabled</span> <span class="op">=</span> <span class="nam">enabled</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t"> <span class="key">def</span> <span class="nam">params</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t"> <span class="str">"""Get the button parameters"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_params</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"> <span class="key">def</span> <span class="nam">html_id</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"> <span class="str">"""Get the HTML id attribute for callback binding"""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_html_id</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t"> <span class="key">def</span> <span class="nam">execute</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">point</span><span class="op">=</span><span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Any</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t"><span class="str"> Execute the button's callback function if the button is enabled.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t"><span class="str"> point: Optional interaction point passed from the interact() method</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t"><span class="str"> The result of the callback function, or None if the button is disabled.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_enabled</span> <span class="key">and</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_callback</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_callback</span><span class="op">(</span><span class="nam">point</span><span class="op">,</span> <span class="op">**</span><span class="nam">self</span><span class="op">.</span><span class="nam">_params</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"><span class="key">class</span> <span class="nam">Form</span><span class="op">(</span><span class="nam">Interactable</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t"><span class="str"> A form that can contain input fields and be submitted.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t"><span class="str"> Forms can be used for user input and settings configuration.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t"> <span class="nam">form_id</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t"> <span class="nam">action</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t"> <span class="nam">callback</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Callable</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t"> <span class="nam">html_id</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t"><span class="str"> Initialize a form.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t"><span class="str"> form_id: The unique identifier for this form</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t"><span class="str"> action: The action URL or endpoint for form submission</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t"><span class="str"> callback: Optional callback function to execute on form submission</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t"><span class="str"> html_id: Optional HTML id attribute (from &lt;form id="...">) for callback binding</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="nam">callback</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_form_id</span> <span class="op">=</span> <span class="nam">form_id</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_action</span> <span class="op">=</span> <span class="nam">action</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_fields</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">FormField</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_html_id</span> <span class="op">=</span> <span class="nam">html_id</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t"> <span class="key">def</span> <span class="nam">form_id</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">str</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t"> <span class="str">"""Get the form ID"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_form_id</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t"> <span class="key">def</span> <span class="nam">action</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t"> <span class="str">"""Get the form action"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_action</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t"> <span class="key">def</span> <span class="nam">html_id</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t"> <span class="str">"""Get the HTML id attribute for callback binding"""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_html_id</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t"> <span class="key">def</span> <span class="nam">add_field</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">field</span><span class="op">:</span> <span class="nam">FormField</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t"><span class="str"> Add a field to this form.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t"><span class="str"> field: The FormField to add</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_fields</span><span class="op">[</span><span class="nam">field</span><span class="op">.</span><span class="nam">name</span><span class="op">]</span> <span class="op">=</span> <span class="nam">field</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t"> <span class="nam">field</span><span class="op">.</span><span class="nam">form</span> <span class="op">=</span> <span class="nam">self</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_field</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">name</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">FormField</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t"><span class="str"> Get a field by name.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"><span class="str"> name: The name of the field to get</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t"><span class="str"> The FormField with the specified name, or None if not found</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_fields</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="nam">name</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_values</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t"><span class="str"> Get the current values of all fields in this form.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t"><span class="str"> A dictionary mapping field names to their current values</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t"> <span class="key">return</span> <span class="op">{</span><span class="nam">name</span><span class="op">:</span> <span class="nam">field</span><span class="op">.</span><span class="nam">value</span> <span class="key">for</span> <span class="nam">name</span><span class="op">,</span> <span class="nam">field</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_fields</span><span class="op">.</span><span class="nam">items</span><span class="op">(</span><span class="op">)</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t"> <span class="key">def</span> <span class="nam">execute</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Any</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t"><span class="str"> Submit the form, executing the callback with the form values.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t"><span class="str"> The result of the callback function, or the form values if no callback is provided.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t"> <span class="nam">values</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_values</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_callback</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_callback</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_form_id</span><span class="op">,</span> <span class="nam">values</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t"> <span class="key">return</span> <span class="nam">values</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t"><span class="key">class</span> <span class="nam">FormFieldType</span><span class="op">(</span><span class="nam">Enum</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t"> <span class="str">"""Enumeration of different types of form fields"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t"> <span class="nam">TEXT</span> <span class="op">=</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t"> <span class="nam">PASSWORD</span> <span class="op">=</span> <span class="num">2</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t"> <span class="nam">CHECKBOX</span> <span class="op">=</span> <span class="num">3</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t"> <span class="nam">RADIO</span> <span class="op">=</span> <span class="num">4</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t"> <span class="nam">SELECT</span> <span class="op">=</span> <span class="num">5</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t"> <span class="nam">TEXTAREA</span> <span class="op">=</span> <span class="num">6</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t"> <span class="nam">NUMBER</span> <span class="op">=</span> <span class="num">7</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t"> <span class="nam">DATE</span> <span class="op">=</span> <span class="num">8</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t"> <span class="nam">TIME</span> <span class="op">=</span> <span class="num">9</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t"> <span class="nam">EMAIL</span> <span class="op">=</span> <span class="num">10</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t"> <span class="nam">URL</span> <span class="op">=</span> <span class="num">11</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t"> <span class="nam">COLOR</span> <span class="op">=</span> <span class="num">12</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t"> <span class="nam">RANGE</span> <span class="op">=</span> <span class="num">13</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t"> <span class="nam">HIDDEN</span> <span class="op">=</span> <span class="num">14</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t"><span class="key">class</span> <span class="nam">FormField</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t"><span class="str"> A field in a form that can accept user input.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t"> <span class="nam">name</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t"> <span class="nam">field_type</span><span class="op">:</span> <span class="nam">FormFieldType</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t279" href="#t279">279</a></span><span class="t"> <span class="nam">label</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t280" href="#t280">280</a></span><span class="t"> <span class="nam">value</span><span class="op">:</span> <span class="nam">Any</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t281" href="#t281">281</a></span><span class="t"> <span class="nam">required</span><span class="op">:</span> <span class="nam">bool</span> <span class="op">=</span> <span class="key">False</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t282" href="#t282">282</a></span><span class="t"> <span class="nam">options</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">List</span><span class="op">[</span><span class="nam">Tuple</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">str</span><span class="op">]</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t283" href="#t283">283</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t284" href="#t284">284</a></span><span class="t"><span class="str"> Initialize a form field.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t285" href="#t285">285</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t286" href="#t286">286</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t287" href="#t287">287</a></span><span class="t"><span class="str"> name: The name of this field</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t288" href="#t288">288</a></span><span class="t"><span class="str"> field_type: The type of this field</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t289" href="#t289">289</a></span><span class="t"><span class="str"> label: Optional label for this field</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t290" href="#t290">290</a></span><span class="t"><span class="str"> value: Initial value for this field</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t291" href="#t291">291</a></span><span class="t"><span class="str"> required: Whether this field is required</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t292" href="#t292">292</a></span><span class="t"><span class="str"> options: Options for select, radio, or checkbox fields (list of (value, label) tuples)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t293" href="#t293">293</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t294" href="#t294">294</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_name</span> <span class="op">=</span> <span class="nam">name</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t295" href="#t295">295</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_field_type</span> <span class="op">=</span> <span class="nam">field_type</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t296" href="#t296">296</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_label</span> <span class="op">=</span> <span class="nam">label</span> <span class="key">or</span> <span class="nam">name</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t297" href="#t297">297</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_value</span> <span class="op">=</span> <span class="nam">value</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t298" href="#t298">298</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_required</span> <span class="op">=</span> <span class="nam">required</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t299" href="#t299">299</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_options</span> <span class="op">=</span> <span class="nam">options</span> <span class="key">or</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t300" href="#t300">300</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_form</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Form</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t301" href="#t301">301</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t302" href="#t302">302</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t303" href="#t303">303</a></span><span class="t"> <span class="key">def</span> <span class="nam">name</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">str</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t304" href="#t304">304</a></span><span class="t"> <span class="str">"""Get the field name"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t305" href="#t305">305</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_name</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t306" href="#t306">306</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t307" href="#t307">307</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t308" href="#t308">308</a></span><span class="t"> <span class="key">def</span> <span class="nam">field_type</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">FormFieldType</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t309" href="#t309">309</a></span><span class="t"> <span class="str">"""Get the field type"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t310" href="#t310">310</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_field_type</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t311" href="#t311">311</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t312" href="#t312">312</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t313" href="#t313">313</a></span><span class="t"> <span class="key">def</span> <span class="nam">label</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">str</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t314" href="#t314">314</a></span><span class="t"> <span class="str">"""Get the field label"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t315" href="#t315">315</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_label</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t316" href="#t316">316</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t317" href="#t317">317</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t318" href="#t318">318</a></span><span class="t"> <span class="key">def</span> <span class="nam">value</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Any</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t319" href="#t319">319</a></span><span class="t"> <span class="str">"""Get the current field value"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t320" href="#t320">320</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_value</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t321" href="#t321">321</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t322" href="#t322">322</a></span><span class="t"> <span class="op">@</span><span class="nam">value</span><span class="op">.</span><span class="nam">setter</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t323" href="#t323">323</a></span><span class="t"> <span class="key">def</span> <span class="nam">value</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">value</span><span class="op">:</span> <span class="nam">Any</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t324" href="#t324">324</a></span><span class="t"> <span class="str">"""Set the field value"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t325" href="#t325">325</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_value</span> <span class="op">=</span> <span class="nam">value</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t326" href="#t326">326</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t327" href="#t327">327</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t328" href="#t328">328</a></span><span class="t"> <span class="key">def</span> <span class="nam">required</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t329" href="#t329">329</a></span><span class="t"> <span class="str">"""Check if the field is required"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t330" href="#t330">330</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_required</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t331" href="#t331">331</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t332" href="#t332">332</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t333" href="#t333">333</a></span><span class="t"> <span class="key">def</span> <span class="nam">options</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">Tuple</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">str</span><span class="op">]</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t334" href="#t334">334</a></span><span class="t"> <span class="str">"""Get the field options"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t335" href="#t335">335</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_options</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t336" href="#t336">336</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t337" href="#t337">337</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t338" href="#t338">338</a></span><span class="t"> <span class="key">def</span> <span class="nam">form</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Form</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t339" href="#t339">339</a></span><span class="t"> <span class="str">"""Get the form containing this field"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t340" href="#t340">340</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_form</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t341" href="#t341">341</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t342" href="#t342">342</a></span><span class="t"> <span class="op">@</span><span class="nam">form</span><span class="op">.</span><span class="nam">setter</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t343" href="#t343">343</a></span><span class="t"> <span class="key">def</span> <span class="nam">form</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">form</span><span class="op">:</span> <span class="nam">Form</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t344" href="#t344">344</a></span><span class="t"> <span class="str">"""Set the form containing this field"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t345" href="#t345">345</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_form</span> <span class="op">=</span> <span class="nam">form</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_af715639580e2d86_document_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_af715639580e2d86_inline_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,519 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/abstract/inline.py: 99%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/abstract/inline.py</b>:
<span class="pc_cov">99%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">157 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">156<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">1<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">29<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">1<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_af715639580e2d86_functional_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_af715639580e2d86_interactive_image_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="run"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="key">from</span> <span class="nam">__future__</span> <span class="key">import</span> <span class="nam">annotations</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">core</span> <span class="key">import</span> <span class="nam">Hierarchical</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span> <span class="key">import</span> <span class="nam">Font</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">abstract_style</span> <span class="key">import</span> <span class="nam">AbstractStyle</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">Tuple</span><span class="op">,</span> <span class="nam">Union</span><span class="op">,</span> <span class="nam">List</span><span class="op">,</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">Dict</span><span class="op">,</span> <span class="nam">Any</span><span class="op">,</span> <span class="nam">Callable</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="key">import</span> <span class="nam">pyphen</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="com"># Import LinkType for type hints (imported at module level to avoid F821 linting error)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">abstract</span><span class="op">.</span><span class="nam">functional</span> <span class="key">import</span> <span class="nam">LinkType</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="key">class</span> <span class="nam">Word</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t"><span class="str"> An abstract representation of a word in a document. Words can be split across</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"><span class="str"> lines or pages during rendering. This class manages the logical representation</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"><span class="str"> of a word without any rendering specifics.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"><span class="str"> Now uses AbstractStyle objects for memory efficiency and proper style management.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"> <span class="nam">text</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"> <span class="nam">style</span><span class="op">:</span> <span class="nam">Union</span><span class="op">[</span><span class="nam">Font</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"> <span class="nam">AbstractStyle</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"> <span class="nam">background</span><span class="op">=</span><span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"> <span class="nam">previous</span><span class="op">:</span> <span class="nam">Union</span><span class="op">[</span><span class="str">'Word'</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"> <span class="key">None</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"><span class="str"> Initialize a new Word.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"><span class="str"> text: The text content of the word</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"><span class="str"> style: AbstractStyle object or Font object (for backward compatibility)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"><span class="str"> background: Optional background color override</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"><span class="str"> previous: Reference to the previous word in sequence</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_text</span> <span class="op">=</span> <span class="nam">text</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span> <span class="op">=</span> <span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_background</span> <span class="op">=</span> <span class="nam">background</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_previous</span> <span class="op">=</span> <span class="nam">previous</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_next</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">concrete</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t"> <span class="key">if</span> <span class="nam">previous</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"> <span class="nam">previous</span><span class="op">.</span><span class="nam">add_next</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"> <span class="op">@</span><span class="nam">classmethod</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"> <span class="key">def</span> <span class="nam">create_and_add_to</span><span class="op">(</span><span class="nam">cls</span><span class="op">,</span> <span class="nam">text</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span> <span class="nam">container</span><span class="op">,</span> <span class="nam">style</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Font</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"> <span class="nam">background</span><span class="op">=</span><span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="str">'Word'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"><span class="str"> Create a new Word and add it to a container, inheriting style and language</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t"><span class="str"> from the container if not explicitly provided.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"><span class="str"> This method provides a convenient way to create words that automatically</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t"><span class="str"> inherit styling from their container (Paragraph, FormattedSpan, etc.)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"><span class="str"> without copying string values - using object references instead.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t"><span class="str"> text: The text content of the word</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"><span class="str"> container: The container to add the word to (must have add_word method and style property)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"><span class="str"> style: Optional Font style override. If None, inherits from container</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"><span class="str"> background: Optional background color override. If None, inherits from container</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"><span class="str"> The newly created Word object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t"><span class="str"> Raises:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t"><span class="str"> AttributeError: If the container doesn't have the required add_word method or style property</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"> <span class="com"># Inherit style from container if not provided</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t"> <span class="key">if</span> <span class="nam">style</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">container</span><span class="op">,</span> <span class="str">'style'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t"> <span class="nam">style</span> <span class="op">=</span> <span class="nam">container</span><span class="op">.</span><span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t"> <span class="key">raise</span> <span class="nam">AttributeError</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"> <span class="fst">f"</span><span class="fst">Container </span><span class="op">{</span><span class="nam">type</span><span class="op">(</span><span class="nam">container</span><span class="op">)</span><span class="op">.</span><span class="nam">__name__</span><span class="op">}</span><span class="fst"> must have a 'style' property</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t"> <span class="com"># Inherit background from container if not provided</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"> <span class="key">if</span> <span class="nam">background</span> <span class="key">is</span> <span class="key">None</span> <span class="key">and</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">container</span><span class="op">,</span> <span class="str">'background'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t"> <span class="nam">background</span> <span class="op">=</span> <span class="nam">container</span><span class="op">.</span><span class="nam">background</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t"> <span class="com"># Determine the previous word for proper linking</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t"> <span class="nam">previous</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">container</span><span class="op">,</span> <span class="str">'_words'</span><span class="op">)</span> <span class="key">and</span> <span class="nam">container</span><span class="op">.</span><span class="nam">_words</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"> <span class="com"># Container has a _words list (like FormattedSpan)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t"> <span class="nam">previous</span> <span class="op">=</span> <span class="nam">container</span><span class="op">.</span><span class="nam">_words</span><span class="op">[</span><span class="op">-</span><span class="num">1</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t"> <span class="key">elif</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">container</span><span class="op">,</span> <span class="str">'words'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t"> <span class="com"># Container has a words() method (like Paragraph)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"> <span class="com"># Get the last word from the iterator</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t"> <span class="key">for</span> <span class="nam">_</span><span class="op">,</span> <span class="nam">word</span> <span class="key">in</span> <span class="nam">container</span><span class="op">.</span><span class="nam">words</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t"> <span class="nam">previous</span> <span class="op">=</span> <span class="nam">word</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t"> <span class="key">except</span> <span class="op">(</span><span class="nam">StopIteration</span><span class="op">,</span> <span class="nam">TypeError</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t"> <span class="nam">previous</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t"> <span class="com"># Create the new word</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t"> <span class="nam">word</span> <span class="op">=</span> <span class="nam">cls</span><span class="op">(</span><span class="nam">text</span><span class="op">,</span> <span class="nam">style</span><span class="op">,</span> <span class="nam">background</span><span class="op">,</span> <span class="nam">previous</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t"> <span class="com"># Link the previous word to this new one</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"> <span class="key">if</span> <span class="nam">previous</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t"> <span class="nam">previous</span><span class="op">.</span><span class="nam">add_next</span><span class="op">(</span><span class="nam">word</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"> <span class="com"># Add the word to the container</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">container</span><span class="op">,</span> <span class="str">'add_word'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t"> <span class="com"># Check if add_word expects a Word object or text string</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t"> <span class="key">import</span> <span class="nam">inspect</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t"> <span class="nam">sig</span> <span class="op">=</span> <span class="nam">inspect</span><span class="op">.</span><span class="nam">signature</span><span class="op">(</span><span class="nam">container</span><span class="op">.</span><span class="nam">add_word</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t"> <span class="nam">params</span> <span class="op">=</span> <span class="nam">list</span><span class="op">(</span><span class="nam">sig</span><span class="op">.</span><span class="nam">parameters</span><span class="op">.</span><span class="nam">keys</span><span class="op">(</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t"> <span class="key">if</span> <span class="nam">len</span><span class="op">(</span><span class="nam">params</span><span class="op">)</span> <span class="op">></span> <span class="num">0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"> <span class="com"># Peek at the parameter name to guess the expected type</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t"> <span class="nam">param_name</span> <span class="op">=</span> <span class="nam">params</span><span class="op">[</span><span class="num">0</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"> <span class="key">if</span> <span class="nam">param_name</span> <span class="key">in</span> <span class="op">[</span><span class="str">'word'</span><span class="op">,</span> <span class="str">'word_obj'</span><span class="op">,</span> <span class="str">'word_object'</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t"> <span class="com"># Expects a Word object</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t"> <span class="nam">container</span><span class="op">.</span><span class="nam">add_word</span><span class="op">(</span><span class="nam">word</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"> <span class="com"># Might expect text string (like FormattedSpan.add_word)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t"> <span class="com"># In this case, we can't use the container's add_word as it would create</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t"> <span class="com"># a duplicate Word. We need to add directly to the container's word</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"> <span class="com"># list.</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">container</span><span class="op">,</span> <span class="str">'_words'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t"> <span class="nam">container</span><span class="op">.</span><span class="nam">_words</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">word</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"> <span class="com"># Fallback: try calling with the Word object anyway</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t"> <span class="nam">container</span><span class="op">.</span><span class="nam">add_word</span><span class="op">(</span><span class="nam">word</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t"> <span class="com"># No parameters, shouldn't happen with add_word methods</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t"> <span class="nam">container</span><span class="op">.</span><span class="nam">add_word</span><span class="op">(</span><span class="nam">word</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t"> <span class="key">raise</span> <span class="nam">AttributeError</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t"> <span class="fst">f"</span><span class="fst">Container </span><span class="op">{</span><span class="nam">type</span><span class="op">(</span><span class="nam">container</span><span class="op">)</span><span class="op">.</span><span class="nam">__name__</span><span class="op">}</span><span class="fst"> must have an 'add_word' method</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t"> <span class="key">return</span> <span class="nam">word</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t"> <span class="key">def</span> <span class="nam">add_concete</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">text</span><span class="op">:</span> <span class="nam">Union</span><span class="op">[</span><span class="nam">Any</span><span class="op">,</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">Any</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">]</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">concrete</span> <span class="op">=</span> <span class="nam">text</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"> <span class="key">def</span> <span class="nam">text</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">str</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t"> <span class="str">"""Get the text content of the word"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_text</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t"> <span class="key">def</span> <span class="nam">style</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Font</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"> <span class="str">"""Get the font style of the word"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"> <span class="key">def</span> <span class="nam">background</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t"> <span class="str">"""Get the background color of the word"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_background</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t"> <span class="key">def</span> <span class="nam">previous</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Union</span><span class="op">[</span><span class="str">'Word'</span><span class="op">,</span> <span class="key">None</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t"> <span class="str">"""Get the previous word in sequence"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_previous</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t"> <span class="key">def</span> <span class="nam">next</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Union</span><span class="op">[</span><span class="str">'Word'</span><span class="op">,</span> <span class="key">None</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t"> <span class="str">"""Get the next word in sequence"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_next</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t"> <span class="key">def</span> <span class="nam">add_next</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">next_word</span><span class="op">:</span> <span class="str">'Word'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"> <span class="str">"""Set the next word in sequence"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_next</span> <span class="op">=</span> <span class="nam">next_word</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"> <span class="key">def</span> <span class="nam">possible_hyphenation</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">language</span><span class="op">:</span> <span class="nam">str</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t"><span class="str"> Hyphenate the word and store the parts.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t"><span class="str"> language: Language code for hyphenation. If None, uses the style's language.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t"><span class="str"> bool: True if the word was hyphenated, False otherwise.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t"> <span class="nam">dic</span> <span class="op">=</span> <span class="nam">pyphen</span><span class="op">.</span><span class="nam">Pyphen</span><span class="op">(</span><span class="nam">lang</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">.</span><span class="nam">language</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t"> <span class="key">return</span> <span class="nam">list</span><span class="op">(</span><span class="nam">dic</span><span class="op">.</span><span class="nam">iterate</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_text</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t"><span class="op">...</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t"><span class="key">class</span> <span class="nam">FormattedSpan</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t"><span class="str"> A run of words with consistent formatting.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t"><span class="str"> This represents a sequence of words that share the same style attributes.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">style</span><span class="op">:</span> <span class="nam">Font</span><span class="op">,</span> <span class="nam">background</span><span class="op">=</span><span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t"><span class="str"> Initialize a new formatted span.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t"><span class="str"> style: Font style information for all words in this span</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t"><span class="str"> background: Optional background color override</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span> <span class="op">=</span> <span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_background</span> <span class="op">=</span> <span class="nam">background</span> <span class="key">if</span> <span class="nam">background</span> <span class="key">else</span> <span class="nam">style</span><span class="op">.</span><span class="nam">background</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_words</span><span class="op">:</span> <span class="nam">List</span><span class="op">[</span><span class="nam">Word</span><span class="op">]</span> <span class="op">=</span> <span class="op">[</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t"> <span class="op">@</span><span class="nam">classmethod</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t"> <span class="key">def</span> <span class="nam">create_and_add_to</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t"> <span class="nam">cls</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t"> <span class="nam">container</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t"> <span class="nam">style</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Font</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t"> <span class="nam">background</span><span class="op">=</span><span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="str">'FormattedSpan'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t"><span class="str"> Create a new FormattedSpan and add it to a container, inheriting style from</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t"><span class="str"> the container if not explicitly provided.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"><span class="str"> container: The container to add the span to (must have add_span method and style property)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t"><span class="str"> style: Optional Font style override. If None, inherits from container</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t"><span class="str"> background: Optional background color override</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t"><span class="str"> The newly created FormattedSpan object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t"><span class="str"> Raises:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t"><span class="str"> AttributeError: If the container doesn't have the required add_span method or style property</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t"> <span class="com"># Inherit style from container if not provided</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t"> <span class="key">if</span> <span class="nam">style</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">container</span><span class="op">,</span> <span class="str">'style'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t"> <span class="nam">style</span> <span class="op">=</span> <span class="nam">container</span><span class="op">.</span><span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t"> <span class="key">raise</span> <span class="nam">AttributeError</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t"> <span class="fst">f"</span><span class="fst">Container </span><span class="op">{</span><span class="nam">type</span><span class="op">(</span><span class="nam">container</span><span class="op">)</span><span class="op">.</span><span class="nam">__name__</span><span class="op">}</span><span class="fst"> must have a 'style' property</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t"> <span class="com"># Inherit background from container if not provided</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t"> <span class="key">if</span> <span class="nam">background</span> <span class="key">is</span> <span class="key">None</span> <span class="key">and</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">container</span><span class="op">,</span> <span class="str">'background'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t"> <span class="nam">background</span> <span class="op">=</span> <span class="nam">container</span><span class="op">.</span><span class="nam">background</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t"> <span class="com"># Create the new span</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t"> <span class="nam">span</span> <span class="op">=</span> <span class="nam">cls</span><span class="op">(</span><span class="nam">style</span><span class="op">,</span> <span class="nam">background</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t"> <span class="com"># Add the span to the container</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">container</span><span class="op">,</span> <span class="str">'add_span'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t"> <span class="nam">container</span><span class="op">.</span><span class="nam">add_span</span><span class="op">(</span><span class="nam">span</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t"> <span class="key">raise</span> <span class="nam">AttributeError</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t"> <span class="fst">f"</span><span class="fst">Container </span><span class="op">{</span><span class="nam">type</span><span class="op">(</span><span class="nam">container</span><span class="op">)</span><span class="op">.</span><span class="nam">__name__</span><span class="op">}</span><span class="fst"> must have an 'add_span' method</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t"> <span class="key">return</span> <span class="nam">span</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t"> <span class="key">def</span> <span class="nam">style</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Font</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t"> <span class="str">"""Get the font style of this span"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t"> <span class="key">def</span> <span class="nam">background</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t"> <span class="str">"""Get the background color of this span"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_background</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t"> <span class="key">def</span> <span class="nam">words</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">List</span><span class="op">[</span><span class="nam">Word</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t"> <span class="str">"""Get the list of words in this span"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_words</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t"> <span class="key">def</span> <span class="nam">add_word</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">text</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Word</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t"><span class="str"> Create and add a new word to this span.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t"><span class="str"> text: The text content of the word</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t"><span class="str"> The newly created Word object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t"> <span class="com"># Get the previous word if any</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t"> <span class="nam">previous</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_words</span><span class="op">[</span><span class="op">-</span><span class="num">1</span><span class="op">]</span> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_words</span> <span class="key">else</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t"> <span class="com"># Create the new word</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t"> <span class="nam">word</span> <span class="op">=</span> <span class="nam">Word</span><span class="op">(</span><span class="nam">text</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_background</span><span class="op">,</span> <span class="nam">previous</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t"> <span class="com"># Link the previous word to this new one</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t279" href="#t279">279</a></span><span class="t"> <span class="key">if</span> <span class="nam">previous</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t280" href="#t280">280</a></span><span class="t"> <span class="nam">previous</span><span class="op">.</span><span class="nam">add_next</span><span class="op">(</span><span class="nam">word</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t281" href="#t281">281</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t282" href="#t282">282</a></span><span class="t"> <span class="com"># Add the word to our list</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t283" href="#t283">283</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_words</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">word</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t284" href="#t284">284</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t285" href="#t285">285</a></span><span class="t"> <span class="key">return</span> <span class="nam">word</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t286" href="#t286">286</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t287" href="#t287">287</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t288" href="#t288">288</a></span><span class="t"><span class="key">class</span> <span class="nam">LinkedWord</span><span class="op">(</span><span class="nam">Word</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t289" href="#t289">289</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t290" href="#t290">290</a></span><span class="t"><span class="str"> A Word that is also a Link - combines text content with hyperlink functionality.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t291" href="#t291">291</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t292" href="#t292">292</a></span><span class="t"><span class="str"> When a word is part of a hyperlink, it becomes clickable and can trigger</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t293" href="#t293">293</a></span><span class="t"><span class="str"> navigation or callbacks. Multiple words can share the same link destination.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t294" href="#t294">294</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t295" href="#t295">295</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t296" href="#t296">296</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">text</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span> <span class="nam">style</span><span class="op">:</span> <span class="nam">Union</span><span class="op">[</span><span class="nam">Font</span><span class="op">,</span> <span class="str">'AbstractStyle'</span><span class="op">]</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t297" href="#t297">297</a></span><span class="t"> <span class="nam">location</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span> <span class="nam">link_type</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="str">'LinkType'</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t298" href="#t298">298</a></span><span class="t"> <span class="nam">callback</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Callable</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t299" href="#t299">299</a></span><span class="t"> <span class="nam">background</span><span class="op">=</span><span class="key">None</span><span class="op">,</span> <span class="nam">previous</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Word</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t300" href="#t300">300</a></span><span class="t"> <span class="nam">params</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t301" href="#t301">301</a></span><span class="t"> <span class="nam">title</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t302" href="#t302">302</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t303" href="#t303">303</a></span><span class="t"><span class="str"> Initialize a linked word.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t304" href="#t304">304</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t305" href="#t305">305</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t306" href="#t306">306</a></span><span class="t"><span class="str"> text: The text content of the word</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t307" href="#t307">307</a></span><span class="t"><span class="str"> style: The font style</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t308" href="#t308">308</a></span><span class="t"><span class="str"> location: The link target (URL, bookmark, etc.)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t309" href="#t309">309</a></span><span class="t"><span class="str"> link_type: Type of link (INTERNAL, EXTERNAL, etc.)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t310" href="#t310">310</a></span><span class="t"><span class="str"> callback: Optional callback for link activation</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t311" href="#t311">311</a></span><span class="t"><span class="str"> background: Optional background color</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t312" href="#t312">312</a></span><span class="t"><span class="str"> previous: Previous word in sequence</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t313" href="#t313">313</a></span><span class="t"><span class="str"> params: Parameters for the link</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t314" href="#t314">314</a></span><span class="t"><span class="str"> title: Tooltip/title for the link</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t315" href="#t315">315</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t316" href="#t316">316</a></span><span class="t"> <span class="com"># Initialize Word first</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t317" href="#t317">317</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="nam">text</span><span class="op">,</span> <span class="nam">style</span><span class="op">,</span> <span class="nam">background</span><span class="op">,</span> <span class="nam">previous</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t318" href="#t318">318</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t319" href="#t319">319</a></span><span class="t"> <span class="com"># Store link properties</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t320" href="#t320">320</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_location</span> <span class="op">=</span> <span class="nam">location</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t321" href="#t321">321</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_link_type</span> <span class="op">=</span> <span class="nam">link_type</span> <span class="key">or</span> <span class="nam">LinkType</span><span class="op">.</span><span class="nam">EXTERNAL</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t322" href="#t322">322</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_callback</span> <span class="op">=</span> <span class="nam">callback</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t323" href="#t323">323</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_params</span> <span class="op">=</span> <span class="nam">params</span> <span class="key">or</span> <span class="op">{</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t324" href="#t324">324</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_title</span> <span class="op">=</span> <span class="nam">title</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t325" href="#t325">325</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t326" href="#t326">326</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t327" href="#t327">327</a></span><span class="t"> <span class="key">def</span> <span class="nam">location</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">str</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t328" href="#t328">328</a></span><span class="t"> <span class="str">"""Get the link target location"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t329" href="#t329">329</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_location</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t330" href="#t330">330</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t331" href="#t331">331</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t332" href="#t332">332</a></span><span class="t"> <span class="key">def</span> <span class="nam">link_type</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t333" href="#t333">333</a></span><span class="t"> <span class="str">"""Get the type of link"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t334" href="#t334">334</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_link_type</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t335" href="#t335">335</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t336" href="#t336">336</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t337" href="#t337">337</a></span><span class="t"> <span class="key">def</span> <span class="nam">link_callback</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Callable</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t338" href="#t338">338</a></span><span class="t"> <span class="str">"""Get the link callback (distinct from word callback)"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t339" href="#t339">339</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_callback</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t340" href="#t340">340</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t341" href="#t341">341</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t342" href="#t342">342</a></span><span class="t"> <span class="key">def</span> <span class="nam">params</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t343" href="#t343">343</a></span><span class="t"> <span class="str">"""Get the link parameters"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t344" href="#t344">344</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_params</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t345" href="#t345">345</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t346" href="#t346">346</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t347" href="#t347">347</a></span><span class="t"> <span class="key">def</span> <span class="nam">link_title</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t348" href="#t348">348</a></span><span class="t"> <span class="str">"""Get the link title/tooltip"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t349" href="#t349">349</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_title</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t350" href="#t350">350</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t351" href="#t351">351</a></span><span class="t"> <span class="key">def</span> <span class="nam">execute_link</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">context</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Any</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Any</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t352" href="#t352">352</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t353" href="#t353">353</a></span><span class="t"><span class="str"> Execute the link action.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t354" href="#t354">354</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t355" href="#t355">355</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t356" href="#t356">356</a></span><span class="t"><span class="str"> context: Optional context dict (e.g., {'text': word.text})</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t357" href="#t357">357</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t358" href="#t358">358</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t359" href="#t359">359</a></span><span class="t"><span class="str"> The result of the link execution</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t360" href="#t360">360</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t361" href="#t361">361</a></span><span class="t"> <span class="com"># Add word text to context</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t362" href="#t362">362</a></span><span class="t"> <span class="nam">full_context</span> <span class="op">=</span> <span class="op">{</span><span class="op">**</span><span class="nam">self</span><span class="op">.</span><span class="nam">_params</span><span class="op">,</span> <span class="str">'text'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_text</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t363" href="#t363">363</a></span><span class="t"> <span class="key">if</span> <span class="nam">context</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">363&#x202F;&#x219B;&#x202F;364</span><span class="annotate long">line 363 didn't jump to line 364 because the condition on line 363 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t364" href="#t364">364</a></span><span class="t"> <span class="nam">full_context</span><span class="op">.</span><span class="nam">update</span><span class="op">(</span><span class="nam">context</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t365" href="#t365">365</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t366" href="#t366">366</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_link_type</span> <span class="key">in</span> <span class="op">(</span><span class="nam">LinkType</span><span class="op">.</span><span class="nam">API</span><span class="op">,</span> <span class="nam">LinkType</span><span class="op">.</span><span class="nam">FUNCTION</span><span class="op">)</span> <span class="key">and</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_callback</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t367" href="#t367">367</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_callback</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_location</span><span class="op">,</span> <span class="op">**</span><span class="nam">full_context</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t368" href="#t368">368</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t369" href="#t369">369</a></span><span class="t"> <span class="com"># For INTERNAL and EXTERNAL links, return the location</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t370" href="#t370">370</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_location</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t371" href="#t371">371</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t372" href="#t372">372</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t373" href="#t373">373</a></span><span class="t"><span class="key">class</span> <span class="nam">LineBreak</span><span class="op">(</span><span class="nam">Hierarchical</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t374" href="#t374">374</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t375" href="#t375">375</a></span><span class="t"><span class="str"> A line break element that forces a new line within text content.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t376" href="#t376">376</a></span><span class="t"><span class="str"> While this is an inline element that can occur within paragraphs,</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t377" href="#t377">377</a></span><span class="t"><span class="str"> it has block-like properties for consistency with the abstract model.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t378" href="#t378">378</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t379" href="#t379">379</a></span><span class="t"><span class="str"> Uses Hierarchical mixin for parent-child relationship management.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t380" href="#t380">380</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t381" href="#t381">381</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t382" href="#t382">382</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t383" href="#t383">383</a></span><span class="t"> <span class="str">"""Initialize a line break element."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t384" href="#t384">384</a></span><span class="t"> <span class="nam">super</span><span class="op">(</span><span class="op">)</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t385" href="#t385">385</a></span><span class="t"> <span class="com"># Import here to avoid circular imports</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t386" href="#t386">386</a></span><span class="t"> <span class="key">from</span> <span class="op">.</span><span class="nam">block</span> <span class="key">import</span> <span class="nam">BlockType</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t387" href="#t387">387</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_block_type</span> <span class="op">=</span> <span class="nam">BlockType</span><span class="op">.</span><span class="nam">LINE_BREAK</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t388" href="#t388">388</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t389" href="#t389">389</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t390" href="#t390">390</a></span><span class="t"> <span class="key">def</span> <span class="nam">block_type</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t391" href="#t391">391</a></span><span class="t"> <span class="str">"""Get the block type for this line break"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t392" href="#t392">392</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_block_type</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t393" href="#t393">393</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t394" href="#t394">394</a></span><span class="t"> <span class="op">@</span><span class="nam">classmethod</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t395" href="#t395">395</a></span><span class="t"> <span class="key">def</span> <span class="nam">create_and_add_to</span><span class="op">(</span><span class="nam">cls</span><span class="op">,</span> <span class="nam">container</span><span class="op">)</span> <span class="op">-></span> <span class="str">'LineBreak'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t396" href="#t396">396</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t397" href="#t397">397</a></span><span class="t"><span class="str"> Create a new LineBreak and add it to a container.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t398" href="#t398">398</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t399" href="#t399">399</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t400" href="#t400">400</a></span><span class="t"><span class="str"> container: The container to add the line break to</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t401" href="#t401">401</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t402" href="#t402">402</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t403" href="#t403">403</a></span><span class="t"><span class="str"> The newly created LineBreak object</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t404" href="#t404">404</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t405" href="#t405">405</a></span><span class="t"> <span class="com"># Create the new line break</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t406" href="#t406">406</a></span><span class="t"> <span class="nam">line_break</span> <span class="op">=</span> <span class="nam">cls</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t407" href="#t407">407</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t408" href="#t408">408</a></span><span class="t"> <span class="com"># Add the line break to the container if it has an appropriate method</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t409" href="#t409">409</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">container</span><span class="op">,</span> <span class="str">'add_line_break'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t410" href="#t410">410</a></span><span class="t"> <span class="nam">container</span><span class="op">.</span><span class="nam">add_line_break</span><span class="op">(</span><span class="nam">line_break</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t411" href="#t411">411</a></span><span class="t"> <span class="key">elif</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">container</span><span class="op">,</span> <span class="str">'add_element'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t412" href="#t412">412</a></span><span class="t"> <span class="nam">container</span><span class="op">.</span><span class="nam">add_element</span><span class="op">(</span><span class="nam">line_break</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t413" href="#t413">413</a></span><span class="t"> <span class="key">elif</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">container</span><span class="op">,</span> <span class="str">'add_word'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t414" href="#t414">414</a></span><span class="t"> <span class="com"># Some containers might treat line breaks like words</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t415" href="#t415">415</a></span><span class="t"> <span class="nam">container</span><span class="op">.</span><span class="nam">add_word</span><span class="op">(</span><span class="nam">line_break</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t416" href="#t416">416</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t417" href="#t417">417</a></span><span class="t"> <span class="com"># Set parent relationship manually</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t418" href="#t418">418</a></span><span class="t"> <span class="nam">line_break</span><span class="op">.</span><span class="nam">parent</span> <span class="op">=</span> <span class="nam">container</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t419" href="#t419">419</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t420" href="#t420">420</a></span><span class="t"> <span class="key">return</span> <span class="nam">line_break</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_af715639580e2d86_functional_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_af715639580e2d86_interactive_image_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,262 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/abstract/interactive_image.py: 80%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/abstract/interactive_image.py</b>:
<span class="pc_cov">80%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">34 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">30<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">4<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">7<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">3<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_af715639580e2d86_inline_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_7d48e1f4c6486fa2___init___py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">Interactive and queryable image for pyWebLayout.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">Provides an InteractiveImage class that combines Image with Interactable</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">and Queriable capabilities, allowing images to respond to tap events with</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="str">proper bounding box detection.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">Callable</span><span class="op">,</span> <span class="nam">Tuple</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="key">import</span> <span class="nam">numpy</span> <span class="key">as</span> <span class="nam">np</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">block</span> <span class="key">import</span> <span class="nam">Image</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="op">.</span><span class="nam">core</span><span class="op">.</span><span class="nam">base</span> <span class="key">import</span> <span class="nam">Interactable</span><span class="op">,</span> <span class="nam">Queriable</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"><span class="key">class</span> <span class="nam">InteractiveImage</span><span class="op">(</span><span class="nam">Image</span><span class="op">,</span> <span class="nam">Interactable</span><span class="op">,</span> <span class="nam">Queriable</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"><span class="str"> An image that can be interacted with and queried for hit detection.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"><span class="str"> This combines pyWebLayout's Image block with Interactable and Queriable</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"><span class="str"> capabilities, allowing the image to:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"><span class="str"> - Have a callback that fires when tapped</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"><span class="str"> - Know its rendered position (origin)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"><span class="str"> - Detect if a point is within its bounds</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"><span class="str"> Example:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"><span class="str"> >>> img = InteractiveImage(</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t"><span class="str"> ... source="cover.png",</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"><span class="str"> ... alt_text="Book Title",</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"><span class="str"> ... callback=lambda point: "/path/to/book.epub"</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"><span class="str"> ... )</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"><span class="str"> >>> # After rendering, origin is set automatically</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"><span class="str"> >>> # Check if tap is inside</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"><span class="str"> >>> result = img.interact((120, 250))</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"><span class="str"> >>> # Returns "/path/to/book.epub" if inside, None if outside</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"> <span class="nam">source</span><span class="op">:</span> <span class="nam">str</span> <span class="op">=</span> <span class="str">""</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t"> <span class="nam">alt_text</span><span class="op">:</span> <span class="nam">str</span> <span class="op">=</span> <span class="str">""</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t"> <span class="nam">width</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t"> <span class="nam">height</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"> <span class="nam">callback</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Callable</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t"> <span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"><span class="str"> Initialize an interactive image.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"><span class="str"> source: The image source URL or path</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t"><span class="str"> alt_text: Alternative text for accessibility</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t"><span class="str"> width: Optional image width in pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"><span class="str"> height: Optional image height in pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t"><span class="str"> callback: Function to call when image is tapped (receives point coordinates)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t"> <span class="com"># Initialize Image</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t"> <span class="nam">Image</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"> <span class="nam">source</span><span class="op">=</span><span class="nam">source</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"> <span class="nam">alt_text</span><span class="op">=</span><span class="nam">alt_text</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"> <span class="nam">width</span><span class="op">=</span><span class="nam">width</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t"> <span class="nam">height</span><span class="op">=</span><span class="nam">height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"> <span class="com"># Initialize Interactable</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"> <span class="nam">Interactable</span><span class="op">.</span><span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">callback</span><span class="op">=</span><span class="nam">callback</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t"> <span class="com"># Initialize position tracking</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="op">[</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">]</span><span class="op">)</span> <span class="com"># Will be set during rendering</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">size</span> <span class="op">=</span> <span class="op">(</span><span class="nam">width</span> <span class="key">or</span> <span class="num">0</span><span class="op">,</span> <span class="nam">height</span> <span class="key">or</span> <span class="num">0</span><span class="op">)</span> <span class="com"># Will be updated during rendering</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t"> <span class="key">def</span> <span class="nam">interact</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">point</span><span class="op">:</span> <span class="nam">np</span><span class="op">.</span><span class="nam">generic</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">any</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"><span class="str"> Handle interaction at the given point.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"><span class="str"> Only triggers the callback if the point is within the image bounds.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"><span class="str"> point: The coordinates of the interaction (x, y)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t"><span class="str"> The result of the callback if point is inside, None otherwise</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t"> <span class="com"># Check if point is inside this image</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">in_object</span><span class="op">(</span><span class="nam">point</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t"> <span class="com"># Point is inside, trigger callback</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_callback</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_callback</span><span class="op">(</span><span class="nam">point</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t"> <span class="key">def</span> <span class="nam">in_object</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">point</span><span class="op">:</span> <span class="nam">np</span><span class="op">.</span><span class="nam">generic</span><span class="op">)</span> <span class="op">-></span> <span class="nam">bool</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t"><span class="str"> Check if a point is within the image bounds.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t"><span class="str"> point: The coordinates to check (x, y)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"><span class="str"> True if point is inside the image, False otherwise</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"> <span class="nam">point_array</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="nam">point</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"> <span class="nam">relative_point</span> <span class="op">=</span> <span class="nam">point_array</span> <span class="op">-</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t"> <span class="key">return</span> <span class="nam">np</span><span class="op">.</span><span class="nam">all</span><span class="op">(</span><span class="op">(</span><span class="num">0</span> <span class="op">&lt;=</span> <span class="nam">relative_point</span><span class="op">)</span> <span class="op">&amp;</span> <span class="op">(</span><span class="nam">relative_point</span> <span class="op">&lt;</span> <span class="nam">self</span><span class="op">.</span><span class="nam">size</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t"> <span class="op">@</span><span class="nam">classmethod</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t"> <span class="key">def</span> <span class="nam">create_and_add_to</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t"> <span class="nam">cls</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t"> <span class="nam">parent</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t"> <span class="nam">source</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"> <span class="nam">alt_text</span><span class="op">:</span> <span class="nam">str</span> <span class="op">=</span> <span class="str">""</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t"> <span class="nam">width</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"> <span class="nam">height</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t"> <span class="nam">callback</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Callable</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t"> <span class="op">)</span> <span class="op">-></span> <span class="str">'InteractiveImage'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"><span class="str"> Create an interactive image and add it to a parent block.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t"><span class="str"> This is a convenience method that mimics the Image.create_and_add_to API</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"><span class="str"> but creates an InteractiveImage instead.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t"><span class="str"> parent: Parent block to add this image to</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"><span class="str"> source: The image source URL or path</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t"><span class="str"> alt_text: Alternative text for accessibility</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t"><span class="str"> width: Optional image width in pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t"><span class="str"> height: Optional image height in pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t"><span class="str"> callback: Function to call when image is tapped</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t"><span class="str"> The created InteractiveImage instance</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t"> <span class="nam">img</span> <span class="op">=</span> <span class="nam">cls</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t"> <span class="nam">source</span><span class="op">=</span><span class="nam">source</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t"> <span class="nam">alt_text</span><span class="op">=</span><span class="nam">alt_text</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t"> <span class="nam">width</span><span class="op">=</span><span class="nam">width</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"> <span class="nam">height</span><span class="op">=</span><span class="nam">height</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t"> <span class="nam">callback</span><span class="op">=</span><span class="nam">callback</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t"> <span class="com"># Add to parent using its add_block method</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t"> <span class="key">if</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">parent</span><span class="op">,</span> <span class="str">'add_block'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">141&#x202F;&#x219B;&#x202F;142</span><span class="annotate long">line 141 didn't jump to line 142 because the condition on line 141 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t"> <span class="nam">parent</span><span class="op">.</span><span class="nam">add_block</span><span class="op">(</span><span class="nam">img</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t"> <span class="key">elif</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">parent</span><span class="op">,</span> <span class="str">'add_child'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">143&#x202F;&#x219B;&#x202F;144</span><span class="annotate long">line 143 didn't jump to line 144 because the condition on line 143 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"> <span class="nam">parent</span><span class="op">.</span><span class="nam">add_child</span><span class="op">(</span><span class="nam">img</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t"> <span class="key">elif</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">parent</span><span class="op">,</span> <span class="str">'_children'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">145&#x202F;&#x219B;&#x202F;147</span><span class="annotate long">line 145 didn't jump to line 147 because the condition on line 145 was always true</span></span></p>
<p class="run"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t"> <span class="nam">parent</span><span class="op">.</span><span class="nam">_children</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">img</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"> <span class="key">elif</span> <span class="nam">hasattr</span><span class="op">(</span><span class="nam">parent</span><span class="op">,</span> <span class="str">'_blocks'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"> <span class="nam">parent</span><span class="op">.</span><span class="nam">_blocks</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="nam">img</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t"> <span class="key">return</span> <span class="nam">img</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t"> <span class="key">def</span> <span class="nam">set_rendered_bounds</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">origin</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">,</span> <span class="nam">size</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t"><span class="str"> Set the rendered position and size of this image.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t"><span class="str"> This should be called by the renderer after it places the image.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t"><span class="str"> origin: (x, y) coordinates of top-left corner</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"><span class="str"> size: (width, height) of the rendered image</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_origin</span> <span class="op">=</span> <span class="nam">np</span><span class="op">.</span><span class="nam">array</span><span class="op">(</span><span class="nam">origin</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">size</span> <span class="op">=</span> <span class="nam">size</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_af715639580e2d86_inline_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_7d48e1f4c6486fa2___init___py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,122 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/style/__init__.py: 100%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/style/__init__.py</b>:
<span class="pc_cov">100%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">6 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">6<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">0<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">1<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">0<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_427cc3035faf7633_table_optimizer_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_ba7f6bdeb0188088_abstract_style_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">Style system for the pyWebLayout library.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">This module provides the core styling components used throughout the library.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">fonts</span> <span class="key">import</span> <span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"> <span class="nam">Font</span><span class="op">,</span> <span class="nam">FontWeight</span><span class="op">,</span> <span class="nam">FontStyle</span><span class="op">,</span> <span class="nam">TextDecoration</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"> <span class="nam">BundledFont</span><span class="op">,</span> <span class="nam">get_bundled_font_path</span><span class="op">,</span> <span class="nam">get_bundled_fonts_dir</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">abstract_style</span> <span class="key">import</span> <span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"> <span class="nam">AbstractStyle</span><span class="op">,</span> <span class="nam">AbstractStyleRegistry</span><span class="op">,</span> <span class="nam">FontFamily</span><span class="op">,</span> <span class="nam">FontSize</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">concrete_style</span> <span class="key">import</span> <span class="nam">ConcreteStyle</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">page_style</span> <span class="key">import</span> <span class="nam">PageStyle</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">alignment</span> <span class="key">import</span> <span class="nam">Alignment</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"><span class="nam">__all__</span> <span class="op">=</span> <span class="op">[</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"> <span class="str">"Font"</span><span class="op">,</span> <span class="str">"FontWeight"</span><span class="op">,</span> <span class="str">"FontStyle"</span><span class="op">,</span> <span class="str">"TextDecoration"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"> <span class="str">"BundledFont"</span><span class="op">,</span> <span class="str">"get_bundled_font_path"</span><span class="op">,</span> <span class="str">"get_bundled_fonts_dir"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"> <span class="str">"AbstractStyle"</span><span class="op">,</span> <span class="str">"AbstractStyleRegistry"</span><span class="op">,</span> <span class="str">"FontFamily"</span><span class="op">,</span> <span class="str">"FontSize"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"> <span class="str">"ConcreteStyle"</span><span class="op">,</span> <span class="str">"PageStyle"</span><span class="op">,</span> <span class="str">"Alignment"</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_427cc3035faf7633_table_optimizer_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_ba7f6bdeb0188088_abstract_style_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,441 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/style/abstract_style.py: 75%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/style/abstract_style.py</b>:
<span class="pc_cov">75%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">130 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">103<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">27<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">22<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">7<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_ba7f6bdeb0188088___init___py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_ba7f6bdeb0188088_alignment_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">Abstract style system for storing document styling intent.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">This module defines styles in terms of semantic meaning rather than concrete</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">rendering parameters, allowing for flexible interpretation by different</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="str">rendering systems and user preferences.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">alignment</span> <span class="key">import</span> <span class="nam">Alignment</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">Dict</span><span class="op">,</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">Tuple</span><span class="op">,</span> <span class="nam">Union</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="key">from</span> <span class="nam">dataclasses</span> <span class="key">import</span> <span class="nam">dataclass</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="key">from</span> <span class="nam">enum</span> <span class="key">import</span> <span class="nam">Enum</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">fonts</span> <span class="key">import</span> <span class="nam">FontWeight</span><span class="op">,</span> <span class="nam">FontStyle</span><span class="op">,</span> <span class="nam">TextDecoration</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"><span class="key">class</span> <span class="nam">FontFamily</span><span class="op">(</span><span class="nam">Enum</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"> <span class="str">"""Semantic font family categories"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"> <span class="nam">SERIF</span> <span class="op">=</span> <span class="str">"serif"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"> <span class="nam">SANS_SERIF</span> <span class="op">=</span> <span class="str">"sans-serif"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"> <span class="nam">MONOSPACE</span> <span class="op">=</span> <span class="str">"monospace"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"> <span class="nam">CURSIVE</span> <span class="op">=</span> <span class="str">"cursive"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"> <span class="nam">FANTASY</span> <span class="op">=</span> <span class="str">"fantasy"</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"><span class="key">class</span> <span class="nam">FontSize</span><span class="op">(</span><span class="nam">Enum</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"> <span class="str">"""Semantic font sizes"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"> <span class="nam">XX_SMALL</span> <span class="op">=</span> <span class="str">"xx-small"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t"> <span class="nam">X_SMALL</span> <span class="op">=</span> <span class="str">"x-small"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"> <span class="nam">SMALL</span> <span class="op">=</span> <span class="str">"small"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"> <span class="nam">MEDIUM</span> <span class="op">=</span> <span class="str">"medium"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"> <span class="nam">LARGE</span> <span class="op">=</span> <span class="str">"large"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"> <span class="nam">X_LARGE</span> <span class="op">=</span> <span class="str">"x-large"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"> <span class="nam">XX_LARGE</span> <span class="op">=</span> <span class="str">"xx-large"</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"> <span class="com"># Allow numeric values as well</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"> <span class="op">@</span><span class="nam">classmethod</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"> <span class="key">def</span> <span class="nam">from_value</span><span class="op">(</span><span class="nam">cls</span><span class="op">,</span> <span class="nam">value</span><span class="op">:</span> <span class="nam">Union</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">float</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Union</span><span class="op">[</span><span class="str">'FontSize'</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t"> <span class="str">"""Convert a value to FontSize enum or return numeric value"""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">value</span><span class="op">,</span> <span class="op">(</span><span class="nam">int</span><span class="op">,</span> <span class="nam">float</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"> <span class="key">return</span> <span class="nam">int</span><span class="op">(</span><span class="nam">value</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">value</span><span class="op">,</span> <span class="nam">str</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t"> <span class="key">return</span> <span class="nam">cls</span><span class="op">(</span><span class="nam">value</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"> <span class="key">except</span> <span class="nam">ValueError</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t"> <span class="com"># Try to parse as number</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"> <span class="key">return</span> <span class="nam">int</span><span class="op">(</span><span class="nam">float</span><span class="op">(</span><span class="nam">value</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"> <span class="key">except</span> <span class="nam">ValueError</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t"> <span class="key">return</span> <span class="nam">cls</span><span class="op">.</span><span class="nam">MEDIUM</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"> <span class="key">return</span> <span class="nam">cls</span><span class="op">.</span><span class="nam">MEDIUM</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"><span class="com"># Import Alignment from the centralized location</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"><span class="com"># Use Alignment for text alignment</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t"><span class="nam">TextAlign</span> <span class="op">=</span> <span class="nam">Alignment</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"><span class="op">@</span><span class="nam">dataclass</span><span class="op">(</span><span class="nam">frozen</span><span class="op">=</span><span class="key">True</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"><span class="key">class</span> <span class="nam">AbstractStyle</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t"><span class="str"> Abstract representation of text styling that captures semantic intent</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t"><span class="str"> rather than concrete rendering parameters.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"><span class="str"> This allows the same document to be rendered differently based on</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t"><span class="str"> user preferences, device capabilities, or accessibility requirements.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"><span class="str"> Being frozen=True makes this class hashable and immutable, which is</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"><span class="str"> perfect for use as dictionary keys and preventing accidental modification.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t"> <span class="com"># Font properties (semantic)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"> <span class="nam">font_family</span><span class="op">:</span> <span class="nam">FontFamily</span> <span class="op">=</span> <span class="nam">FontFamily</span><span class="op">.</span><span class="nam">SERIF</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t"> <span class="nam">font_size</span><span class="op">:</span> <span class="nam">Union</span><span class="op">[</span><span class="nam">FontSize</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="nam">FontSize</span><span class="op">.</span><span class="nam">MEDIUM</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"> <span class="nam">font_weight</span><span class="op">:</span> <span class="nam">FontWeight</span> <span class="op">=</span> <span class="nam">FontWeight</span><span class="op">.</span><span class="nam">NORMAL</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t"> <span class="nam">font_style</span><span class="op">:</span> <span class="nam">FontStyle</span> <span class="op">=</span> <span class="nam">FontStyle</span><span class="op">.</span><span class="nam">NORMAL</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t"> <span class="nam">text_decoration</span><span class="op">:</span> <span class="nam">TextDecoration</span> <span class="op">=</span> <span class="nam">TextDecoration</span><span class="op">.</span><span class="nam">NONE</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t"> <span class="com"># Color (as semantic names or RGB)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t"> <span class="nam">color</span><span class="op">:</span> <span class="nam">Union</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="str">"black"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t"> <span class="nam">background_color</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Union</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t"> <span class="com"># Text properties</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"> <span class="nam">text_align</span><span class="op">:</span> <span class="nam">TextAlign</span> <span class="op">=</span> <span class="nam">TextAlign</span><span class="op">.</span><span class="nam">LEFT</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t"> <span class="nam">line_height</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Union</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">float</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span> <span class="com"># "normal", "1.2", 1.5, etc.</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t"> <span class="nam">letter_spacing</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Union</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">float</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span> <span class="com"># "normal", "0.1em", etc.</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t"> <span class="nam">word_spacing</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Union</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">float</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t"> <span class="nam">word_spacing_min</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Union</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">float</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span> <span class="com"># Minimum allowed word spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"> <span class="nam">word_spacing_max</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Union</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">float</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span> <span class="com"># Maximum allowed word spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t"> <span class="com"># Language and locale</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t"> <span class="nam">language</span><span class="op">:</span> <span class="nam">str</span> <span class="op">=</span> <span class="str">"en-US"</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t"> <span class="com"># Hierarchy properties</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t"> <span class="nam">parent_style_id</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t"> <span class="key">def</span> <span class="nam">__post_init__</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t"> <span class="str">"""Validate and normalize values after creation"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"> <span class="com"># Normalize font_size if it's a string that could be a number</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">font_size</span><span class="op">,</span> <span class="nam">str</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">100&#x202F;&#x219B;&#x202F;101</span><span class="annotate long">line 100 didn't jump to line 101 because the condition on line 100 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"> <span class="nam">object</span><span class="op">.</span><span class="nam">__setattr__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="str">'font_size'</span><span class="op">,</span> <span class="nam">int</span><span class="op">(</span><span class="nam">float</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">font_size</span><span class="op">)</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t"> <span class="key">except</span> <span class="nam">ValueError</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t"> <span class="com"># Keep as is if it's a semantic size name</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t"> <span class="key">pass</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t"> <span class="key">def</span> <span class="nam">__hash__</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t"><span class="str"> Custom hash implementation to ensure consistent hashing.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t"><span class="str"> Since this is a frozen dataclass, it should be hashable by default,</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"><span class="str"> but we provide a custom implementation to ensure all fields are</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t"><span class="str"> properly considered and to handle the Union types correctly.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t"> <span class="com"># Convert all values to hashable forms</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"> <span class="nam">hashable_values</span> <span class="op">=</span> <span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">font_family</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">font_size</span> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">font_size</span><span class="op">,</span> <span class="nam">int</span><span class="op">)</span> <span class="key">else</span> <span class="nam">self</span><span class="op">.</span><span class="nam">font_size</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">font_weight</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">font_style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">text_decoration</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">color</span> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">color</span><span class="op">,</span> <span class="op">(</span><span class="nam">str</span><span class="op">,</span> <span class="nam">tuple</span><span class="op">)</span><span class="op">)</span> <span class="key">else</span> <span class="nam">str</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">color</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">background_color</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">text_align</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">line_height</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">letter_spacing</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">word_spacing</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">word_spacing_min</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">word_spacing_max</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">language</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">parent_style_id</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t"> <span class="key">return</span> <span class="nam">hash</span><span class="op">(</span><span class="nam">hashable_values</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"> <span class="key">def</span> <span class="nam">merge_with</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">other</span><span class="op">:</span> <span class="str">'AbstractStyle'</span><span class="op">)</span> <span class="op">-></span> <span class="str">'AbstractStyle'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"><span class="str"> Create a new AbstractStyle by merging this one with another.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t"><span class="str"> The other style's properties take precedence.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t"><span class="str"> other: AbstractStyle to merge with this one</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t"><span class="str"> New AbstractStyle with merged values</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"> <span class="com"># Get all fields from both styles</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"> <span class="nam">current_dict</span> <span class="op">=</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t"> <span class="nam">field</span><span class="op">.</span><span class="nam">name</span><span class="op">:</span> <span class="nam">getattr</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">field</span><span class="op">.</span><span class="nam">name</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t"> <span class="key">for</span> <span class="nam">field</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">__dataclass_fields__</span><span class="op">.</span><span class="nam">values</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t"> <span class="nam">other_dict</span> <span class="op">=</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t"> <span class="nam">field</span><span class="op">.</span><span class="nam">name</span><span class="op">:</span> <span class="nam">getattr</span><span class="op">(</span><span class="nam">other</span><span class="op">,</span> <span class="nam">field</span><span class="op">.</span><span class="nam">name</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t"> <span class="key">for</span> <span class="nam">field</span> <span class="key">in</span> <span class="nam">other</span><span class="op">.</span><span class="nam">__dataclass_fields__</span><span class="op">.</span><span class="nam">values</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t"> <span class="key">if</span> <span class="nam">getattr</span><span class="op">(</span><span class="nam">other</span><span class="op">,</span> <span class="nam">field</span><span class="op">.</span><span class="nam">name</span><span class="op">)</span> <span class="op">!=</span> <span class="nam">field</span><span class="op">.</span><span class="nam">default</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t"> <span class="com"># Merge dictionaries (other takes precedence)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"> <span class="nam">merged_dict</span> <span class="op">=</span> <span class="nam">current_dict</span><span class="op">.</span><span class="nam">copy</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t"> <span class="nam">merged_dict</span><span class="op">.</span><span class="nam">update</span><span class="op">(</span><span class="nam">other_dict</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"> <span class="key">return</span> <span class="nam">AbstractStyle</span><span class="op">(</span><span class="op">**</span><span class="nam">merged_dict</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t"> <span class="key">def</span> <span class="nam">with_modifications</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span> <span class="op">-></span> <span class="str">'AbstractStyle'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t"><span class="str"> Create a new AbstractStyle with specified modifications.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"><span class="str"> **kwargs: Properties to modify</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t"><span class="str"> New AbstractStyle with modifications applied</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t"> <span class="nam">current_dict</span> <span class="op">=</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t"> <span class="nam">field</span><span class="op">.</span><span class="nam">name</span><span class="op">:</span> <span class="nam">getattr</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">field</span><span class="op">.</span><span class="nam">name</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t"> <span class="key">for</span> <span class="nam">field</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">__dataclass_fields__</span><span class="op">.</span><span class="nam">values</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t"> <span class="nam">current_dict</span><span class="op">.</span><span class="nam">update</span><span class="op">(</span><span class="nam">kwargs</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t"> <span class="key">return</span> <span class="nam">AbstractStyle</span><span class="op">(</span><span class="op">**</span><span class="nam">current_dict</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t"><span class="key">class</span> <span class="nam">AbstractStyleRegistry</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t"><span class="str"> Registry for managing abstract document styles.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t"><span class="str"> This registry stores the semantic styling intent and provides</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t"><span class="str"> deduplication and inheritance capabilities using hashable AbstractStyle objects.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t"> <span class="str">"""Initialize an empty abstract style registry."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_styles</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">AbstractStyle</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t"> <span class="com"># Reverse mapping using hashable styles</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style_to_id</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">AbstractStyle</span><span class="op">,</span> <span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_next_id</span> <span class="op">=</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t"> <span class="com"># Create and register the default style</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_default_style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_create_default_style</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t"> <span class="key">def</span> <span class="nam">_create_default_style</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">AbstractStyle</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t"> <span class="str">"""Create the default document style."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t"> <span class="nam">default_style</span> <span class="op">=</span> <span class="nam">AbstractStyle</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t"> <span class="nam">style_id</span> <span class="op">=</span> <span class="str">"default"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_styles</span><span class="op">[</span><span class="nam">style_id</span><span class="op">]</span> <span class="op">=</span> <span class="nam">default_style</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style_to_id</span><span class="op">[</span><span class="nam">default_style</span><span class="op">]</span> <span class="op">=</span> <span class="nam">style_id</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"> <span class="key">return</span> <span class="nam">default_style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t"> <span class="key">def</span> <span class="nam">default_style</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">AbstractStyle</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t"> <span class="str">"""Get the default style for the document."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_default_style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t"> <span class="key">def</span> <span class="nam">_generate_style_id</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">str</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t"> <span class="str">"""Generate a unique style ID."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t"> <span class="nam">style_id</span> <span class="op">=</span> <span class="fst">f"</span><span class="fst">abstract_style_</span><span class="op">{</span><span class="nam">self</span><span class="op">.</span><span class="nam">_next_id</span><span class="op">}</span><span class="fst">"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_next_id</span> <span class="op">+=</span> <span class="num">1</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t"> <span class="key">return</span> <span class="nam">style_id</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_style_id</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">style</span><span class="op">:</span> <span class="nam">AbstractStyle</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t"><span class="str"> Get the ID for a given style if it exists in the registry.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t"><span class="str"> style: AbstractStyle to find</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t"><span class="str"> Style ID if found, None otherwise</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style_to_id</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="nam">style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t"> <span class="key">def</span> <span class="nam">register_style</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t"> <span class="nam">style</span><span class="op">:</span> <span class="nam">AbstractStyle</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t"> <span class="nam">style_id</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="nam">str</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t"><span class="str"> Register a style in the registry.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t"><span class="str"> style: AbstractStyle to register</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t"><span class="str"> style_id: Optional style ID. If None, one will be generated</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t"><span class="str"> The style ID</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t"> <span class="com"># Check if style already exists</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t"> <span class="nam">existing_id</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_style_id</span><span class="op">(</span><span class="nam">style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t"> <span class="key">if</span> <span class="nam">existing_id</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">249&#x202F;&#x219B;&#x202F;250</span><span class="annotate long">line 249 didn't jump to line 250 because the condition on line 249 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t"> <span class="key">return</span> <span class="nam">existing_id</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t"> <span class="key">if</span> <span class="nam">style_id</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">252&#x202F;&#x219B;&#x202F;255</span><span class="annotate long">line 252 didn't jump to line 255 because the condition on line 252 was always true</span></span></p>
<p class="run"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t"> <span class="nam">style_id</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_generate_style_id</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_styles</span><span class="op">[</span><span class="nam">style_id</span><span class="op">]</span> <span class="op">=</span> <span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style_to_id</span><span class="op">[</span><span class="nam">style</span><span class="op">]</span> <span class="op">=</span> <span class="nam">style_id</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t"> <span class="key">return</span> <span class="nam">style_id</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_or_create_style</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t"> <span class="nam">style</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">AbstractStyle</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t"> <span class="nam">parent_id</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t"> <span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">AbstractStyle</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t"><span class="str"> Get an existing style or create a new one.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t"><span class="str"> style: AbstractStyle object. If None, created from kwargs</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t"><span class="str"> parent_id: Optional parent style ID</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t"><span class="str"> **kwargs: Individual style properties (used if style is None)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t"><span class="str"> Tuple of (style_id, AbstractStyle)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t"> <span class="com"># Create style object if not provided</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t"> <span class="key">if</span> <span class="nam">style</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t"> <span class="com"># Filter out None values from kwargs</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t"> <span class="nam">filtered_kwargs</span> <span class="op">=</span> <span class="op">{</span><span class="nam">k</span><span class="op">:</span> <span class="nam">v</span> <span class="key">for</span> <span class="nam">k</span><span class="op">,</span> <span class="nam">v</span> <span class="key">in</span> <span class="nam">kwargs</span><span class="op">.</span><span class="nam">items</span><span class="op">(</span><span class="op">)</span> <span class="key">if</span> <span class="nam">v</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t"> <span class="key">if</span> <span class="nam">parent_id</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">278&#x202F;&#x219B;&#x202F;279</span><span class="annotate long">line 278 didn't jump to line 279 because the condition on line 278 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t279" href="#t279">279</a></span><span class="t"> <span class="nam">filtered_kwargs</span><span class="op">[</span><span class="str">'parent_style_id'</span><span class="op">]</span> <span class="op">=</span> <span class="nam">parent_id</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t280" href="#t280">280</a></span><span class="t"> <span class="nam">style</span> <span class="op">=</span> <span class="nam">AbstractStyle</span><span class="op">(</span><span class="op">**</span><span class="nam">filtered_kwargs</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t281" href="#t281">281</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t282" href="#t282">282</a></span><span class="t"> <span class="com"># Check if we already have this style (using hashable property)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t283" href="#t283">283</a></span><span class="t"> <span class="nam">existing_id</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_style_id</span><span class="op">(</span><span class="nam">style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t284" href="#t284">284</a></span><span class="t"> <span class="key">if</span> <span class="nam">existing_id</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t285" href="#t285">285</a></span><span class="t"> <span class="key">return</span> <span class="nam">existing_id</span><span class="op">,</span> <span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t286" href="#t286">286</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t287" href="#t287">287</a></span><span class="t"> <span class="com"># Create new style</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t288" href="#t288">288</a></span><span class="t"> <span class="nam">style_id</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">register_style</span><span class="op">(</span><span class="nam">style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t289" href="#t289">289</a></span><span class="t"> <span class="key">return</span> <span class="nam">style_id</span><span class="op">,</span> <span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t290" href="#t290">290</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t291" href="#t291">291</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_style_by_id</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">style_id</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">AbstractStyle</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t292" href="#t292">292</a></span><span class="t"> <span class="str">"""Get a style by its ID."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t293" href="#t293">293</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_styles</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="nam">style_id</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t294" href="#t294">294</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t295" href="#t295">295</a></span><span class="t"> <span class="key">def</span> <span class="nam">create_derived_style</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">base_style_id</span><span class="op">:</span> <span class="nam">str</span><span class="op">,</span> <span class="op">**</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t296" href="#t296">296</a></span><span class="t"> <span class="nam">modifications</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">AbstractStyle</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t297" href="#t297">297</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t298" href="#t298">298</a></span><span class="t"><span class="str"> Create a new style derived from a base style.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t299" href="#t299">299</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t300" href="#t300">300</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t301" href="#t301">301</a></span><span class="t"><span class="str"> base_style_id: ID of the base style</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t302" href="#t302">302</a></span><span class="t"><span class="str"> **modifications: Properties to modify</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t303" href="#t303">303</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t304" href="#t304">304</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t305" href="#t305">305</a></span><span class="t"><span class="str"> Tuple of (new_style_id, new_AbstractStyle)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t306" href="#t306">306</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t307" href="#t307">307</a></span><span class="t"> <span class="nam">base_style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_style_by_id</span><span class="op">(</span><span class="nam">base_style_id</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t308" href="#t308">308</a></span><span class="t"> <span class="key">if</span> <span class="nam">base_style</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">308&#x202F;&#x219B;&#x202F;309</span><span class="annotate long">line 308 didn't jump to line 309 because the condition on line 308 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t309" href="#t309">309</a></span><span class="t"> <span class="key">raise</span> <span class="nam">ValueError</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Base style '</span><span class="op">{</span><span class="nam">base_style_id</span><span class="op">}</span><span class="fst">' not found</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t310" href="#t310">310</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t311" href="#t311">311</a></span><span class="t"> <span class="com"># Create derived style</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t312" href="#t312">312</a></span><span class="t"> <span class="nam">derived_style</span> <span class="op">=</span> <span class="nam">base_style</span><span class="op">.</span><span class="nam">with_modifications</span><span class="op">(</span><span class="op">**</span><span class="nam">modifications</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t313" href="#t313">313</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_or_create_style</span><span class="op">(</span><span class="nam">derived_style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t314" href="#t314">314</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t315" href="#t315">315</a></span><span class="t"> <span class="key">def</span> <span class="nam">resolve_effective_style</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">style_id</span><span class="op">:</span> <span class="nam">str</span><span class="op">)</span> <span class="op">-></span> <span class="nam">AbstractStyle</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t316" href="#t316">316</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t317" href="#t317">317</a></span><span class="t"><span class="str"> Resolve the effective style including inheritance.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t318" href="#t318">318</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t319" href="#t319">319</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t320" href="#t320">320</a></span><span class="t"><span class="str"> style_id: Style ID to resolve</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t321" href="#t321">321</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t322" href="#t322">322</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t323" href="#t323">323</a></span><span class="t"><span class="str"> Effective AbstractStyle with inheritance applied</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t324" href="#t324">324</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t325" href="#t325">325</a></span><span class="t"> <span class="nam">style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_style_by_id</span><span class="op">(</span><span class="nam">style_id</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t326" href="#t326">326</a></span><span class="t"> <span class="key">if</span> <span class="nam">style</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">326&#x202F;&#x219B;&#x202F;327</span><span class="annotate long">line 326 didn't jump to line 327 because the condition on line 326 was never true</span></span></p>
<p class="mis show_mis"><span class="n"><a id="t327" href="#t327">327</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_default_style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t328" href="#t328">328</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t329" href="#t329">329</a></span><span class="t"> <span class="key">if</span> <span class="nam">style</span><span class="op">.</span><span class="nam">parent_style_id</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">329&#x202F;&#x219B;&#x202F;333</span><span class="annotate long">line 329 didn't jump to line 333 because the condition on line 329 was always true</span></span></p>
<p class="run"><span class="n"><a id="t330" href="#t330">330</a></span><span class="t"> <span class="key">return</span> <span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t331" href="#t331">331</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t332" href="#t332">332</a></span><span class="t"> <span class="com"># Recursively resolve parent styles</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t333" href="#t333">333</a></span><span class="t"> <span class="nam">parent_style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">resolve_effective_style</span><span class="op">(</span><span class="nam">style</span><span class="op">.</span><span class="nam">parent_style_id</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t334" href="#t334">334</a></span><span class="t"> <span class="key">return</span> <span class="nam">parent_style</span><span class="op">.</span><span class="nam">merge_with</span><span class="op">(</span><span class="nam">style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t335" href="#t335">335</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t336" href="#t336">336</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_all_styles</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">AbstractStyle</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t337" href="#t337">337</a></span><span class="t"> <span class="str">"""Get all registered styles."""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t338" href="#t338">338</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_styles</span><span class="op">.</span><span class="nam">copy</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t339" href="#t339">339</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t340" href="#t340">340</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_style_count</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t341" href="#t341">341</a></span><span class="t"> <span class="str">"""Get the number of registered styles."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t342" href="#t342">342</a></span><span class="t"> <span class="key">return</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_styles</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_ba7f6bdeb0188088___init___py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_ba7f6bdeb0188088_alignment_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,124 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/style/alignment.py: 91%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/style/alignment.py</b>:
<span class="pc_cov">91%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">11 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">10<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">1<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">3<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">0<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_ba7f6bdeb0188088_abstract_style_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_ba7f6bdeb0188088_concrete_style_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">Alignment options for the pyWebLayout library.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">This module provides alignment-related functionality.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="key">from</span> <span class="nam">enum</span> <span class="key">import</span> <span class="nam">Enum</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="key">class</span> <span class="nam">Alignment</span><span class="op">(</span><span class="nam">Enum</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"> <span class="str">"""Text and box alignment options"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"> <span class="com"># Horizontal alignment</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"> <span class="nam">LEFT</span> <span class="op">=</span> <span class="str">"left"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t"> <span class="nam">RIGHT</span> <span class="op">=</span> <span class="str">"right"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"> <span class="nam">CENTER</span> <span class="op">=</span> <span class="str">"center"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"> <span class="nam">JUSTIFY</span> <span class="op">=</span> <span class="str">"justify"</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"> <span class="com"># Vertical alignment</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"> <span class="nam">TOP</span> <span class="op">=</span> <span class="str">"top"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"> <span class="nam">MIDDLE</span> <span class="op">=</span> <span class="str">"middle"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"> <span class="nam">BOTTOM</span> <span class="op">=</span> <span class="str">"bottom"</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"> <span class="key">def</span> <span class="nam">__str__</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"> <span class="str">"""Return the string value of the alignment."""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">value</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_ba7f6bdeb0188088_abstract_style_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_ba7f6bdeb0188088_concrete_style_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,583 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/style/concrete_style.py: 63%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/style/concrete_style.py</b>:
<span class="pc_cov">63%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">207 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">141<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">66<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">23<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">12<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_ba7f6bdeb0188088_alignment_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_ba7f6bdeb0188088_fonts_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">Concrete style system for actual rendering parameters.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">This module converts abstract styles to concrete rendering parameters based on</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">user preferences, device capabilities, and rendering context.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">Dict</span><span class="op">,</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">Tuple</span><span class="op">,</span> <span class="nam">Union</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="key">from</span> <span class="nam">dataclasses</span> <span class="key">import</span> <span class="nam">dataclass</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">abstract_style</span> <span class="key">import</span> <span class="nam">AbstractStyle</span><span class="op">,</span> <span class="nam">FontFamily</span><span class="op">,</span> <span class="nam">FontSize</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"><span class="key">from</span> <span class="nam">pyWebLayout</span><span class="op">.</span><span class="nam">style</span><span class="op">.</span><span class="nam">alignment</span> <span class="key">import</span> <span class="nam">Alignment</span> <span class="key">as</span> <span class="nam">TextAlign</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="key">from</span> <span class="op">.</span><span class="nam">fonts</span> <span class="key">import</span> <span class="nam">Font</span><span class="op">,</span> <span class="nam">FontWeight</span><span class="op">,</span> <span class="nam">FontStyle</span><span class="op">,</span> <span class="nam">TextDecoration</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"><span class="op">@</span><span class="nam">dataclass</span><span class="op">(</span><span class="nam">frozen</span><span class="op">=</span><span class="key">True</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"><span class="key">class</span> <span class="nam">RenderingContext</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"><span class="str"> Context information for style resolution.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"><span class="str"> Contains user preferences and device capabilities.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t"> <span class="com"># User preferences</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"> <span class="nam">base_font_size</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">16</span> <span class="com"># Base font size in points</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"> <span class="nam">font_scale_factor</span><span class="op">:</span> <span class="nam">float</span> <span class="op">=</span> <span class="num">1.0</span> <span class="com"># Global font scaling</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"> <span class="nam">preferred_serif_font</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"> <span class="nam">preferred_sans_serif_font</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"> <span class="nam">preferred_monospace_font</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"> <span class="com"># Device/environment info</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"> <span class="nam">dpi</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">96</span> <span class="com"># Dots per inch</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"> <span class="nam">available_width</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span> <span class="com"># Available width in pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t"> <span class="nam">available_height</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span> <span class="com"># Available height in pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"> <span class="com"># Accessibility preferences</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"> <span class="nam">high_contrast</span><span class="op">:</span> <span class="nam">bool</span> <span class="op">=</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"> <span class="nam">large_text</span><span class="op">:</span> <span class="nam">bool</span> <span class="op">=</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"> <span class="nam">reduce_motion</span><span class="op">:</span> <span class="nam">bool</span> <span class="op">=</span> <span class="key">False</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"> <span class="com"># Language and locale</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"> <span class="nam">default_language</span><span class="op">:</span> <span class="nam">str</span> <span class="op">=</span> <span class="str">"en-US"</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t"><span class="op">@</span><span class="nam">dataclass</span><span class="op">(</span><span class="nam">frozen</span><span class="op">=</span><span class="key">True</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t"><span class="key">class</span> <span class="nam">ConcreteStyle</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"><span class="str"> Concrete representation of text styling with actual rendering parameters.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"><span class="str"> This contains the resolved font files, pixel sizes, actual colors, etc.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t"><span class="str"> that will be used for rendering. This is also hashable for efficient caching.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t"> <span class="com"># Concrete font properties</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"> <span class="nam">font_path</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t"> <span class="nam">font_size</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">16</span> <span class="com"># Always in points/pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"> <span class="nam">color</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span> <span class="com"># Always RGB</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t"> <span class="nam">background_color</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span> <span class="com"># Always RGBA or None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t"> <span class="com"># Font attributes</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"> <span class="nam">weight</span><span class="op">:</span> <span class="nam">FontWeight</span> <span class="op">=</span> <span class="nam">FontWeight</span><span class="op">.</span><span class="nam">NORMAL</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"> <span class="nam">style</span><span class="op">:</span> <span class="nam">FontStyle</span> <span class="op">=</span> <span class="nam">FontStyle</span><span class="op">.</span><span class="nam">NORMAL</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"> <span class="nam">decoration</span><span class="op">:</span> <span class="nam">TextDecoration</span> <span class="op">=</span> <span class="nam">TextDecoration</span><span class="op">.</span><span class="nam">NONE</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t"> <span class="com"># Layout properties</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"> <span class="nam">text_align</span><span class="op">:</span> <span class="nam">TextAlign</span> <span class="op">=</span> <span class="nam">TextAlign</span><span class="op">.</span><span class="nam">LEFT</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"> <span class="nam">line_height</span><span class="op">:</span> <span class="nam">float</span> <span class="op">=</span> <span class="num">1.0</span> <span class="com"># Multiplier</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t"> <span class="nam">letter_spacing</span><span class="op">:</span> <span class="nam">float</span> <span class="op">=</span> <span class="num">0.0</span> <span class="com"># In pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t"> <span class="nam">word_spacing</span><span class="op">:</span> <span class="nam">float</span> <span class="op">=</span> <span class="num">0.0</span> <span class="com"># In pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"> <span class="nam">word_spacing_min</span><span class="op">:</span> <span class="nam">float</span> <span class="op">=</span> <span class="num">0.0</span> <span class="com"># Minimum word spacing in pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"> <span class="nam">word_spacing_max</span><span class="op">:</span> <span class="nam">float</span> <span class="op">=</span> <span class="num">0.0</span> <span class="com"># Maximum word spacing in pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t"> <span class="com"># Language and locale</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t"> <span class="nam">language</span><span class="op">:</span> <span class="nam">str</span> <span class="op">=</span> <span class="str">"en-US"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"> <span class="nam">min_hyphenation_width</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">64</span> <span class="com"># In pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"> <span class="com"># Reference to source abstract style</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t"> <span class="nam">abstract_style</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">AbstractStyle</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"> <span class="key">def</span> <span class="nam">create_font</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Font</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t"> <span class="str">"""Create a Font object from this concrete style."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t"> <span class="key">return</span> <span class="nam">Font</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t"> <span class="nam">font_path</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">font_path</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t"> <span class="nam">font_size</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">font_size</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t"> <span class="nam">colour</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">color</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"> <span class="nam">weight</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">weight</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t"> <span class="nam">style</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t"> <span class="nam">decoration</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">decoration</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t"> <span class="nam">background</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">background_color</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t"> <span class="nam">language</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">language</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"> <span class="nam">min_hyphenation_width</span><span class="op">=</span><span class="nam">self</span><span class="op">.</span><span class="nam">min_hyphenation_width</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t"><span class="key">class</span> <span class="nam">StyleResolver</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t"><span class="str"> Resolves abstract styles to concrete styles based on rendering context.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t"><span class="str"> This class handles the conversion from semantic styling intent to actual</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t"><span class="str"> rendering parameters, applying user preferences and device capabilities.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">context</span><span class="op">:</span> <span class="nam">RenderingContext</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t"><span class="str"> Initialize the style resolver with a rendering context.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t"><span class="str"> context: RenderingContext with user preferences and device info</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">context</span> <span class="op">=</span> <span class="nam">context</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_concrete_cache</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">AbstractStyle</span><span class="op">,</span> <span class="nam">ConcreteStyle</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t"> <span class="com"># Font size mapping for semantic sizes</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_semantic_font_sizes</span> <span class="op">=</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t"> <span class="nam">FontSize</span><span class="op">.</span><span class="nam">XX_SMALL</span><span class="op">:</span> <span class="num">0.6</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t"> <span class="nam">FontSize</span><span class="op">.</span><span class="nam">X_SMALL</span><span class="op">:</span> <span class="num">0.75</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t"> <span class="nam">FontSize</span><span class="op">.</span><span class="nam">SMALL</span><span class="op">:</span> <span class="num">0.89</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"> <span class="nam">FontSize</span><span class="op">.</span><span class="nam">MEDIUM</span><span class="op">:</span> <span class="num">1.0</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t"> <span class="nam">FontSize</span><span class="op">.</span><span class="nam">LARGE</span><span class="op">:</span> <span class="num">1.2</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t"> <span class="nam">FontSize</span><span class="op">.</span><span class="nam">X_LARGE</span><span class="op">:</span> <span class="num">1.5</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"> <span class="nam">FontSize</span><span class="op">.</span><span class="nam">XX_LARGE</span><span class="op">:</span> <span class="num">2.0</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t"> <span class="com"># Color name mapping</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_color_names</span> <span class="op">=</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t"> <span class="str">"black"</span><span class="op">:</span> <span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t"> <span class="str">"white"</span><span class="op">:</span> <span class="op">(</span><span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t"> <span class="str">"red"</span><span class="op">:</span> <span class="op">(</span><span class="num">255</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t"> <span class="str">"green"</span><span class="op">:</span> <span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">128</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t"> <span class="str">"blue"</span><span class="op">:</span> <span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">255</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t"> <span class="str">"yellow"</span><span class="op">:</span> <span class="op">(</span><span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t"> <span class="str">"cyan"</span><span class="op">:</span> <span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t"> <span class="str">"magenta"</span><span class="op">:</span> <span class="op">(</span><span class="num">255</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">255</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t"> <span class="str">"silver"</span><span class="op">:</span> <span class="op">(</span><span class="num">192</span><span class="op">,</span> <span class="num">192</span><span class="op">,</span> <span class="num">192</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t"> <span class="str">"gray"</span><span class="op">:</span> <span class="op">(</span><span class="num">128</span><span class="op">,</span> <span class="num">128</span><span class="op">,</span> <span class="num">128</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t"> <span class="str">"maroon"</span><span class="op">:</span> <span class="op">(</span><span class="num">128</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t"> <span class="str">"olive"</span><span class="op">:</span> <span class="op">(</span><span class="num">128</span><span class="op">,</span> <span class="num">128</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t"> <span class="str">"lime"</span><span class="op">:</span> <span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t"> <span class="str">"aqua"</span><span class="op">:</span> <span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"> <span class="str">"teal"</span><span class="op">:</span> <span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">128</span><span class="op">,</span> <span class="num">128</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t"> <span class="str">"navy"</span><span class="op">:</span> <span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">128</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t"> <span class="str">"fuchsia"</span><span class="op">:</span> <span class="op">(</span><span class="num">255</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">255</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t"> <span class="str">"purple"</span><span class="op">:</span> <span class="op">(</span><span class="num">128</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">128</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"> <span class="key">def</span> <span class="nam">resolve_style</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">abstract_style</span><span class="op">:</span> <span class="nam">AbstractStyle</span><span class="op">)</span> <span class="op">-></span> <span class="nam">ConcreteStyle</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t"><span class="str"> Resolve an abstract style to a concrete style.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t"><span class="str"> abstract_style: AbstractStyle to resolve</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t"><span class="str"> ConcreteStyle with concrete rendering parameters</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t"> <span class="com"># Check cache first</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t"> <span class="key">if</span> <span class="nam">abstract_style</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_concrete_cache</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_concrete_cache</span><span class="op">[</span><span class="nam">abstract_style</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t"> <span class="com"># Resolve each property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t"> <span class="nam">font_path</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_resolve_font_path</span><span class="op">(</span><span class="nam">abstract_style</span><span class="op">.</span><span class="nam">font_family</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"> <span class="nam">font_size</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_resolve_font_size</span><span class="op">(</span><span class="nam">abstract_style</span><span class="op">.</span><span class="nam">font_size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t"> <span class="com"># Ensure font_size is always an int before using in arithmetic</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t"> <span class="nam">font_size</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">font_size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"> <span class="nam">color</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_resolve_color</span><span class="op">(</span><span class="nam">abstract_style</span><span class="op">.</span><span class="nam">color</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t"> <span class="nam">background_color</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_resolve_background_color</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t"> <span class="nam">abstract_style</span><span class="op">.</span><span class="nam">background_color</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"> <span class="nam">line_height</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_resolve_line_height</span><span class="op">(</span><span class="nam">abstract_style</span><span class="op">.</span><span class="nam">line_height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t"> <span class="nam">letter_spacing</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_resolve_letter_spacing</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t"> <span class="nam">abstract_style</span><span class="op">.</span><span class="nam">letter_spacing</span><span class="op">,</span> <span class="nam">font_size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t"> <span class="nam">word_spacing</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_resolve_word_spacing</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"> <span class="nam">abstract_style</span><span class="op">.</span><span class="nam">word_spacing</span><span class="op">,</span> <span class="nam">font_size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t"> <span class="nam">word_spacing_min</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_resolve_word_spacing</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t"> <span class="nam">abstract_style</span><span class="op">.</span><span class="nam">word_spacing_min</span><span class="op">,</span> <span class="nam">font_size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t"> <span class="nam">word_spacing_max</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_resolve_word_spacing</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t"> <span class="nam">abstract_style</span><span class="op">.</span><span class="nam">word_spacing_max</span><span class="op">,</span> <span class="nam">font_size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t"> <span class="nam">min_hyphenation_width</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">int</span><span class="op">(</span><span class="nam">font_size</span><span class="op">)</span> <span class="op">*</span> <span class="num">4</span><span class="op">,</span> <span class="num">32</span><span class="op">)</span> <span class="com"># At least 32 pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t"> <span class="com"># Apply default logic for word spacing constraints</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t"> <span class="key">if</span> <span class="nam">word_spacing_min</span> <span class="op">==</span> <span class="num">0.0</span> <span class="key">and</span> <span class="nam">word_spacing_max</span> <span class="op">==</span> <span class="num">0.0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t"> <span class="com"># If no constraints specified, use base word_spacing as reference</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t"> <span class="key">if</span> <span class="nam">word_spacing</span> <span class="op">></span> <span class="num">0.0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t"> <span class="nam">word_spacing_min</span> <span class="op">=</span> <span class="nam">word_spacing</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t"> <span class="nam">word_spacing_max</span> <span class="op">=</span> <span class="nam">word_spacing</span> <span class="op">*</span> <span class="num">2</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t"> <span class="com"># Default constraints when no word spacing is specified</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t"> <span class="nam">word_spacing_min</span> <span class="op">=</span> <span class="num">2.0</span> <span class="com"># Minimum 2 pixels</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t"> <span class="nam">word_spacing_max</span> <span class="op">=</span> <span class="nam">font_size</span> <span class="op">*</span> <span class="num">0.5</span> <span class="com"># Maximum 50% of font size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t"> <span class="key">elif</span> <span class="nam">word_spacing_min</span> <span class="op">==</span> <span class="num">0.0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t"> <span class="com"># Only max specified, use base word_spacing or min default</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t"> <span class="nam">word_spacing_min</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">word_spacing</span><span class="op">,</span> <span class="num">2.0</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t"> <span class="key">elif</span> <span class="nam">word_spacing_max</span> <span class="op">==</span> <span class="num">0.0</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t"> <span class="com"># Only min specified, use base word_spacing or reasonable multiple</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t"> <span class="nam">word_spacing_max</span> <span class="op">=</span> <span class="nam">max</span><span class="op">(</span><span class="nam">word_spacing</span><span class="op">,</span> <span class="nam">word_spacing_min</span> <span class="op">*</span> <span class="num">2</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t"> <span class="com"># Create concrete style</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t"> <span class="nam">concrete_style</span> <span class="op">=</span> <span class="nam">ConcreteStyle</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t"> <span class="nam">font_path</span><span class="op">=</span><span class="nam">font_path</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t"> <span class="nam">font_size</span><span class="op">=</span><span class="nam">font_size</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t"> <span class="nam">color</span><span class="op">=</span><span class="nam">color</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t"> <span class="nam">background_color</span><span class="op">=</span><span class="nam">background_color</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t"> <span class="nam">weight</span><span class="op">=</span><span class="nam">abstract_style</span><span class="op">.</span><span class="nam">font_weight</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t"> <span class="nam">style</span><span class="op">=</span><span class="nam">abstract_style</span><span class="op">.</span><span class="nam">font_style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t"> <span class="nam">decoration</span><span class="op">=</span><span class="nam">abstract_style</span><span class="op">.</span><span class="nam">text_decoration</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t"> <span class="nam">text_align</span><span class="op">=</span><span class="nam">abstract_style</span><span class="op">.</span><span class="nam">text_align</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t"> <span class="nam">line_height</span><span class="op">=</span><span class="nam">line_height</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t"> <span class="nam">letter_spacing</span><span class="op">=</span><span class="nam">letter_spacing</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t"> <span class="nam">word_spacing</span><span class="op">=</span><span class="nam">word_spacing</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t"> <span class="nam">word_spacing_min</span><span class="op">=</span><span class="nam">word_spacing_min</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t"> <span class="nam">word_spacing_max</span><span class="op">=</span><span class="nam">word_spacing_max</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t"> <span class="nam">language</span><span class="op">=</span><span class="nam">abstract_style</span><span class="op">.</span><span class="nam">language</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t"> <span class="nam">min_hyphenation_width</span><span class="op">=</span><span class="nam">min_hyphenation_width</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t"> <span class="nam">abstract_style</span><span class="op">=</span><span class="nam">abstract_style</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t"> <span class="com"># Cache and return</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_concrete_cache</span><span class="op">[</span><span class="nam">abstract_style</span><span class="op">]</span> <span class="op">=</span> <span class="nam">concrete_style</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t"> <span class="key">return</span> <span class="nam">concrete_style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t"> <span class="key">def</span> <span class="nam">_resolve_font_path</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">font_family</span><span class="op">:</span> <span class="nam">FontFamily</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t"> <span class="str">"""Resolve font family to actual font file path."""</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t"> <span class="key">if</span> <span class="nam">font_family</span> <span class="op">==</span> <span class="nam">FontFamily</span><span class="op">.</span><span class="nam">SERIF</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">220&#x202F;&#x219B;&#x202F;222</span><span class="annotate long">line 220 didn't jump to line 222 because the condition on line 220 was always true</span></span></p>
<p class="run"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">context</span><span class="op">.</span><span class="nam">preferred_serif_font</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"> <span class="key">elif</span> <span class="nam">font_family</span> <span class="op">==</span> <span class="nam">FontFamily</span><span class="op">.</span><span class="nam">SANS_SERIF</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">context</span><span class="op">.</span><span class="nam">preferred_sans_serif_font</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t"> <span class="key">elif</span> <span class="nam">font_family</span> <span class="op">==</span> <span class="nam">FontFamily</span><span class="op">.</span><span class="nam">MONOSPACE</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">context</span><span class="op">.</span><span class="nam">preferred_monospace_font</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t"> <span class="com"># For cursive and fantasy, fall back to sans-serif</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">context</span><span class="op">.</span><span class="nam">preferred_sans_serif_font</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t"> <span class="key">def</span> <span class="nam">_resolve_font_size</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">font_size</span><span class="op">:</span> <span class="nam">Union</span><span class="op">[</span><span class="nam">FontSize</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t"> <span class="str">"""Resolve font size to actual pixel/point size."""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t"> <span class="com"># Ensure we handle FontSize enums properly</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">font_size</span><span class="op">,</span> <span class="nam">FontSize</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t"> <span class="com"># Semantic size, convert to multiplier</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t"> <span class="nam">multiplier</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_semantic_font_sizes</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="nam">font_size</span><span class="op">,</span> <span class="num">1.0</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t"> <span class="nam">base_size</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">context</span><span class="op">.</span><span class="nam">base_font_size</span> <span class="op">*</span> <span class="nam">multiplier</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t"> <span class="key">elif</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">font_size</span><span class="op">,</span> <span class="nam">int</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">237&#x202F;&#x219B;&#x202F;242</span><span class="annotate long">line 237 didn't jump to line 242 because the condition on line 237 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t"> <span class="com"># Already a concrete size, apply scaling</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t"> <span class="nam">base_size</span> <span class="op">=</span> <span class="nam">font_size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t"> <span class="com"># Fallback for any other type - try to convert to int</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t"> <span class="nam">base_size</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">font_size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t"> <span class="key">except</span> <span class="op">(</span><span class="nam">ValueError</span><span class="op">,</span> <span class="nam">TypeError</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t"> <span class="com"># If conversion fails, use default</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t"> <span class="nam">base_size</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">context</span><span class="op">.</span><span class="nam">base_font_size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t"> <span class="com"># Apply global font scaling</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t"> <span class="nam">final_size</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">base_size</span> <span class="op">*</span> <span class="nam">self</span><span class="op">.</span><span class="nam">context</span><span class="op">.</span><span class="nam">font_scale_factor</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t"> <span class="com"># Apply accessibility adjustments</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">context</span><span class="op">.</span><span class="nam">large_text</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t"> <span class="nam">final_size</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">final_size</span> <span class="op">*</span> <span class="num">1.2</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t"> <span class="com"># Ensure we always return an int, minimum 8pt font</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t"> <span class="key">return</span> <span class="nam">max</span><span class="op">(</span><span class="nam">int</span><span class="op">(</span><span class="nam">final_size</span><span class="op">)</span><span class="op">,</span> <span class="num">8</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t"> <span class="key">def</span> <span class="nam">_resolve_color</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span> <span class="nam">color</span><span class="op">:</span> <span class="nam">Union</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t"> <span class="str">"""Resolve color to RGB tuple."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">color</span><span class="op">,</span> <span class="nam">tuple</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t"> <span class="key">return</span> <span class="nam">color</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">color</span><span class="op">,</span> <span class="nam">str</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">264&#x202F;&#x219B;&#x202F;299</span><span class="annotate long">line 264 didn't jump to line 299 because the condition on line 264 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t"> <span class="com"># Check if it's a named color</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t"> <span class="key">if</span> <span class="nam">color</span><span class="op">.</span><span class="nam">lower</span><span class="op">(</span><span class="op">)</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_color_names</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t"> <span class="nam">base_color</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_color_names</span><span class="op">[</span><span class="nam">color</span><span class="op">.</span><span class="nam">lower</span><span class="op">(</span><span class="op">)</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t"> <span class="key">elif</span> <span class="nam">color</span><span class="op">.</span><span class="nam">startswith</span><span class="op">(</span><span class="str">'#'</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">268&#x202F;&#x219B;&#x202F;285</span><span class="annotate long">line 268 didn't jump to line 285 because the condition on line 268 was always true</span></span></p>
<p class="pln"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t"> <span class="com"># Parse hex color</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t"> <span class="nam">hex_color</span> <span class="op">=</span> <span class="nam">color</span><span class="op">[</span><span class="num">1</span><span class="op">:</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t"> <span class="key">if</span> <span class="nam">len</span><span class="op">(</span><span class="nam">hex_color</span><span class="op">)</span> <span class="op">==</span> <span class="num">3</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">272&#x202F;&#x219B;&#x202F;274</span><span class="annotate long">line 272 didn't jump to line 274 because the condition on line 272 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t"> <span class="com"># Short hex format #RGB -> #RRGGBB</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t"> <span class="nam">hex_color</span> <span class="op">=</span> <span class="str">''</span><span class="op">.</span><span class="nam">join</span><span class="op">(</span><span class="nam">c</span> <span class="op">*</span> <span class="num">2</span> <span class="key">for</span> <span class="nam">c</span> <span class="key">in</span> <span class="nam">hex_color</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t"> <span class="key">if</span> <span class="nam">len</span><span class="op">(</span><span class="nam">hex_color</span><span class="op">)</span> <span class="op">==</span> <span class="num">6</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">275&#x202F;&#x219B;&#x202F;281</span><span class="annotate long">line 275 didn't jump to line 281 because the condition on line 275 was always true</span></span></p>
<p class="run"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t"> <span class="nam">r</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">hex_color</span><span class="op">[</span><span class="num">0</span><span class="op">:</span><span class="num">2</span><span class="op">]</span><span class="op">,</span> <span class="num">16</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t"> <span class="nam">g</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">hex_color</span><span class="op">[</span><span class="num">2</span><span class="op">:</span><span class="num">4</span><span class="op">]</span><span class="op">,</span> <span class="num">16</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t"> <span class="nam">b</span> <span class="op">=</span> <span class="nam">int</span><span class="op">(</span><span class="nam">hex_color</span><span class="op">[</span><span class="num">4</span><span class="op">:</span><span class="num">6</span><span class="op">]</span><span class="op">,</span> <span class="num">16</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t279" href="#t279">279</a></span><span class="t"> <span class="nam">base_color</span> <span class="op">=</span> <span class="op">(</span><span class="nam">r</span><span class="op">,</span> <span class="nam">g</span><span class="op">,</span> <span class="nam">b</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t280" href="#t280">280</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t281" href="#t281">281</a></span><span class="t"> <span class="nam">base_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span> <span class="com"># Fallback to black</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t282" href="#t282">282</a></span><span class="t"> <span class="key">except</span> <span class="nam">ValueError</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t283" href="#t283">283</a></span><span class="t"> <span class="nam">base_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span> <span class="com"># Fallback to black</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t284" href="#t284">284</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t285" href="#t285">285</a></span><span class="t"> <span class="nam">base_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span> <span class="com"># Fallback to black</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t286" href="#t286">286</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t287" href="#t287">287</a></span><span class="t"> <span class="com"># Apply high contrast if needed</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t288" href="#t288">288</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">context</span><span class="op">.</span><span class="nam">high_contrast</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">288&#x202F;&#x219B;&#x202F;290</span><span class="annotate long">line 288 didn't jump to line 290 because the condition on line 288 was never true</span></span></p>
<p class="pln"><span class="n"><a id="t289" href="#t289">289</a></span><span class="t"> <span class="com"># Simple high contrast: make dark colors black, light colors white</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t290" href="#t290">290</a></span><span class="t"> <span class="nam">r</span><span class="op">,</span> <span class="nam">g</span><span class="op">,</span> <span class="nam">b</span> <span class="op">=</span> <span class="nam">base_color</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t291" href="#t291">291</a></span><span class="t"> <span class="nam">brightness</span> <span class="op">=</span> <span class="op">(</span><span class="nam">r</span> <span class="op">+</span> <span class="nam">g</span> <span class="op">+</span> <span class="nam">b</span><span class="op">)</span> <span class="op">/</span> <span class="num">3</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t292" href="#t292">292</a></span><span class="t"> <span class="key">if</span> <span class="nam">brightness</span> <span class="op">&lt;</span> <span class="num">128</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t293" href="#t293">293</a></span><span class="t"> <span class="nam">base_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span> <span class="com"># Black</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t294" href="#t294">294</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t295" href="#t295">295</a></span><span class="t"> <span class="nam">base_color</span> <span class="op">=</span> <span class="op">(</span><span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">)</span> <span class="com"># White</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t296" href="#t296">296</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t297" href="#t297">297</a></span><span class="t"> <span class="key">return</span> <span class="nam">base_color</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t298" href="#t298">298</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t299" href="#t299">299</a></span><span class="t"> <span class="key">return</span> <span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span> <span class="com"># Fallback to black</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t300" href="#t300">300</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t301" href="#t301">301</a></span><span class="t"> <span class="key">def</span> <span class="nam">_resolve_background_color</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t302" href="#t302">302</a></span><span class="t"> <span class="nam">bg_color</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Union</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t303" href="#t303">303</a></span><span class="t"> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t304" href="#t304">304</a></span><span class="t"> <span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t305" href="#t305">305</a></span><span class="t"> <span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t306" href="#t306">306</a></span><span class="t"> <span class="nam">int</span><span class="op">]</span><span class="op">]</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t307" href="#t307">307</a></span><span class="t"> <span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t308" href="#t308">308</a></span><span class="t"> <span class="nam">int</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t309" href="#t309">309</a></span><span class="t"> <span class="nam">int</span><span class="op">]</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t310" href="#t310">310</a></span><span class="t"> <span class="str">"""Resolve background color to RGBA tuple or None."""</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t311" href="#t311">311</a></span><span class="t"> <span class="key">if</span> <span class="nam">bg_color</span> <span class="key">is</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">311&#x202F;&#x219B;&#x202F;314</span><span class="annotate long">line 311 didn't jump to line 314 because the condition on line 311 was always true</span></span></p>
<p class="run"><span class="n"><a id="t312" href="#t312">312</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t313" href="#t313">313</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t314" href="#t314">314</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">bg_color</span><span class="op">,</span> <span class="nam">tuple</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t315" href="#t315">315</a></span><span class="t"> <span class="key">if</span> <span class="nam">len</span><span class="op">(</span><span class="nam">bg_color</span><span class="op">)</span> <span class="op">==</span> <span class="num">3</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t316" href="#t316">316</a></span><span class="t"> <span class="com"># RGB -> RGBA</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t317" href="#t317">317</a></span><span class="t"> <span class="key">return</span> <span class="nam">bg_color</span> <span class="op">+</span> <span class="op">(</span><span class="num">255</span><span class="op">,</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t318" href="#t318">318</a></span><span class="t"> <span class="key">return</span> <span class="nam">bg_color</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t319" href="#t319">319</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t320" href="#t320">320</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">bg_color</span><span class="op">,</span> <span class="nam">str</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t321" href="#t321">321</a></span><span class="t"> <span class="key">if</span> <span class="nam">bg_color</span><span class="op">.</span><span class="nam">lower</span><span class="op">(</span><span class="op">)</span> <span class="op">==</span> <span class="str">"transparent"</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t322" href="#t322">322</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t323" href="#t323">323</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t324" href="#t324">324</a></span><span class="t"> <span class="com"># Resolve as RGB then add alpha</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t325" href="#t325">325</a></span><span class="t"> <span class="nam">rgb</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_resolve_color</span><span class="op">(</span><span class="nam">bg_color</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t326" href="#t326">326</a></span><span class="t"> <span class="key">return</span> <span class="nam">rgb</span> <span class="op">+</span> <span class="op">(</span><span class="num">255</span><span class="op">,</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t327" href="#t327">327</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t328" href="#t328">328</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t329" href="#t329">329</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t330" href="#t330">330</a></span><span class="t"> <span class="key">def</span> <span class="nam">_resolve_line_height</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">line_height</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Union</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">float</span><span class="op">]</span><span class="op">]</span><span class="op">)</span> <span class="op">-></span> <span class="nam">float</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t331" href="#t331">331</a></span><span class="t"> <span class="str">"""Resolve line height to multiplier."""</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t332" href="#t332">332</a></span><span class="t"> <span class="key">if</span> <span class="nam">line_height</span> <span class="key">is</span> <span class="key">None</span> <span class="key">or</span> <span class="nam">line_height</span> <span class="op">==</span> <span class="str">"normal"</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">332&#x202F;&#x219B;&#x202F;335</span><span class="annotate long">line 332 didn't jump to line 335 because the condition on line 332 was always true</span></span></p>
<p class="run"><span class="n"><a id="t333" href="#t333">333</a></span><span class="t"> <span class="key">return</span> <span class="num">1.2</span> <span class="com"># Default line height</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t334" href="#t334">334</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t335" href="#t335">335</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">line_height</span><span class="op">,</span> <span class="op">(</span><span class="nam">int</span><span class="op">,</span> <span class="nam">float</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t336" href="#t336">336</a></span><span class="t"> <span class="key">return</span> <span class="nam">float</span><span class="op">(</span><span class="nam">line_height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t337" href="#t337">337</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t338" href="#t338">338</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">line_height</span><span class="op">,</span> <span class="nam">str</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t339" href="#t339">339</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t340" href="#t340">340</a></span><span class="t"> <span class="key">return</span> <span class="nam">float</span><span class="op">(</span><span class="nam">line_height</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t341" href="#t341">341</a></span><span class="t"> <span class="key">except</span> <span class="nam">ValueError</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t342" href="#t342">342</a></span><span class="t"> <span class="key">return</span> <span class="num">1.2</span> <span class="com"># Fallback</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t343" href="#t343">343</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t344" href="#t344">344</a></span><span class="t"> <span class="key">return</span> <span class="num">1.2</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t345" href="#t345">345</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t346" href="#t346">346</a></span><span class="t"> <span class="key">def</span> <span class="nam">_resolve_letter_spacing</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t347" href="#t347">347</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span> <span class="nam">letter_spacing</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Union</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">float</span><span class="op">]</span><span class="op">]</span><span class="op">,</span> <span class="nam">font_size</span><span class="op">:</span> <span class="nam">int</span><span class="op">)</span> <span class="op">-></span> <span class="nam">float</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t348" href="#t348">348</a></span><span class="t"> <span class="str">"""Resolve letter spacing to pixels."""</span>&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t349" href="#t349">349</a></span><span class="t"> <span class="key">if</span> <span class="nam">letter_spacing</span> <span class="key">is</span> <span class="key">None</span> <span class="key">or</span> <span class="nam">letter_spacing</span> <span class="op">==</span> <span class="str">"normal"</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">349&#x202F;&#x219B;&#x202F;352</span><span class="annotate long">line 349 didn't jump to line 352 because the condition on line 349 was always true</span></span></p>
<p class="run"><span class="n"><a id="t350" href="#t350">350</a></span><span class="t"> <span class="key">return</span> <span class="num">0.0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t351" href="#t351">351</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t352" href="#t352">352</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">letter_spacing</span><span class="op">,</span> <span class="op">(</span><span class="nam">int</span><span class="op">,</span> <span class="nam">float</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t353" href="#t353">353</a></span><span class="t"> <span class="key">return</span> <span class="nam">float</span><span class="op">(</span><span class="nam">letter_spacing</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t354" href="#t354">354</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t355" href="#t355">355</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">letter_spacing</span><span class="op">,</span> <span class="nam">str</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t356" href="#t356">356</a></span><span class="t"> <span class="key">if</span> <span class="nam">letter_spacing</span><span class="op">.</span><span class="nam">endswith</span><span class="op">(</span><span class="str">"em"</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t357" href="#t357">357</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t358" href="#t358">358</a></span><span class="t"> <span class="nam">em_value</span> <span class="op">=</span> <span class="nam">float</span><span class="op">(</span><span class="nam">letter_spacing</span><span class="op">[</span><span class="op">:</span><span class="op">-</span><span class="num">2</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t359" href="#t359">359</a></span><span class="t"> <span class="key">return</span> <span class="nam">em_value</span> <span class="op">*</span> <span class="nam">font_size</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t360" href="#t360">360</a></span><span class="t"> <span class="key">except</span> <span class="nam">ValueError</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t361" href="#t361">361</a></span><span class="t"> <span class="key">return</span> <span class="num">0.0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t362" href="#t362">362</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t363" href="#t363">363</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t364" href="#t364">364</a></span><span class="t"> <span class="key">return</span> <span class="nam">float</span><span class="op">(</span><span class="nam">letter_spacing</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t365" href="#t365">365</a></span><span class="t"> <span class="key">except</span> <span class="nam">ValueError</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t366" href="#t366">366</a></span><span class="t"> <span class="key">return</span> <span class="num">0.0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t367" href="#t367">367</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t368" href="#t368">368</a></span><span class="t"> <span class="key">return</span> <span class="num">0.0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t369" href="#t369">369</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t370" href="#t370">370</a></span><span class="t"> <span class="key">def</span> <span class="nam">_resolve_word_spacing</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t371" href="#t371">371</a></span><span class="t"> <span class="nam">self</span><span class="op">,</span> <span class="nam">word_spacing</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Union</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">float</span><span class="op">]</span><span class="op">]</span><span class="op">,</span> <span class="nam">font_size</span><span class="op">:</span> <span class="nam">int</span><span class="op">)</span> <span class="op">-></span> <span class="nam">float</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t372" href="#t372">372</a></span><span class="t"> <span class="str">"""Resolve word spacing to pixels."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t373" href="#t373">373</a></span><span class="t"> <span class="key">if</span> <span class="nam">word_spacing</span> <span class="key">is</span> <span class="key">None</span> <span class="key">or</span> <span class="nam">word_spacing</span> <span class="op">==</span> <span class="str">"normal"</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t374" href="#t374">374</a></span><span class="t"> <span class="key">return</span> <span class="num">0.0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t375" href="#t375">375</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t376" href="#t376">376</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">word_spacing</span><span class="op">,</span> <span class="op">(</span><span class="nam">int</span><span class="op">,</span> <span class="nam">float</span><span class="op">)</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t377" href="#t377">377</a></span><span class="t"> <span class="key">return</span> <span class="nam">float</span><span class="op">(</span><span class="nam">word_spacing</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t378" href="#t378">378</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t379" href="#t379">379</a></span><span class="t"> <span class="key">if</span> <span class="nam">isinstance</span><span class="op">(</span><span class="nam">word_spacing</span><span class="op">,</span> <span class="nam">str</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">379&#x202F;&#x219B;&#x202F;392</span><span class="annotate long">line 379 didn't jump to line 392 because the condition on line 379 was always true</span></span></p>
<p class="par run show_par"><span class="n"><a id="t380" href="#t380">380</a></span><span class="t"> <span class="key">if</span> <span class="nam">word_spacing</span><span class="op">.</span><span class="nam">endswith</span><span class="op">(</span><span class="str">"em"</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">380&#x202F;&#x219B;&#x202F;387</span><span class="annotate long">line 380 didn't jump to line 387 because the condition on line 380 was always true</span></span></p>
<p class="run"><span class="n"><a id="t381" href="#t381">381</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t382" href="#t382">382</a></span><span class="t"> <span class="nam">em_value</span> <span class="op">=</span> <span class="nam">float</span><span class="op">(</span><span class="nam">word_spacing</span><span class="op">[</span><span class="op">:</span><span class="op">-</span><span class="num">2</span><span class="op">]</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t383" href="#t383">383</a></span><span class="t"> <span class="key">return</span> <span class="nam">em_value</span> <span class="op">*</span> <span class="nam">font_size</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t384" href="#t384">384</a></span><span class="t"> <span class="key">except</span> <span class="nam">ValueError</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t385" href="#t385">385</a></span><span class="t"> <span class="key">return</span> <span class="num">0.0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t386" href="#t386">386</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t387" href="#t387">387</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t388" href="#t388">388</a></span><span class="t"> <span class="key">return</span> <span class="nam">float</span><span class="op">(</span><span class="nam">word_spacing</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t389" href="#t389">389</a></span><span class="t"> <span class="key">except</span> <span class="nam">ValueError</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t390" href="#t390">390</a></span><span class="t"> <span class="key">return</span> <span class="num">0.0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t391" href="#t391">391</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t392" href="#t392">392</a></span><span class="t"> <span class="key">return</span> <span class="num">0.0</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t393" href="#t393">393</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t394" href="#t394">394</a></span><span class="t"> <span class="key">def</span> <span class="nam">update_context</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t395" href="#t395">395</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t396" href="#t396">396</a></span><span class="t"><span class="str"> Update the rendering context and clear cache.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t397" href="#t397">397</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t398" href="#t398">398</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t399" href="#t399">399</a></span><span class="t"><span class="str"> **kwargs: Context properties to update</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t400" href="#t400">400</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t401" href="#t401">401</a></span><span class="t"> <span class="com"># Create new context with updates</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t402" href="#t402">402</a></span><span class="t"> <span class="nam">context_dict</span> <span class="op">=</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t403" href="#t403">403</a></span><span class="t"> <span class="nam">field</span><span class="op">.</span><span class="nam">name</span><span class="op">:</span> <span class="nam">getattr</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">context</span><span class="op">,</span> <span class="nam">field</span><span class="op">.</span><span class="nam">name</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t404" href="#t404">404</a></span><span class="t"> <span class="key">for</span> <span class="nam">field</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">context</span><span class="op">.</span><span class="nam">__dataclass_fields__</span><span class="op">.</span><span class="nam">values</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t405" href="#t405">405</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t406" href="#t406">406</a></span><span class="t"> <span class="nam">context_dict</span><span class="op">.</span><span class="nam">update</span><span class="op">(</span><span class="nam">kwargs</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t407" href="#t407">407</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t408" href="#t408">408</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">context</span> <span class="op">=</span> <span class="nam">RenderingContext</span><span class="op">(</span><span class="op">**</span><span class="nam">context_dict</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t409" href="#t409">409</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t410" href="#t410">410</a></span><span class="t"> <span class="com"># Clear cache since context changed</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t411" href="#t411">411</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_concrete_cache</span><span class="op">.</span><span class="nam">clear</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t412" href="#t412">412</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t413" href="#t413">413</a></span><span class="t"> <span class="key">def</span> <span class="nam">clear_cache</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t414" href="#t414">414</a></span><span class="t"> <span class="str">"""Clear the concrete style cache."""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t415" href="#t415">415</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_concrete_cache</span><span class="op">.</span><span class="nam">clear</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t416" href="#t416">416</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t417" href="#t417">417</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_cache_size</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t418" href="#t418">418</a></span><span class="t"> <span class="str">"""Get the number of cached concrete styles."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t419" href="#t419">419</a></span><span class="t"> <span class="key">return</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_concrete_cache</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t420" href="#t420">420</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t421" href="#t421">421</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t422" href="#t422">422</a></span><span class="t"><span class="key">class</span> <span class="nam">ConcreteStyleRegistry</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t423" href="#t423">423</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t424" href="#t424">424</a></span><span class="t"><span class="str"> Registry for managing concrete styles with efficient caching.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t425" href="#t425">425</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t426" href="#t426">426</a></span><span class="t"><span class="str"> This registry manages the mapping between abstract and concrete styles,</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t427" href="#t427">427</a></span><span class="t"><span class="str"> and provides efficient access to Font objects for rendering.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t428" href="#t428">428</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t429" href="#t429">429</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t430" href="#t430">430</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">resolver</span><span class="op">:</span> <span class="nam">StyleResolver</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t431" href="#t431">431</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t432" href="#t432">432</a></span><span class="t"><span class="str"> Initialize the concrete style registry.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t433" href="#t433">433</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t434" href="#t434">434</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t435" href="#t435">435</a></span><span class="t"><span class="str"> resolver: StyleResolver for converting abstract to concrete styles</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t436" href="#t436">436</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t437" href="#t437">437</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">resolver</span> <span class="op">=</span> <span class="nam">resolver</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t438" href="#t438">438</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_font_cache</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">ConcreteStyle</span><span class="op">,</span> <span class="nam">Font</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t439" href="#t439">439</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t440" href="#t440">440</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_concrete_style</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">abstract_style</span><span class="op">:</span> <span class="nam">AbstractStyle</span><span class="op">)</span> <span class="op">-></span> <span class="nam">ConcreteStyle</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t441" href="#t441">441</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t442" href="#t442">442</a></span><span class="t"><span class="str"> Get a concrete style for an abstract style.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t443" href="#t443">443</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t444" href="#t444">444</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t445" href="#t445">445</a></span><span class="t"><span class="str"> abstract_style: AbstractStyle to resolve</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t446" href="#t446">446</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t447" href="#t447">447</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t448" href="#t448">448</a></span><span class="t"><span class="str"> ConcreteStyle with rendering parameters</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t449" href="#t449">449</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t450" href="#t450">450</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">resolver</span><span class="op">.</span><span class="nam">resolve_style</span><span class="op">(</span><span class="nam">abstract_style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t451" href="#t451">451</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t452" href="#t452">452</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_font</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">abstract_style</span><span class="op">:</span> <span class="nam">AbstractStyle</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Font</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t453" href="#t453">453</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t454" href="#t454">454</a></span><span class="t"><span class="str"> Get a Font object for an abstract style.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t455" href="#t455">455</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t456" href="#t456">456</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t457" href="#t457">457</a></span><span class="t"><span class="str"> abstract_style: AbstractStyle to get font for</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t458" href="#t458">458</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t459" href="#t459">459</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t460" href="#t460">460</a></span><span class="t"><span class="str"> Font object ready for rendering</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t461" href="#t461">461</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t462" href="#t462">462</a></span><span class="t"> <span class="nam">concrete_style</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">get_concrete_style</span><span class="op">(</span><span class="nam">abstract_style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t463" href="#t463">463</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t464" href="#t464">464</a></span><span class="t"> <span class="com"># Check font cache</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t465" href="#t465">465</a></span><span class="t"> <span class="key">if</span> <span class="nam">concrete_style</span> <span class="key">in</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_font_cache</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t466" href="#t466">466</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_font_cache</span><span class="op">[</span><span class="nam">concrete_style</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t467" href="#t467">467</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t468" href="#t468">468</a></span><span class="t"> <span class="com"># Create and cache font</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t469" href="#t469">469</a></span><span class="t"> <span class="nam">font</span> <span class="op">=</span> <span class="nam">concrete_style</span><span class="op">.</span><span class="nam">create_font</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t470" href="#t470">470</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_font_cache</span><span class="op">[</span><span class="nam">concrete_style</span><span class="op">]</span> <span class="op">=</span> <span class="nam">font</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t471" href="#t471">471</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t472" href="#t472">472</a></span><span class="t"> <span class="key">return</span> <span class="nam">font</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t473" href="#t473">473</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t474" href="#t474">474</a></span><span class="t"> <span class="key">def</span> <span class="nam">clear_caches</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t475" href="#t475">475</a></span><span class="t"> <span class="str">"""Clear all caches."""</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t476" href="#t476">476</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">resolver</span><span class="op">.</span><span class="nam">clear_cache</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t477" href="#t477">477</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_font_cache</span><span class="op">.</span><span class="nam">clear</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t478" href="#t478">478</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t479" href="#t479">479</a></span><span class="t"> <span class="key">def</span> <span class="nam">get_cache_stats</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">str</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t480" href="#t480">480</a></span><span class="t"> <span class="str">"""Get cache statistics."""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t481" href="#t481">481</a></span><span class="t"> <span class="key">return</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t482" href="#t482">482</a></span><span class="t"> <span class="str">"concrete_styles"</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">resolver</span><span class="op">.</span><span class="nam">get_cache_size</span><span class="op">(</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t483" href="#t483">483</a></span><span class="t"> <span class="str">"fonts"</span><span class="op">:</span> <span class="nam">len</span><span class="op">(</span><span class="nam">self</span><span class="op">.</span><span class="nam">_font_cache</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t484" href="#t484">484</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_ba7f6bdeb0188088_alignment_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_ba7f6bdeb0188088_fonts_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,505 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/style/fonts.py: 66%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/style/fonts.py</b>:
<span class="pc_cov">66%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">161 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">118<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">43<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">23<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">2<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_ba7f6bdeb0188088_concrete_style_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_ba7f6bdeb0188088_page_style_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="pln"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="com"># this should contain classes for how different object can be rendered,</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="com"># e.g. bold, italic, regular</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t"><span class="key">from</span> <span class="nam">PIL</span> <span class="key">import</span> <span class="nam">ImageFont</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="key">from</span> <span class="nam">enum</span> <span class="key">import</span> <span class="nam">Enum</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">Tuple</span><span class="op">,</span> <span class="nam">Optional</span><span class="op">,</span> <span class="nam">Dict</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="key">import</span> <span class="nam">os</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"><span class="key">import</span> <span class="nam">logging</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="com"># Set up logging for font loading</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t"><span class="nam">logger</span> <span class="op">=</span> <span class="nam">logging</span><span class="op">.</span><span class="nam">getLogger</span><span class="op">(</span><span class="nam">__name__</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"><span class="com"># Global cache for PIL ImageFont objects to avoid reloading fonts from disk</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"><span class="com"># Key: (font_path, font_size), Value: PIL ImageFont object</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t"><span class="nam">_FONT_CACHE</span><span class="op">:</span> <span class="nam">Dict</span><span class="op">[</span><span class="nam">Tuple</span><span class="op">[</span><span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">,</span> <span class="nam">ImageFont</span><span class="op">.</span><span class="nam">FreeTypeFont</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"><span class="com"># Cache for bundled font path to avoid repeated filesystem lookups</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"><span class="nam">_BUNDLED_FONT_PATH</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t"><span class="com"># Cache for bundled fonts directory</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"><span class="nam">_BUNDLED_FONTS_DIR</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"><span class="key">class</span> <span class="nam">FontWeight</span><span class="op">(</span><span class="nam">Enum</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"> <span class="nam">NORMAL</span> <span class="op">=</span> <span class="str">"normal"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t"> <span class="nam">BOLD</span> <span class="op">=</span> <span class="str">"bold"</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t"><span class="key">class</span> <span class="nam">FontStyle</span><span class="op">(</span><span class="nam">Enum</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"> <span class="nam">NORMAL</span> <span class="op">=</span> <span class="str">"normal"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"> <span class="nam">ITALIC</span> <span class="op">=</span> <span class="str">"italic"</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"><span class="key">class</span> <span class="nam">TextDecoration</span><span class="op">(</span><span class="nam">Enum</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"> <span class="nam">NONE</span> <span class="op">=</span> <span class="str">"none"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"> <span class="nam">UNDERLINE</span> <span class="op">=</span> <span class="str">"underline"</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t"> <span class="nam">STRIKETHROUGH</span> <span class="op">=</span> <span class="str">"strikethrough"</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"><span class="key">class</span> <span class="nam">BundledFont</span><span class="op">(</span><span class="nam">Enum</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t"> <span class="str">"""Bundled font families available in pyWebLayout"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t"> <span class="nam">SANS</span> <span class="op">=</span> <span class="str">"sans"</span> <span class="com"># DejaVu Sans - modern sans-serif</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t"> <span class="nam">SERIF</span> <span class="op">=</span> <span class="str">"serif"</span> <span class="com"># DejaVu Serif - classic serif</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t"> <span class="nam">MONOSPACE</span> <span class="op">=</span> <span class="str">"monospace"</span> <span class="com"># DejaVu Sans Mono - fixed-width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"><span class="key">def</span> <span class="nam">get_bundled_fonts_dir</span><span class="op">(</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"><span class="str"> Get the directory containing bundled fonts (cached).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t"><span class="str"> str: Path to the fonts directory, or None if not found</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"> <span class="key">global</span> <span class="nam">_BUNDLED_FONTS_DIR</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"> <span class="com"># Return cached path if available</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t"> <span class="key">if</span> <span class="nam">_BUNDLED_FONTS_DIR</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t"> <span class="key">return</span> <span class="nam">_BUNDLED_FONTS_DIR</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t59" href="#t59">59</a></span><span class="t"> <span class="com"># First time - determine the path and cache it</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t60" href="#t60">60</a></span><span class="t"> <span class="nam">current_dir</span> <span class="op">=</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">dirname</span><span class="op">(</span><span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">abspath</span><span class="op">(</span><span class="nam">__file__</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t61" href="#t61">61</a></span><span class="t"> <span class="nam">fonts_dir</span> <span class="op">=</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">join</span><span class="op">(</span><span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">dirname</span><span class="op">(</span><span class="nam">current_dir</span><span class="op">)</span><span class="op">,</span> <span class="str">'assets'</span><span class="op">,</span> <span class="str">'fonts'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t62" href="#t62">62</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t63" href="#t63">63</a></span><span class="t"> <span class="key">if</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">exists</span><span class="op">(</span><span class="nam">fonts_dir</span><span class="op">)</span> <span class="key">and</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">isdir</span><span class="op">(</span><span class="nam">fonts_dir</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t64" href="#t64">64</a></span><span class="t"> <span class="nam">_BUNDLED_FONTS_DIR</span> <span class="op">=</span> <span class="nam">fonts_dir</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t65" href="#t65">65</a></span><span class="t"> <span class="nam">logger</span><span class="op">.</span><span class="nam">debug</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Found bundled fonts directory at: </span><span class="op">{</span><span class="nam">fonts_dir</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t66" href="#t66">66</a></span><span class="t"> <span class="key">return</span> <span class="nam">fonts_dir</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t67" href="#t67">67</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t68" href="#t68">68</a></span><span class="t"> <span class="nam">logger</span><span class="op">.</span><span class="nam">warning</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Bundled fonts directory not found at: </span><span class="op">{</span><span class="nam">fonts_dir</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t69" href="#t69">69</a></span><span class="t"> <span class="nam">_BUNDLED_FONTS_DIR</span> <span class="op">=</span> <span class="str">""</span> <span class="com"># Empty string to indicate "checked but not found"</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t70" href="#t70">70</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t71" href="#t71">71</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t72" href="#t72">72</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t73" href="#t73">73</a></span><span class="t"><span class="key">def</span> <span class="nam">get_bundled_font_path</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t74" href="#t74">74</a></span><span class="t"> <span class="nam">family</span><span class="op">:</span> <span class="nam">BundledFont</span> <span class="op">=</span> <span class="nam">BundledFont</span><span class="op">.</span><span class="nam">SANS</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t75" href="#t75">75</a></span><span class="t"> <span class="nam">weight</span><span class="op">:</span> <span class="nam">FontWeight</span> <span class="op">=</span> <span class="nam">FontWeight</span><span class="op">.</span><span class="nam">NORMAL</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t76" href="#t76">76</a></span><span class="t"> <span class="nam">style</span><span class="op">:</span> <span class="nam">FontStyle</span> <span class="op">=</span> <span class="nam">FontStyle</span><span class="op">.</span><span class="nam">NORMAL</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t77" href="#t77">77</a></span><span class="t"><span class="op">)</span> <span class="op">-></span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t78" href="#t78">78</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t79" href="#t79">79</a></span><span class="t"><span class="str"> Get the path to a specific bundled font file.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t80" href="#t80">80</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t81" href="#t81">81</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t82" href="#t82">82</a></span><span class="t"><span class="str"> family: The font family (SANS, SERIF, or MONOSPACE)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t83" href="#t83">83</a></span><span class="t"><span class="str"> weight: The font weight (NORMAL or BOLD)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t84" href="#t84">84</a></span><span class="t"><span class="str"> style: The font style (NORMAL or ITALIC)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t85" href="#t85">85</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t86" href="#t86">86</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t87" href="#t87">87</a></span><span class="t"><span class="str"> str: Full path to the font file, or None if not found</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t88" href="#t88">88</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t89" href="#t89">89</a></span><span class="t"><span class="str"> Example:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t90" href="#t90">90</a></span><span class="t"><span class="str"> >>> # Get bold italic sans font</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t91" href="#t91">91</a></span><span class="t"><span class="str"> >>> path = get_bundled_font_path(BundledFont.SANS, FontWeight.BOLD, FontStyle.ITALIC)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t92" href="#t92">92</a></span><span class="t"><span class="str"> >>> font = Font(font_path=path, font_size=16)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t93" href="#t93">93</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t94" href="#t94">94</a></span><span class="t"> <span class="nam">fonts_dir</span> <span class="op">=</span> <span class="nam">get_bundled_fonts_dir</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t95" href="#t95">95</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">fonts_dir</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t96" href="#t96">96</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t97" href="#t97">97</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t98" href="#t98">98</a></span><span class="t"> <span class="com"># Map font parameters to filename</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t99" href="#t99">99</a></span><span class="t"> <span class="nam">family_map</span> <span class="op">=</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t100" href="#t100">100</a></span><span class="t"> <span class="nam">BundledFont</span><span class="op">.</span><span class="nam">SANS</span><span class="op">:</span> <span class="str">"DejaVuSans"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t101" href="#t101">101</a></span><span class="t"> <span class="nam">BundledFont</span><span class="op">.</span><span class="nam">SERIF</span><span class="op">:</span> <span class="str">"DejaVuSerif"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t102" href="#t102">102</a></span><span class="t"> <span class="nam">BundledFont</span><span class="op">.</span><span class="nam">MONOSPACE</span><span class="op">:</span> <span class="str">"DejaVuSansMono"</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t103" href="#t103">103</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t104" href="#t104">104</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t105" href="#t105">105</a></span><span class="t"> <span class="nam">base_name</span> <span class="op">=</span> <span class="nam">family_map</span><span class="op">.</span><span class="nam">get</span><span class="op">(</span><span class="nam">family</span><span class="op">,</span> <span class="str">"DejaVuSans"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t106" href="#t106">106</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t107" href="#t107">107</a></span><span class="t"> <span class="com"># Build the font file name</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t108" href="#t108">108</a></span><span class="t"> <span class="nam">parts</span> <span class="op">=</span> <span class="op">[</span><span class="nam">base_name</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t109" href="#t109">109</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t110" href="#t110">110</a></span><span class="t"> <span class="key">if</span> <span class="nam">weight</span> <span class="op">==</span> <span class="nam">FontWeight</span><span class="op">.</span><span class="nam">BOLD</span> <span class="key">and</span> <span class="nam">style</span> <span class="op">==</span> <span class="nam">FontStyle</span><span class="op">.</span><span class="nam">ITALIC</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t111" href="#t111">111</a></span><span class="t"> <span class="com"># Special case: both bold and italic</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t112" href="#t112">112</a></span><span class="t"> <span class="key">if</span> <span class="nam">family</span> <span class="op">==</span> <span class="nam">BundledFont</span><span class="op">.</span><span class="nam">MONOSPACE</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t113" href="#t113">113</a></span><span class="t"> <span class="nam">parts</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="str">"BoldOblique"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t114" href="#t114">114</a></span><span class="t"> <span class="key">elif</span> <span class="nam">family</span> <span class="op">==</span> <span class="nam">BundledFont</span><span class="op">.</span><span class="nam">SERIF</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t115" href="#t115">115</a></span><span class="t"> <span class="nam">parts</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="str">"BoldItalic"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t116" href="#t116">116</a></span><span class="t"> <span class="key">else</span><span class="op">:</span> <span class="com"># SANS</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t117" href="#t117">117</a></span><span class="t"> <span class="nam">parts</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="str">"BoldOblique"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t118" href="#t118">118</a></span><span class="t"> <span class="key">elif</span> <span class="nam">weight</span> <span class="op">==</span> <span class="nam">FontWeight</span><span class="op">.</span><span class="nam">BOLD</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t119" href="#t119">119</a></span><span class="t"> <span class="nam">parts</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="str">"Bold"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t120" href="#t120">120</a></span><span class="t"> <span class="key">elif</span> <span class="nam">style</span> <span class="op">==</span> <span class="nam">FontStyle</span><span class="op">.</span><span class="nam">ITALIC</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t121" href="#t121">121</a></span><span class="t"> <span class="com"># Italic naming differs by family</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t122" href="#t122">122</a></span><span class="t"> <span class="key">if</span> <span class="nam">family</span> <span class="op">==</span> <span class="nam">BundledFont</span><span class="op">.</span><span class="nam">MONOSPACE</span> <span class="key">or</span> <span class="nam">family</span> <span class="op">==</span> <span class="nam">BundledFont</span><span class="op">.</span><span class="nam">SANS</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t123" href="#t123">123</a></span><span class="t"> <span class="nam">parts</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="str">"Oblique"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t124" href="#t124">124</a></span><span class="t"> <span class="key">else</span><span class="op">:</span> <span class="com"># SERIF</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t125" href="#t125">125</a></span><span class="t"> <span class="nam">parts</span><span class="op">.</span><span class="nam">append</span><span class="op">(</span><span class="str">"Italic"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t126" href="#t126">126</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t127" href="#t127">127</a></span><span class="t"> <span class="nam">filename</span> <span class="op">=</span> <span class="str">"-"</span><span class="op">.</span><span class="nam">join</span><span class="op">(</span><span class="nam">parts</span><span class="op">)</span> <span class="op">+</span> <span class="str">".ttf"</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t128" href="#t128">128</a></span><span class="t"> <span class="nam">font_path</span> <span class="op">=</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">join</span><span class="op">(</span><span class="nam">fonts_dir</span><span class="op">,</span> <span class="nam">filename</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t129" href="#t129">129</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t130" href="#t130">130</a></span><span class="t"> <span class="key">if</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">exists</span><span class="op">(</span><span class="nam">font_path</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t131" href="#t131">131</a></span><span class="t"> <span class="nam">logger</span><span class="op">.</span><span class="nam">debug</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Found bundled font: </span><span class="op">{</span><span class="nam">filename</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t132" href="#t132">132</a></span><span class="t"> <span class="key">return</span> <span class="nam">font_path</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t133" href="#t133">133</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t134" href="#t134">134</a></span><span class="t"> <span class="nam">logger</span><span class="op">.</span><span class="nam">warning</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Bundled font not found: </span><span class="op">{</span><span class="nam">filename</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t135" href="#t135">135</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t136" href="#t136">136</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t137" href="#t137">137</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t138" href="#t138">138</a></span><span class="t"><span class="key">class</span> <span class="nam">Font</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t139" href="#t139">139</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t140" href="#t140">140</a></span><span class="t"><span class="str"> Font class to manage text rendering properties including font face, size, color, and styling.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t141" href="#t141">141</a></span><span class="t"><span class="str"> This class is used by the text renderer to determine how to render text.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t142" href="#t142">142</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t143" href="#t143">143</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t144" href="#t144">144</a></span><span class="t"> <span class="key">def</span> <span class="nam">__init__</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t145" href="#t145">145</a></span><span class="t"> <span class="nam">font_path</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">str</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t146" href="#t146">146</a></span><span class="t"> <span class="nam">font_size</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">16</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t147" href="#t147">147</a></span><span class="t"> <span class="nam">colour</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t148" href="#t148">148</a></span><span class="t"> <span class="nam">weight</span><span class="op">:</span> <span class="nam">FontWeight</span> <span class="op">=</span> <span class="nam">FontWeight</span><span class="op">.</span><span class="nam">NORMAL</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t149" href="#t149">149</a></span><span class="t"> <span class="nam">style</span><span class="op">:</span> <span class="nam">FontStyle</span> <span class="op">=</span> <span class="nam">FontStyle</span><span class="op">.</span><span class="nam">NORMAL</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t150" href="#t150">150</a></span><span class="t"> <span class="nam">decoration</span><span class="op">:</span> <span class="nam">TextDecoration</span> <span class="op">=</span> <span class="nam">TextDecoration</span><span class="op">.</span><span class="nam">NONE</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t151" href="#t151">151</a></span><span class="t"> <span class="nam">background</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t152" href="#t152">152</a></span><span class="t"> <span class="nam">language</span><span class="op">=</span><span class="str">"en_EN"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t153" href="#t153">153</a></span><span class="t"> <span class="nam">min_hyphenation_width</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t154" href="#t154">154</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t155" href="#t155">155</a></span><span class="t"><span class="str"> Initialize a Font object with the specified properties.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t156" href="#t156">156</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t157" href="#t157">157</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t158" href="#t158">158</a></span><span class="t"><span class="str"> font_path: Path to the font file (.ttf, .otf). If None, uses default bundled font.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t159" href="#t159">159</a></span><span class="t"><span class="str"> font_size: Size of the font in points.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t160" href="#t160">160</a></span><span class="t"><span class="str"> colour: RGB color tuple for the text.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t161" href="#t161">161</a></span><span class="t"><span class="str"> weight: Font weight (normal or bold).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t162" href="#t162">162</a></span><span class="t"><span class="str"> style: Font style (normal or italic).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t163" href="#t163">163</a></span><span class="t"><span class="str"> decoration: Text decoration (none, underline, or strikethrough).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t164" href="#t164">164</a></span><span class="t"><span class="str"> background: RGBA background color for the text. If None, transparent background.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t165" href="#t165">165</a></span><span class="t"><span class="str"> language: Language code for hyphenation and text processing.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t166" href="#t166">166</a></span><span class="t"><span class="str"> min_hyphenation_width: Minimum width in pixels required for hyphenation to be considered.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t167" href="#t167">167</a></span><span class="t"><span class="str"> If None, defaults to 4 times the font size.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t168" href="#t168">168</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t169" href="#t169">169</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_font_path</span> <span class="op">=</span> <span class="nam">font_path</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t170" href="#t170">170</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_font_size</span> <span class="op">=</span> <span class="nam">font_size</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t171" href="#t171">171</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_colour</span> <span class="op">=</span> <span class="nam">colour</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t172" href="#t172">172</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_weight</span> <span class="op">=</span> <span class="nam">weight</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t173" href="#t173">173</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span> <span class="op">=</span> <span class="nam">style</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t174" href="#t174">174</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_decoration</span> <span class="op">=</span> <span class="nam">decoration</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t175" href="#t175">175</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_background</span> <span class="op">=</span> <span class="nam">background</span> <span class="key">if</span> <span class="nam">background</span> <span class="key">else</span> <span class="op">(</span><span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t176" href="#t176">176</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">language</span> <span class="op">=</span> <span class="nam">language</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t177" href="#t177">177</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_min_hyphenation_width</span> <span class="op">=</span> <span class="nam">min_hyphenation_width</span> <span class="key">if</span> <span class="nam">min_hyphenation_width</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span> <span class="key">else</span> <span class="nam">font_size</span> <span class="op">*</span> <span class="num">4</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t178" href="#t178">178</a></span><span class="t"> <span class="com"># Load the font file or use default</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t179" href="#t179">179</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_load_font</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t180" href="#t180">180</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t181" href="#t181">181</a></span><span class="t"> <span class="op">@</span><span class="nam">classmethod</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t182" href="#t182">182</a></span><span class="t"> <span class="key">def</span> <span class="nam">from_family</span><span class="op">(</span><span class="nam">cls</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t183" href="#t183">183</a></span><span class="t"> <span class="nam">family</span><span class="op">:</span> <span class="nam">BundledFont</span> <span class="op">=</span> <span class="nam">BundledFont</span><span class="op">.</span><span class="nam">SANS</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t184" href="#t184">184</a></span><span class="t"> <span class="nam">font_size</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">16</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t185" href="#t185">185</a></span><span class="t"> <span class="nam">colour</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t186" href="#t186">186</a></span><span class="t"> <span class="nam">weight</span><span class="op">:</span> <span class="nam">FontWeight</span> <span class="op">=</span> <span class="nam">FontWeight</span><span class="op">.</span><span class="nam">NORMAL</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t187" href="#t187">187</a></span><span class="t"> <span class="nam">style</span><span class="op">:</span> <span class="nam">FontStyle</span> <span class="op">=</span> <span class="nam">FontStyle</span><span class="op">.</span><span class="nam">NORMAL</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t188" href="#t188">188</a></span><span class="t"> <span class="nam">decoration</span><span class="op">:</span> <span class="nam">TextDecoration</span> <span class="op">=</span> <span class="nam">TextDecoration</span><span class="op">.</span><span class="nam">NONE</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t189" href="#t189">189</a></span><span class="t"> <span class="nam">background</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t190" href="#t190">190</a></span><span class="t"> <span class="nam">language</span><span class="op">:</span> <span class="nam">str</span> <span class="op">=</span> <span class="str">"en_EN"</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t191" href="#t191">191</a></span><span class="t"> <span class="nam">min_hyphenation_width</span><span class="op">:</span> <span class="nam">Optional</span><span class="op">[</span><span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="key">None</span><span class="op">)</span> <span class="op">-></span> <span class="str">'Font'</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t192" href="#t192">192</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t193" href="#t193">193</a></span><span class="t"><span class="str"> Create a Font using a bundled font family.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t194" href="#t194">194</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t195" href="#t195">195</a></span><span class="t"><span class="str"> This is a convenient way to use the bundled DejaVu fonts without needing to</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t196" href="#t196">196</a></span><span class="t"><span class="str"> specify paths manually.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t197" href="#t197">197</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t198" href="#t198">198</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t199" href="#t199">199</a></span><span class="t"><span class="str"> family: The font family to use (SANS, SERIF, or MONOSPACE)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t200" href="#t200">200</a></span><span class="t"><span class="str"> font_size: Size of the font in points.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t201" href="#t201">201</a></span><span class="t"><span class="str"> colour: RGB color tuple for the text.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t202" href="#t202">202</a></span><span class="t"><span class="str"> weight: Font weight (normal or bold).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t203" href="#t203">203</a></span><span class="t"><span class="str"> style: Font style (normal or italic).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t204" href="#t204">204</a></span><span class="t"><span class="str"> decoration: Text decoration (none, underline, or strikethrough).</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t205" href="#t205">205</a></span><span class="t"><span class="str"> background: RGBA background color for the text. If None, transparent background.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t206" href="#t206">206</a></span><span class="t"><span class="str"> language: Language code for hyphenation and text processing.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t207" href="#t207">207</a></span><span class="t"><span class="str"> min_hyphenation_width: Minimum width in pixels required for hyphenation.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t208" href="#t208">208</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t209" href="#t209">209</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t210" href="#t210">210</a></span><span class="t"><span class="str"> Font object configured with the bundled font</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t211" href="#t211">211</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t212" href="#t212">212</a></span><span class="t"><span class="str"> Example:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t213" href="#t213">213</a></span><span class="t"><span class="str"> >>> # Create a bold serif font</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t214" href="#t214">214</a></span><span class="t"><span class="str"> >>> font = Font.from_family(BundledFont.SERIF, font_size=18, weight=FontWeight.BOLD)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t215" href="#t215">215</a></span><span class="t"><span class="str"> >>></span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t216" href="#t216">216</a></span><span class="t"><span class="str"> >>> # Create an italic monospace font</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t217" href="#t217">217</a></span><span class="t"><span class="str"> >>> code_font = Font.from_family(BundledFont.MONOSPACE, style=FontStyle.ITALIC)</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t218" href="#t218">218</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t219" href="#t219">219</a></span><span class="t"> <span class="nam">font_path</span> <span class="op">=</span> <span class="nam">get_bundled_font_path</span><span class="op">(</span><span class="nam">family</span><span class="op">,</span> <span class="nam">weight</span><span class="op">,</span> <span class="nam">style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t220" href="#t220">220</a></span><span class="t"> <span class="key">return</span> <span class="nam">cls</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t221" href="#t221">221</a></span><span class="t"> <span class="nam">font_path</span><span class="op">=</span><span class="nam">font_path</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t222" href="#t222">222</a></span><span class="t"> <span class="nam">font_size</span><span class="op">=</span><span class="nam">font_size</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t223" href="#t223">223</a></span><span class="t"> <span class="nam">colour</span><span class="op">=</span><span class="nam">colour</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t224" href="#t224">224</a></span><span class="t"> <span class="nam">weight</span><span class="op">=</span><span class="nam">weight</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t225" href="#t225">225</a></span><span class="t"> <span class="nam">style</span><span class="op">=</span><span class="nam">style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t226" href="#t226">226</a></span><span class="t"> <span class="nam">decoration</span><span class="op">=</span><span class="nam">decoration</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t227" href="#t227">227</a></span><span class="t"> <span class="nam">background</span><span class="op">=</span><span class="nam">background</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t228" href="#t228">228</a></span><span class="t"> <span class="nam">language</span><span class="op">=</span><span class="nam">language</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t229" href="#t229">229</a></span><span class="t"> <span class="nam">min_hyphenation_width</span><span class="op">=</span><span class="nam">min_hyphenation_width</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t230" href="#t230">230</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t231" href="#t231">231</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t232" href="#t232">232</a></span><span class="t"> <span class="key">def</span> <span class="nam">_get_bundled_font_path</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t233" href="#t233">233</a></span><span class="t"> <span class="str">"""Get the path to the bundled font (cached)"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t234" href="#t234">234</a></span><span class="t"> <span class="key">global</span> <span class="nam">_BUNDLED_FONT_PATH</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t235" href="#t235">235</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t236" href="#t236">236</a></span><span class="t"> <span class="com"># Return cached path if available</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t237" href="#t237">237</a></span><span class="t"> <span class="key">if</span> <span class="nam">_BUNDLED_FONT_PATH</span> <span class="key">is</span> <span class="key">not</span> <span class="key">None</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t238" href="#t238">238</a></span><span class="t"> <span class="key">return</span> <span class="nam">_BUNDLED_FONT_PATH</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t239" href="#t239">239</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t240" href="#t240">240</a></span><span class="t"> <span class="com"># First time - determine the path and cache it</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t241" href="#t241">241</a></span><span class="t"> <span class="com"># Get the directory containing this module</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t242" href="#t242">242</a></span><span class="t"> <span class="nam">current_dir</span> <span class="op">=</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">dirname</span><span class="op">(</span><span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">abspath</span><span class="op">(</span><span class="nam">__file__</span><span class="op">)</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t243" href="#t243">243</a></span><span class="t"> <span class="com"># Navigate to the assets/fonts directory</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t244" href="#t244">244</a></span><span class="t"> <span class="nam">assets_dir</span> <span class="op">=</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">join</span><span class="op">(</span><span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">dirname</span><span class="op">(</span><span class="nam">current_dir</span><span class="op">)</span><span class="op">,</span> <span class="str">'assets'</span><span class="op">,</span> <span class="str">'fonts'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t245" href="#t245">245</a></span><span class="t"> <span class="nam">bundled_font_path</span> <span class="op">=</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">join</span><span class="op">(</span><span class="nam">assets_dir</span><span class="op">,</span> <span class="str">'DejaVuSans.ttf'</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t246" href="#t246">246</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t247" href="#t247">247</a></span><span class="t"> <span class="nam">logger</span><span class="op">.</span><span class="nam">debug</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Font loading: current_dir = </span><span class="op">{</span><span class="nam">current_dir</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t248" href="#t248">248</a></span><span class="t"> <span class="nam">logger</span><span class="op">.</span><span class="nam">debug</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Font loading: assets_dir = </span><span class="op">{</span><span class="nam">assets_dir</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t249" href="#t249">249</a></span><span class="t"> <span class="nam">logger</span><span class="op">.</span><span class="nam">debug</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Font loading: bundled_font_path = </span><span class="op">{</span><span class="nam">bundled_font_path</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t250" href="#t250">250</a></span><span class="t"> <span class="nam">logger</span><span class="op">.</span><span class="nam">debug</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t251" href="#t251">251</a></span><span class="t"> <span class="fst">f"</span><span class="fst">Font loading: bundled font exists = </span><span class="op">{</span><span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">exists</span><span class="op">(</span><span class="nam">bundled_font_path</span><span class="op">)</span><span class="op">}</span><span class="fst">"</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t252" href="#t252">252</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t253" href="#t253">253</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t254" href="#t254">254</a></span><span class="t"> <span class="key">if</span> <span class="nam">os</span><span class="op">.</span><span class="nam">path</span><span class="op">.</span><span class="nam">exists</span><span class="op">(</span><span class="nam">bundled_font_path</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">254&#x202F;&#x219B;&#x202F;259</span><span class="annotate long">line 254 didn't jump to line 259 because the condition on line 254 was always true</span></span></p>
<p class="run"><span class="n"><a id="t255" href="#t255">255</a></span><span class="t"> <span class="nam">logger</span><span class="op">.</span><span class="nam">info</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Found bundled font at: </span><span class="op">{</span><span class="nam">bundled_font_path</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t256" href="#t256">256</a></span><span class="t"> <span class="nam">_BUNDLED_FONT_PATH</span> <span class="op">=</span> <span class="nam">bundled_font_path</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t257" href="#t257">257</a></span><span class="t"> <span class="key">return</span> <span class="nam">bundled_font_path</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t258" href="#t258">258</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t259" href="#t259">259</a></span><span class="t"> <span class="nam">logger</span><span class="op">.</span><span class="nam">warning</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Bundled font not found at: </span><span class="op">{</span><span class="nam">bundled_font_path</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t260" href="#t260">260</a></span><span class="t"> <span class="com"># Cache None to indicate bundled font is not available</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t261" href="#t261">261</a></span><span class="t"> <span class="nam">_BUNDLED_FONT_PATH</span> <span class="op">=</span> <span class="str">""</span> <span class="com"># Use empty string instead of None to differentiate from "not checked yet"</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t262" href="#t262">262</a></span><span class="t"> <span class="key">return</span> <span class="key">None</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t263" href="#t263">263</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t264" href="#t264">264</a></span><span class="t"> <span class="key">def</span> <span class="nam">_load_font</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t265" href="#t265">265</a></span><span class="t"> <span class="str">"""Load the font using PIL's ImageFont with consistent bundled font and caching"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t266" href="#t266">266</a></span><span class="t"> <span class="com"># Determine the actual font path to use</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t267" href="#t267">267</a></span><span class="t"> <span class="nam">font_path_to_use</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_font_path</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t268" href="#t268">268</a></span><span class="t"> <span class="key">if</span> <span class="key">not</span> <span class="nam">font_path_to_use</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t269" href="#t269">269</a></span><span class="t"> <span class="nam">font_path_to_use</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_get_bundled_font_path</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t270" href="#t270">270</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t271" href="#t271">271</a></span><span class="t"> <span class="com"># Create cache key</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t272" href="#t272">272</a></span><span class="t"> <span class="nam">cache_key</span> <span class="op">=</span> <span class="op">(</span><span class="nam">font_path_to_use</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_font_size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t273" href="#t273">273</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t274" href="#t274">274</a></span><span class="t"> <span class="com"># Check if font is already cached</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t275" href="#t275">275</a></span><span class="t"> <span class="key">if</span> <span class="nam">cache_key</span> <span class="key">in</span> <span class="nam">_FONT_CACHE</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t276" href="#t276">276</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_font</span> <span class="op">=</span> <span class="nam">_FONT_CACHE</span><span class="op">[</span><span class="nam">cache_key</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t277" href="#t277">277</a></span><span class="t"> <span class="nam">logger</span><span class="op">.</span><span class="nam">debug</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Reusing cached font: </span><span class="op">{</span><span class="nam">font_path_to_use</span><span class="op">}</span><span class="fst"> at size </span><span class="op">{</span><span class="nam">self</span><span class="op">.</span><span class="nam">_font_size</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t278" href="#t278">278</a></span><span class="t"> <span class="key">return</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t279" href="#t279">279</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t280" href="#t280">280</a></span><span class="t"> <span class="com"># Font not cached, need to load it</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t281" href="#t281">281</a></span><span class="t"> <span class="key">try</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t282" href="#t282">282</a></span><span class="t"> <span class="key">if</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_font_path</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t283" href="#t283">283</a></span><span class="t"> <span class="com"># Use specified font path</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t284" href="#t284">284</a></span><span class="t"> <span class="nam">logger</span><span class="op">.</span><span class="nam">info</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Loading font from specified path: </span><span class="op">{</span><span class="nam">self</span><span class="op">.</span><span class="nam">_font_path</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t285" href="#t285">285</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_font</span> <span class="op">=</span> <span class="nam">ImageFont</span><span class="op">.</span><span class="nam">truetype</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t286" href="#t286">286</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_font_path</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t287" href="#t287">287</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_font_size</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t288" href="#t288">288</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t289" href="#t289">289</a></span><span class="t"> <span class="nam">logger</span><span class="op">.</span><span class="nam">info</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Successfully loaded font from: </span><span class="op">{</span><span class="nam">self</span><span class="op">.</span><span class="nam">_font_path</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t290" href="#t290">290</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t291" href="#t291">291</a></span><span class="t"> <span class="com"># Use bundled font for consistency across environments</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t292" href="#t292">292</a></span><span class="t"> <span class="nam">bundled_font_path</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_get_bundled_font_path</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t293" href="#t293">293</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="par run show_par"><span class="n"><a id="t294" href="#t294">294</a></span><span class="t"> <span class="key">if</span> <span class="nam">bundled_font_path</span><span class="op">:</span>&nbsp;</span><span class="r"><span class="annotate short">294&#x202F;&#x219B;&#x202F;303</span><span class="annotate long">line 294 didn't jump to line 303 because the condition on line 294 was always true</span></span></p>
<p class="run"><span class="n"><a id="t295" href="#t295">295</a></span><span class="t"> <span class="nam">logger</span><span class="op">.</span><span class="nam">info</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Loading bundled font from: </span><span class="op">{</span><span class="nam">bundled_font_path</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t296" href="#t296">296</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_font</span> <span class="op">=</span> <span class="nam">ImageFont</span><span class="op">.</span><span class="nam">truetype</span><span class="op">(</span><span class="nam">bundled_font_path</span><span class="op">,</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_font_size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t297" href="#t297">297</a></span><span class="t"> <span class="nam">logger</span><span class="op">.</span><span class="nam">info</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t298" href="#t298">298</a></span><span class="t"> <span class="fst">f"</span><span class="fst">Successfully loaded bundled font at size </span><span class="op">{</span><span class="nam">self</span><span class="op">.</span><span class="nam">_font_size</span><span class="op">}</span><span class="fst">"</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t299" href="#t299">299</a></span><span class="t"> <span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t300" href="#t300">300</a></span><span class="t"> <span class="key">else</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t301" href="#t301">301</a></span><span class="t"> <span class="com"># Only fall back to PIL's default font if bundled font is not</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t302" href="#t302">302</a></span><span class="t"> <span class="com"># available</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t303" href="#t303">303</a></span><span class="t"> <span class="nam">logger</span><span class="op">.</span><span class="nam">warning</span><span class="op">(</span>&nbsp;</span><span class="r"></span></p>
<p class="mis mis2 show_mis"><span class="n"><a id="t304" href="#t304">304</a></span><span class="t"> <span class="str">"Bundled font not available, falling back to PIL default font"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="mis show_mis"><span class="n"><a id="t305" href="#t305">305</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_font</span> <span class="op">=</span> <span class="nam">ImageFont</span><span class="op">.</span><span class="nam">load_default</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t306" href="#t306">306</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t307" href="#t307">307</a></span><span class="t"> <span class="com"># Cache the loaded font</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t308" href="#t308">308</a></span><span class="t"> <span class="nam">_FONT_CACHE</span><span class="op">[</span><span class="nam">cache_key</span><span class="op">]</span> <span class="op">=</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_font</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t309" href="#t309">309</a></span><span class="t"> <span class="nam">logger</span><span class="op">.</span><span class="nam">debug</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Cached font: </span><span class="op">{</span><span class="nam">font_path_to_use</span><span class="op">}</span><span class="fst"> at size </span><span class="op">{</span><span class="nam">self</span><span class="op">.</span><span class="nam">_font_size</span><span class="op">}</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t310" href="#t310">310</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t311" href="#t311">311</a></span><span class="t"> <span class="key">except</span> <span class="nam">Exception</span> <span class="key">as</span> <span class="nam">e</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t312" href="#t312">312</a></span><span class="t"> <span class="com"># Ultimate fallback to default font</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t313" href="#t313">313</a></span><span class="t"> <span class="nam">logger</span><span class="op">.</span><span class="nam">error</span><span class="op">(</span><span class="fst">f"</span><span class="fst">Failed to load font: </span><span class="op">{</span><span class="nam">e</span><span class="op">}</span><span class="fst">, falling back to PIL default font</span><span class="fst">"</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t314" href="#t314">314</a></span><span class="t"> <span class="nam">self</span><span class="op">.</span><span class="nam">_font</span> <span class="op">=</span> <span class="nam">ImageFont</span><span class="op">.</span><span class="nam">load_default</span><span class="op">(</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t315" href="#t315">315</a></span><span class="t"> <span class="com"># Don't cache the default font as it doesn't have a path</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t316" href="#t316">316</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t317" href="#t317">317</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t318" href="#t318">318</a></span><span class="t"> <span class="key">def</span> <span class="nam">font</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t319" href="#t319">319</a></span><span class="t"> <span class="str">"""Get the PIL ImageFont object"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t320" href="#t320">320</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_font</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t321" href="#t321">321</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t322" href="#t322">322</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t323" href="#t323">323</a></span><span class="t"> <span class="key">def</span> <span class="nam">font_size</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t324" href="#t324">324</a></span><span class="t"> <span class="str">"""Get the font size"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t325" href="#t325">325</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_font_size</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t326" href="#t326">326</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t327" href="#t327">327</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t328" href="#t328">328</a></span><span class="t"> <span class="key">def</span> <span class="nam">colour</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t329" href="#t329">329</a></span><span class="t"> <span class="str">"""Get the text color"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t330" href="#t330">330</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_colour</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t331" href="#t331">331</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t332" href="#t332">332</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t333" href="#t333">333</a></span><span class="t"> <span class="key">def</span> <span class="nam">color</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t334" href="#t334">334</a></span><span class="t"> <span class="str">"""Alias for colour (American spelling)"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t335" href="#t335">335</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_colour</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t336" href="#t336">336</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t337" href="#t337">337</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t338" href="#t338">338</a></span><span class="t"> <span class="key">def</span> <span class="nam">background</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t339" href="#t339">339</a></span><span class="t"> <span class="str">"""Get the background color"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t340" href="#t340">340</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_background</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t341" href="#t341">341</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t342" href="#t342">342</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t343" href="#t343">343</a></span><span class="t"> <span class="key">def</span> <span class="nam">weight</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t344" href="#t344">344</a></span><span class="t"> <span class="str">"""Get the font weight"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t345" href="#t345">345</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_weight</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t346" href="#t346">346</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t347" href="#t347">347</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t348" href="#t348">348</a></span><span class="t"> <span class="key">def</span> <span class="nam">style</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t349" href="#t349">349</a></span><span class="t"> <span class="str">"""Get the font style"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t350" href="#t350">350</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t351" href="#t351">351</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t352" href="#t352">352</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t353" href="#t353">353</a></span><span class="t"> <span class="key">def</span> <span class="nam">decoration</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t354" href="#t354">354</a></span><span class="t"> <span class="str">"""Get the text decoration"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t355" href="#t355">355</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_decoration</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t356" href="#t356">356</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t357" href="#t357">357</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t358" href="#t358">358</a></span><span class="t"> <span class="key">def</span> <span class="nam">min_hyphenation_width</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t359" href="#t359">359</a></span><span class="t"> <span class="str">"""Get the minimum width required for hyphenation to be considered"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t360" href="#t360">360</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_min_hyphenation_width</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t361" href="#t361">361</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t362" href="#t362">362</a></span><span class="t"> <span class="key">def</span> <span class="nam">_with_modified</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="op">**</span><span class="nam">kwargs</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t363" href="#t363">363</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t364" href="#t364">364</a></span><span class="t"><span class="str"> Internal helper to create a new Font with modified parameters.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t365" href="#t365">365</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t366" href="#t366">366</a></span><span class="t"><span class="str"> This consolidates the duplication across all with_* methods.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t367" href="#t367">367</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t368" href="#t368">368</a></span><span class="t"><span class="str"> Args:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t369" href="#t369">369</a></span><span class="t"><span class="str"> **kwargs: Parameters to override (e.g., font_size=20, colour=(255,0,0))</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t370" href="#t370">370</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t371" href="#t371">371</a></span><span class="t"><span class="str"> Returns:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t372" href="#t372">372</a></span><span class="t"><span class="str"> New Font object with modified parameters</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t373" href="#t373">373</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t374" href="#t374">374</a></span><span class="t"> <span class="nam">params</span> <span class="op">=</span> <span class="op">{</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t375" href="#t375">375</a></span><span class="t"> <span class="str">'font_path'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_font_path</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t376" href="#t376">376</a></span><span class="t"> <span class="str">'font_size'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_font_size</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t377" href="#t377">377</a></span><span class="t"> <span class="str">'colour'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_colour</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t378" href="#t378">378</a></span><span class="t"> <span class="str">'weight'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_weight</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t379" href="#t379">379</a></span><span class="t"> <span class="str">'style'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_style</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t380" href="#t380">380</a></span><span class="t"> <span class="str">'decoration'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_decoration</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t381" href="#t381">381</a></span><span class="t"> <span class="str">'background'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_background</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t382" href="#t382">382</a></span><span class="t"> <span class="str">'language'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">language</span><span class="op">,</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t383" href="#t383">383</a></span><span class="t"> <span class="str">'min_hyphenation_width'</span><span class="op">:</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_min_hyphenation_width</span>&nbsp;</span><span class="r"></span></p>
<p class="run run2"><span class="n"><a id="t384" href="#t384">384</a></span><span class="t"> <span class="op">}</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t385" href="#t385">385</a></span><span class="t"> <span class="nam">params</span><span class="op">.</span><span class="nam">update</span><span class="op">(</span><span class="nam">kwargs</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t386" href="#t386">386</a></span><span class="t"> <span class="key">return</span> <span class="nam">Font</span><span class="op">(</span><span class="op">**</span><span class="nam">params</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t387" href="#t387">387</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t388" href="#t388">388</a></span><span class="t"> <span class="key">def</span> <span class="nam">with_size</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">size</span><span class="op">:</span> <span class="nam">int</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t389" href="#t389">389</a></span><span class="t"> <span class="str">"""Create a new Font object with modified size"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t390" href="#t390">390</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_with_modified</span><span class="op">(</span><span class="nam">font_size</span><span class="op">=</span><span class="nam">size</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t391" href="#t391">391</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t392" href="#t392">392</a></span><span class="t"> <span class="key">def</span> <span class="nam">with_colour</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">colour</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t393" href="#t393">393</a></span><span class="t"> <span class="str">"""Create a new Font object with modified colour"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t394" href="#t394">394</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_with_modified</span><span class="op">(</span><span class="nam">colour</span><span class="op">=</span><span class="nam">colour</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t395" href="#t395">395</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t396" href="#t396">396</a></span><span class="t"> <span class="key">def</span> <span class="nam">with_weight</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">weight</span><span class="op">:</span> <span class="nam">FontWeight</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t397" href="#t397">397</a></span><span class="t"> <span class="str">"""Create a new Font object with modified weight"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t398" href="#t398">398</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_with_modified</span><span class="op">(</span><span class="nam">weight</span><span class="op">=</span><span class="nam">weight</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t399" href="#t399">399</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t400" href="#t400">400</a></span><span class="t"> <span class="key">def</span> <span class="nam">with_style</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">style</span><span class="op">:</span> <span class="nam">FontStyle</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t401" href="#t401">401</a></span><span class="t"> <span class="str">"""Create a new Font object with modified style"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t402" href="#t402">402</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_with_modified</span><span class="op">(</span><span class="nam">style</span><span class="op">=</span><span class="nam">style</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t403" href="#t403">403</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t404" href="#t404">404</a></span><span class="t"> <span class="key">def</span> <span class="nam">with_decoration</span><span class="op">(</span><span class="nam">self</span><span class="op">,</span> <span class="nam">decoration</span><span class="op">:</span> <span class="nam">TextDecoration</span><span class="op">)</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t405" href="#t405">405</a></span><span class="t"> <span class="str">"""Create a new Font object with modified decoration"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t406" href="#t406">406</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">_with_modified</span><span class="op">(</span><span class="nam">decoration</span><span class="op">=</span><span class="nam">decoration</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_ba7f6bdeb0188088_concrete_style_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_ba7f6bdeb0188088_page_style_py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,157 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/style/page_style.py: 100%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/style/page_style.py</b>:
<span class="pc_cov">100%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">33 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">33<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">0<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">4<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">0<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_ba7f6bdeb0188088_fonts_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="index.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="run"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="key">from</span> <span class="nam">typing</span> <span class="key">import</span> <span class="nam">Tuple</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="key">from</span> <span class="nam">dataclasses</span> <span class="key">import</span> <span class="nam">dataclass</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="op">@</span><span class="nam">dataclass</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="key">class</span> <span class="nam">PageStyle</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t"> <span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="str"> Defines the styling properties for a page including borders, spacing, and layout.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t9" href="#t9">9</a></span><span class="t"><span class="str"> """</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t10" href="#t10">10</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t11" href="#t11">11</a></span><span class="t"> <span class="com"># Border properties</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t12" href="#t12">12</a></span><span class="t"> <span class="nam">border_width</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">0</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t13" href="#t13">13</a></span><span class="t"> <span class="nam">border_color</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="op">(</span><span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">,</span> <span class="num">0</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t14" href="#t14">14</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t15" href="#t15">15</a></span><span class="t"> <span class="com"># Spacing properties</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t16" href="#t16">16</a></span><span class="t"> <span class="nam">line_spacing</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">5</span> <span class="com"># Additional pixels between lines (added to font size)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t17" href="#t17">17</a></span><span class="t"> <span class="nam">inter_block_spacing</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">15</span> <span class="com"># Pixels between blocks (paragraphs, headings, etc.)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t18" href="#t18">18</a></span><span class="t"> <span class="nam">word_spacing</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">0</span> <span class="com"># Additional pixels between words (0 = use font defaults)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t19" href="#t19">19</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t20" href="#t20">20</a></span><span class="t"> <span class="com"># Padding (top, right, bottom, left)</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t21" href="#t21">21</a></span><span class="t"> <span class="nam">padding</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="op">(</span><span class="num">20</span><span class="op">,</span> <span class="num">20</span><span class="op">,</span> <span class="num">20</span><span class="op">,</span> <span class="num">20</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t22" href="#t22">22</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t23" href="#t23">23</a></span><span class="t"> <span class="com"># Background color</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t24" href="#t24">24</a></span><span class="t"> <span class="nam">background_color</span><span class="op">:</span> <span class="nam">Tuple</span><span class="op">[</span><span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">,</span> <span class="nam">int</span><span class="op">]</span> <span class="op">=</span> <span class="op">(</span><span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">,</span> <span class="num">255</span><span class="op">)</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t25" href="#t25">25</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t26" href="#t26">26</a></span><span class="t"> <span class="com"># Typography properties</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t27" href="#t27">27</a></span><span class="t"> <span class="nam">max_font_size</span><span class="op">:</span> <span class="nam">int</span> <span class="op">=</span> <span class="num">72</span> <span class="com"># Maximum font size allowed on a page</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t28" href="#t28">28</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t29" href="#t29">29</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t30" href="#t30">30</a></span><span class="t"> <span class="key">def</span> <span class="nam">padding_top</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t31" href="#t31">31</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">padding</span><span class="op">[</span><span class="num">0</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t32" href="#t32">32</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t33" href="#t33">33</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t34" href="#t34">34</a></span><span class="t"> <span class="key">def</span> <span class="nam">padding_right</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t35" href="#t35">35</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">padding</span><span class="op">[</span><span class="num">1</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t36" href="#t36">36</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t37" href="#t37">37</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t38" href="#t38">38</a></span><span class="t"> <span class="key">def</span> <span class="nam">padding_bottom</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t39" href="#t39">39</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">padding</span><span class="op">[</span><span class="num">2</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t40" href="#t40">40</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t41" href="#t41">41</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t42" href="#t42">42</a></span><span class="t"> <span class="key">def</span> <span class="nam">padding_left</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t43" href="#t43">43</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">padding</span><span class="op">[</span><span class="num">3</span><span class="op">]</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t44" href="#t44">44</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t45" href="#t45">45</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t46" href="#t46">46</a></span><span class="t"> <span class="key">def</span> <span class="nam">total_horizontal_padding</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t47" href="#t47">47</a></span><span class="t"> <span class="str">"""Get total horizontal padding (left + right)"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t48" href="#t48">48</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">padding_left</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">padding_right</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t49" href="#t49">49</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t50" href="#t50">50</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t51" href="#t51">51</a></span><span class="t"> <span class="key">def</span> <span class="nam">total_vertical_padding</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t52" href="#t52">52</a></span><span class="t"> <span class="str">"""Get total vertical padding (top + bottom)"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t53" href="#t53">53</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">padding_top</span> <span class="op">+</span> <span class="nam">self</span><span class="op">.</span><span class="nam">padding_bottom</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t54" href="#t54">54</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t55" href="#t55">55</a></span><span class="t"> <span class="op">@</span><span class="nam">property</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t56" href="#t56">56</a></span><span class="t"> <span class="key">def</span> <span class="nam">total_border_width</span><span class="op">(</span><span class="nam">self</span><span class="op">)</span> <span class="op">-></span> <span class="nam">int</span><span class="op">:</span>&nbsp;</span><span class="r"></span></p>
<p class="exc show_exc"><span class="n"><a id="t57" href="#t57">57</a></span><span class="t"> <span class="str">"""Get total border width (both sides)"""</span>&nbsp;</span><span class="r"></span></p>
<p class="run"><span class="n"><a id="t58" href="#t58">58</a></span><span class="t"> <span class="key">return</span> <span class="nam">self</span><span class="op">.</span><span class="nam">border_width</span> <span class="op">*</span> <span class="num">2</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_ba7f6bdeb0188088_fonts_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,107 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage for pyWebLayout/io/__init__.py: 100%</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_6b508a39.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="pyfile">
<header>
<div class="content">
<h1>
<span class="text">Coverage for </span><b>pyWebLayout/io/__init__.py</b>:
<span class="pc_cov">100%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
<label for="help_panel_state">
<img id="keyboard_icon" src="keybd_closed_cb_ce680311.png" alt="Show/hide keyboard shortcuts">
</label>
<div id="help_panel">
<p class="legend">Shortcuts on this page</p>
<div class="keyhelp">
<p>
<kbd>r</kbd>
<kbd>m</kbd>
<kbd>x</kbd>
<kbd>p</kbd>
&nbsp; toggle line displays
</p>
<p>
<kbd>j</kbd>
<kbd>k</kbd>
&nbsp; next/prev highlighted chunk
</p>
<p>
<kbd>0</kbd> &nbsp; (zero) top of page
</p>
<p>
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p>
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p>
<kbd>u</kbd> &nbsp; up to the index
</p>
<p>
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</aside>
<h2>
<span class="text">0 statements &nbsp;</span>
<button type="button" class="run button_toggle_run" value="run" data-shortcut="r" title="Toggle lines run">0<span class="text"> run</span></button>
<button type="button" class="mis show_mis button_toggle_mis" value="mis" data-shortcut="m" title="Toggle lines missing">0<span class="text"> missing</span></button>
<button type="button" class="exc show_exc button_toggle_exc" value="exc" data-shortcut="x" title="Toggle lines excluded">1<span class="text"> excluded</span></button>
<button type="button" class="par run show_par button_toggle_par" value="par" data-shortcut="p" title="Toggle lines partially run">0<span class="text"> partial</span></button>
</h2>
<p class="text">
<a id="prevFileLink" class="nav" href="z_40407af872b0cf37_query_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="z_263f2e628cef8c50___init___py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
<button type="button" class="button_prev_chunk" data-shortcut="k"></button>
<button type="button" class="button_top_of_page" data-shortcut="0"></button>
<button type="button" class="button_first_chunk" data-shortcut="1"></button>
<button type="button" class="button_prev_file" data-shortcut="["></button>
<button type="button" class="button_next_file" data-shortcut="]"></button>
<button type="button" class="button_to_index" data-shortcut="u"></button>
<button type="button" class="button_show_hide_help" data-shortcut="?"></button>
</aside>
</div>
</header>
<main id="source">
<p class="exc show_exc"><span class="n"><a id="t1" href="#t1">1</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t2" href="#t2">2</a></span><span class="t"><span class="str">Input/Output module for pyWebLayout.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t3" href="#t3">3</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t4" href="#t4">4</a></span><span class="t"><span class="str">This package provides functionality for reading and writing various file formats,</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t5" href="#t5">5</a></span><span class="t"><span class="str">including HTML, EPUB, and other document formats.</span>&nbsp;</span><span class="r"></span></p>
<p class="exc exc2 show_exc"><span class="n"><a id="t6" href="#t6">6</a></span><span class="t"><span class="str">"""</span>&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t7" href="#t7">7</a></span><span class="t">&nbsp;</span><span class="r"></span></p>
<p class="pln"><span class="n"><a id="t8" href="#t8">8</a></span><span class="t"><span class="com"># Readers</span>&nbsp;</span><span class="r"></span></p>
</main>
<footer>
<div class="content">
<p>
<a class="nav" href="z_40407af872b0cf37_query_py.html">&#xab; prev</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="z_263f2e628cef8c50___init___py.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.11.2">coverage.py v7.11.2</a>,
created at 2025-11-12 12:02 +0000
</p>
</div>
</footer>
</body>
</html>

213
docs/images/README.md Normal file
View File

@ -0,0 +1,213 @@
# pyWebLayout Visual Documentation
This directory contains visual documentation for pyWebLayout, including animated GIF demonstrations of the EbookReader functionality and static example outputs showcasing various features.
## Generated GIFs
### 1. Page Navigation (`ereader_page_navigation.gif`)
Demonstrates forward and backward page navigation through an EPUB book. Shows smooth transitions between pages using `next_page()` and `previous_page()` methods.
**Features shown:**
- Sequential page advancement
- Page-by-page content rendering
- Natural reading flow
### 2. Font Size Adjustment (`ereader_font_size.gif`)
Shows dynamic font size scaling from 0.8x to 1.4x and back. The reader maintains the current reading position even as the layout changes with different font sizes.
**Features shown:**
- `increase_font_size()` / `decrease_font_size()`
- `set_font_size(scale)` with specific values
- Position preservation across layout changes
- Text reflow with different sizes
### 3. Chapter Navigation (`ereader_chapter_navigation.gif`)
Demonstrates jumping between chapters in a book. Each chapter's first page is displayed, showing the ability to navigate non-linearly through the content.
**Features shown:**
- `jump_to_chapter(index)` for index-based navigation
- `jump_to_chapter(title)` for title-based navigation
- `get_chapters()` to list available chapters
- Quick access to any part of the book
### 4. Bookmarks & Positions (`ereader_bookmarks.gif`)
Illustrates the bookmark system: navigating to a position, saving it, navigating away, and then returning to the saved position.
**Features shown:**
- `save_position(name)` to bookmark current location
- `load_position(name)` to return to saved bookmark
- Position stability across navigation
- Multiple bookmark support
## Generating Your Own GIFs
To generate these animations with your own EPUB file:
```bash
cd examples
python generate_ereader_gifs.py path/to/your/book.epub ../docs/images/
```
This will create all four GIF animations in the specified output directory.
### Script Options
```python
python generate_ereader_gifs.py <epub_path> [output_dir]
```
- `epub_path`: Path to your EPUB file (required)
- `output_dir`: Directory to save GIFs (default: current directory)
### Customization
You can modify `generate_ereader_gifs.py` to adjust:
- Frame duration (`duration` parameter in `create_gif()`)
- Page dimensions (change `page_size` in `EbookReader`)
- Number of frames for each animation
- Font scale ranges
- Animation sequences
## Technical Details
- **Format**: Animated GIF
- **Page Size**: 600x800 pixels
- **Frame Rate**: Variable (500-1000ms per frame)
- **Loop**: Infinite
- **Book Used**: Alice's Adventures in Wonderland (test.epub)
## File Sizes
| GIF | Size | Frames | Duration per Frame |
|-----|------|--------|-------------------|
| `ereader_page_navigation.gif` | ~500 KB | 10 | 600ms |
| `ereader_font_size.gif` | ~680 KB | 13 | 500ms |
| `ereader_chapter_navigation.gif` | ~290 KB | 11 | 1000ms |
| `ereader_bookmarks.gif` | ~500 KB | 17 | 600ms |
---
## Example Outputs
Static PNG images generated by the example scripts, demonstrating various pyWebLayout features.
### Example 01: Simple Page Rendering
**File:** `example_01_page_rendering.png`
**Source:** [examples/01_simple_page_rendering.py](../../examples/01_simple_page_rendering.py)
**Demonstrates:** Page styles, borders, padding, background colors
### Example 06: Functional Elements
**File:** `example_06_functional_elements.png`
**Source:** [examples/06_functional_elements_demo.py](../../examples/06_functional_elements_demo.py)
**Demonstrates:** Buttons, form fields, interactive elements
### Example 08: Pagination (NEW)
**Files:**
- `example_08_pagination_explicit.png` (109 KB) - 5 pages with explicit PageBreaks
- `example_08_pagination_auto.png` (87 KB) - 2 pages with automatic pagination
**Source:** [examples/08_pagination_demo.py](../../examples/08_pagination_demo.py)
**Test:** [tests/examples/test_08_pagination_demo.py](../../tests/examples/test_08_pagination_demo.py)
**Demonstrates:**
- Using `PageBreak` to force content onto new pages
- Multi-page document layout with explicit breaks
- Automatic pagination when content overflows
- Page numbering functionality
- Document flow control
**Coverage:** ✅ Fills critical gap - PageBreak had NO examples before this
### Example 09: Link Navigation (NEW)
**File:** `example_09_link_navigation.png` (60 KB)
**Source:** [examples/09_link_navigation_demo.py](../../examples/09_link_navigation_demo.py)
**Test:** [tests/examples/test_09_link_navigation_demo.py](../../tests/examples/test_09_link_navigation_demo.py)
**Demonstrates:**
- **Internal links** - Document navigation (`#section1`, `#section2`)
- **External links** - Web URLs (`https://example.com`)
- **API links** - API endpoints (`/api/settings`, `/api/save`)
- **Function links** - Direct function calls (`calculate()`, `process()`)
- Link styling (underlined, color-coded by type)
- Link callbacks and interactivity
**Coverage:** ✅ Comprehensive - All 4 LinkType variations demonstrated
### Example 10: Comprehensive Forms (NEW)
**File:** `example_10_forms.png` (31 KB)
**Source:** [examples/10_forms_demo.py](../../examples/10_forms_demo.py)
**Test:** [tests/examples/test_10_forms_demo.py](../../tests/examples/test_10_forms_demo.py)
**Demonstrates all 14 FormFieldType variations:**
**Text-Based Fields:**
- `TEXT` - Standard text input
- `EMAIL` - Email validation field
- `PASSWORD` - Password masking
- `URL` - URL validation
- `TEXTAREA` - Multi-line text
**Number/Date/Time Fields:**
- `NUMBER` - Numeric input
- `DATE` - Date picker
- `TIME` - Time selector
- `RANGE` - Slider control
- `COLOR` - Color picker
**Selection Fields:**
- `CHECKBOX` - Boolean selection
- `RADIO` - Single choice from options
- `SELECT` - Dropdown menu
- `HIDDEN` - Hidden form data
**Coverage:** ✅ Complete - All 14 field types across 4 practical examples
---
## Generating New Examples
### Run Individual Examples
```bash
# Navigate to project root
cd /path/to/pyWebLayout
# Run specific example
python examples/08_pagination_demo.py
python examples/09_link_navigation_demo.py
python examples/10_forms_demo.py
```
### Run All Example Tests
```bash
# Run all example tests with pytest
python -m pytest tests/examples/ -v
# Run specific test file
python -m pytest tests/examples/test_08_pagination_demo.py -v
```
All new examples (08, 09, 10) include:
- ✅ Comprehensive documentation
- ✅ Full test coverage (30 tests total)
- ✅ Visual output verification
- ✅ Working code examples
See the main [README.md](../../README.md) and [examples/README.md](../../examples/README.md) for detailed information.
---
## Usage in Documentation
These visual assets are used throughout the pyWebLayout documentation to showcase capabilities.
To embed in Markdown:
```markdown
![Page Navigation](docs/images/ereader_page_navigation.gif)
![Pagination Example](docs/images/example_08_pagination_explicit.png)
```
To embed in HTML with size control:
```html
<img src="docs/images/ereader_page_navigation.gif" width="300" alt="Page Navigation">
<img src="docs/images/example_08_pagination_explicit.png" width="400" alt="Pagination">
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,217 @@
#!/usr/bin/env python3
"""
Simple Page Rendering Example
This example demonstrates:
- Creating pages with different styles
- Setting borders, padding, and background colors
- Understanding the page layout system
- Rendering pages to images
This is a foundational example showing the basic Page API.
"""
from pyWebLayout.style.page_style import PageStyle
from pyWebLayout.concrete.page import Page
import sys
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont
# Add pyWebLayout to path
sys.path.insert(0, str(Path(__file__).parent.parent))
def draw_placeholder_content(page: Page):
"""Draw some placeholder content directly on the page to visualize the layout."""
if page.draw is None:
# Trigger canvas creation
page.render()
draw = page.draw
# Draw content area boundary (for visualization)
content_x = page.border_size + page.style.padding_left
content_y = page.border_size + page.style.padding_top
content_w = page.content_size[0]
content_h = page.content_size[1]
# Draw a light blue rectangle showing the content area
draw.rectangle(
[content_x, content_y, content_x + content_w, content_y + content_h],
outline=(100, 150, 255),
width=1
)
# Add some text labels
try:
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 12)
except BaseException:
font = ImageFont.load_default()
# Label the areas
draw.text(
(content_x + 10,
content_y + 10),
"Content Area",
fill=(
100,
100,
100),
font=font)
draw.text(
(10, 10), f"Border: {page.border_size}px", fill=(
150, 150, 150), font=font)
draw.text(
(content_x + 10,
content_y + 30),
f"Size: {content_w}x{content_h}",
fill=(
100,
100,
100),
font=font)
def create_example_1():
"""Example 1: Default page style."""
print("\n Creating Example 1: Default style...")
page = Page(size=(400, 300))
draw_placeholder_content(page)
return page
def create_example_2():
"""Example 2: Page with visible borders."""
print(" Creating Example 2: With borders...")
page_style = PageStyle(
border_width=3,
border_color=(255, 100, 100),
padding=(20, 20, 20, 20),
background_color=(255, 250, 250)
)
page = Page(size=(400, 300), style=page_style)
draw_placeholder_content(page)
return page
def create_example_3():
"""Example 3: Page with generous padding."""
print(" Creating Example 3: With padding...")
page_style = PageStyle(
border_width=2,
border_color=(100, 100, 255),
padding=(40, 40, 40, 40),
background_color=(250, 250, 255)
)
page = Page(size=(400, 300), style=page_style)
draw_placeholder_content(page)
return page
def create_example_4():
"""Example 4: Clean, borderless design."""
print(" Creating Example 4: Borderless...")
page_style = PageStyle(
border_width=0,
padding=(30, 30, 30, 30),
background_color=(245, 245, 245)
)
page = Page(size=(400, 300), style=page_style)
draw_placeholder_content(page)
return page
def combine_into_grid(pages, title):
"""Combine multiple pages into a 2x2 grid with title."""
print("\n Combining pages into grid...")
# Render all pages
images = [page.render() for page in pages]
# Grid layout
padding = 20
title_height = 40
cols = 2
rows = 2
# Calculate dimensions
img_width = images[0].size[0]
img_height = images[0].size[1]
total_width = cols * img_width + (cols + 1) * padding
total_height = rows * img_height + (rows + 1) * padding + title_height
# Create combined image
combined = Image.new('RGB', (total_width, total_height), (250, 250, 250))
draw = ImageDraw.Draw(combined)
# Draw title
try:
title_font = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 20)
except BaseException:
title_font = ImageFont.load_default()
# Center the title
bbox = draw.textbbox((0, 0), title, font=title_font)
text_width = bbox[2] - bbox[0]
title_x = (total_width - text_width) // 2
draw.text((title_x, 10), title, fill=(50, 50, 50), font=title_font)
# Place pages in grid
y_offset = title_height + padding
for row in range(rows):
x_offset = padding
for col in range(cols):
idx = row * cols + col
if idx < len(images):
combined.paste(images[idx], (x_offset, y_offset))
x_offset += img_width + padding
y_offset += img_height + padding
return combined
def main():
"""Demonstrate basic page rendering."""
print("Simple Page Rendering Example")
print("=" * 50)
# Create different page examples
pages = [
create_example_1(),
create_example_2(),
create_example_3(),
create_example_4()
]
# Combine into a single demonstration image
combined_image = combine_into_grid(pages, "Page Styles: Border & Padding Examples")
# Save output
output_dir = Path("docs/images")
output_dir.mkdir(parents=True, exist_ok=True)
output_path = output_dir / "example_01_page_rendering.png"
combined_image.save(output_path)
print("\n✓ Example completed!")
print(f" Output saved to: {output_path}")
print(f" Image size: {combined_image.size[0]}x{combined_image.size[1]} pixels")
print(f" Created {len(pages)} page examples")
return combined_image
if __name__ == "__main__":
main()

View File

@ -0,0 +1,215 @@
#!/usr/bin/env python3
"""
Text and Layout Example
This example demonstrates text rendering using the pyWebLayout system:
- Different text alignments
- Font sizes and styles
- Multi-line paragraphs
- Document layout and pagination
This example uses the HTML parsing system to create rich text layouts.
"""
from pyWebLayout.style.page_style import PageStyle
from pyWebLayout.concrete.page import Page
from pyWebLayout.style import Font
from pyWebLayout.io.readers.html_extraction import parse_html_string
import sys
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont
# Add pyWebLayout to path
sys.path.insert(0, str(Path(__file__).parent.parent))
def create_sample_document():
"""Create different HTML samples demonstrating various features."""
samples = []
# Sample 1: Text alignment examples
samples.append((
"Text Alignment",
"""
<html><body>
<h2>Left Aligned</h2>
<p>This is left-aligned text. It is the default alignment for most text.</p>
<h2>Justified Text</h2>
<p style="text-align: justify;">This paragraph is justified. The text stretches to fill
the entire width of the line, creating clean edges on both sides.</p>
<h2>Centered</h2>
<p style="text-align: center;">This text is centered.</p>
</body></html>
"""
))
# Sample 2: Font sizes
samples.append((
"Font Sizes",
"""
<html><body>
<h1>Heading 1</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>
<p>Normal paragraph text at the default size.</p>
<p><small>Small text for fine print.</small></p>
</body></html>
"""
))
# Sample 3: Text styles
samples.append((
"Text Styles",
"""
<html><body>
<p>Normal text with <b>bold words</b> and <i>italic text</i>.</p>
<p><b>Completely bold paragraph.</b></p>
<p><i>Completely italic paragraph.</i></p>
<p>Text with <u>underlined words</u> for emphasis.</p>
</body></html>
"""
))
# Sample 4: Mixed content
samples.append((
"Mixed Content",
"""
<html><body>
<h2>Document Title</h2>
<p>A paragraph with <b>bold</b>, <i>italic</i>, and normal text all mixed together.</p>
<h3>Subsection</h3>
<p>Another paragraph demonstrating the layout system.</p>
</body></html>
"""
))
return samples
def render_html_to_image(html_content, page_size=(500, 400)):
"""Render HTML content to an image using the pyWebLayout system."""
# Create a page
page_style = PageStyle(
border_width=2,
border_color=(200, 200, 200),
padding=(30, 30, 30, 30),
background_color=(255, 255, 255)
)
page = Page(size=page_size, style=page_style)
# Parse HTML
base_font = Font(font_size=14)
blocks = parse_html_string(html_content, base_font=base_font)
# For now, just render the page structure
# (The full layout engine would place the blocks, but we'll show the page)
image = page.render()
draw = ImageDraw.Draw(image)
# Add a note that this is HTML-parsed content
try:
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 11)
except BaseException:
font = ImageFont.load_default()
# Draw info about what was parsed
content_x = page.border_size + page.style.padding_left + 10
content_y = page.border_size + page.style.padding_top + 10
draw.text((content_x, content_y),
f"Parsed {len(blocks)} block(s) from HTML",
fill=(100, 100, 100), font=font)
# List the block types
y_offset = content_y + 25
for i, block in enumerate(blocks[:10]): # Show first 10
block_type = type(block).__name__
draw.text((content_x, y_offset),
f" {i + 1}. {block_type}",
fill=(60, 60, 60), font=font)
y_offset += 18
if y_offset > page.size[1] - 60: # Don't overflow
break
return image
def combine_samples(samples):
"""Combine multiple sample renders into a grid."""
print("\n Rendering samples...")
images = []
for title, html in samples:
print(f" - {title}")
img = render_html_to_image(html)
# Add title to image
draw = ImageDraw.Draw(img)
try:
font = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 14)
except BaseException:
font = ImageFont.load_default()
draw.text((10, 10), title, fill=(50, 50, 150), font=font)
images.append(img)
# Create grid (2x2)
padding = 20
cols = 2
rows = 2
img_width = images[0].size[0]
img_height = images[0].size[1]
total_width = cols * img_width + (cols + 1) * padding
total_height = rows * img_height + (rows + 1) * padding
combined = Image.new('RGB', (total_width, total_height), (240, 240, 240))
# Place images
y_offset = padding
for row in range(rows):
x_offset = padding
for col in range(cols):
idx = row * cols + col
if idx < len(images):
combined.paste(images[idx], (x_offset, y_offset))
x_offset += img_width + padding
y_offset += img_height + padding
return combined
def main():
"""Demonstrate text and layout features."""
print("Text and Layout Example")
print("=" * 50)
# Create sample documents
samples = create_sample_document()
# Render and combine
combined_image = combine_samples(samples)
# Save output
output_dir = Path("docs/images")
output_dir.mkdir(parents=True, exist_ok=True)
output_path = output_dir / "example_02_text_and_layout.png"
combined_image.save(output_path)
print("\n✓ Example completed!")
print(f" Output saved to: {output_path}")
print(f" Image size: {combined_image.size[0]}x{combined_image.size[1]} pixels")
print(" Note: This example demonstrates HTML parsing")
print(" Full layout rendering requires the typesetting engine")
return combined_image
if __name__ == "__main__":
main()

247
examples/03_page_layouts.py Normal file
View File

@ -0,0 +1,247 @@
#!/usr/bin/env python3
"""
Page Layouts Example
This example demonstrates different page layout configurations:
- Various page sizes (small, medium, large)
- Different aspect ratios (portrait, landscape, square)
- Border and padding variations
- Color schemes
Shows how the pyWebLayout system handles different page dimensions.
"""
from pyWebLayout.style.page_style import PageStyle
from pyWebLayout.concrete.page import Page
import sys
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont
# Add pyWebLayout to path
sys.path.insert(0, str(Path(__file__).parent.parent))
def add_page_info(page: Page, title: str):
"""Add informational text to a page showing its properties."""
if page.draw is None:
page.render()
draw = page.draw
try:
font_large = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 14)
font_small = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 11)
except BaseException:
font_large = ImageFont.load_default()
font_small = ImageFont.load_default()
# Title
content_x = page.border_size + page.style.padding_left + 5
content_y = page.border_size + page.style.padding_top + 5
draw.text((content_x, content_y), title, fill=(40, 40, 40), font=font_large)
# Page info
y = content_y + 25
info = [
f"Page: {page.size[0]}×{page.size[1]}px",
f"Content: {page.content_size[0]}×{page.content_size[1]}px",
f"Border: {page.border_size}px",
f"Padding: {page.style.padding}",
]
for line in info:
draw.text((content_x, y), line, fill=(80, 80, 80), font=font_small)
y += 16
# Draw content area boundary
cx = page.border_size + page.style.padding_left
cy = page.border_size + page.style.padding_top
cw = page.content_size[0]
ch = page.content_size[1]
draw.rectangle(
[cx, cy, cx + cw, cy + ch],
outline=(150, 150, 255),
width=1
)
def create_layouts():
"""Create various page layout examples."""
layouts = []
# 1. Small portrait page
print("\n Creating layout examples...")
print(" - Small portrait")
style1 = PageStyle(
border_width=2,
border_color=(100, 100, 100),
padding=(15, 15, 15, 15),
background_color=(255, 255, 255)
)
page1 = Page(size=(300, 400), style=style1)
add_page_info(page1, "Small Portrait")
layouts.append(("small_portrait", page1))
# 2. Large portrait page
print(" - Large portrait")
style2 = PageStyle(
border_width=3,
border_color=(150, 100, 100),
padding=(30, 30, 30, 30),
background_color=(255, 250, 250)
)
page2 = Page(size=(400, 600), style=style2)
add_page_info(page2, "Large Portrait")
layouts.append(("large_portrait", page2))
# 3. Landscape page
print(" - Landscape")
style3 = PageStyle(
border_width=2,
border_color=(100, 150, 100),
padding=(20, 40, 20, 40),
background_color=(250, 255, 250)
)
page3 = Page(size=(600, 350), style=style3)
add_page_info(page3, "Landscape")
layouts.append(("landscape", page3))
# 4. Square page
print(" - Square")
style4 = PageStyle(
border_width=3,
border_color=(100, 100, 150),
padding=(25, 25, 25, 25),
background_color=(250, 250, 255)
)
page4 = Page(size=(400, 400), style=style4)
add_page_info(page4, "Square")
layouts.append(("square", page4))
# 5. Minimal padding
print(" - Minimal padding")
style5 = PageStyle(
border_width=1,
border_color=(180, 180, 180),
padding=(5, 5, 5, 5),
background_color=(245, 245, 245)
)
page5 = Page(size=(350, 300), style=style5)
add_page_info(page5, "Minimal Padding")
layouts.append(("minimal", page5))
# 6. Generous padding
print(" - Generous padding")
style6 = PageStyle(
border_width=2,
border_color=(150, 120, 100),
padding=(50, 50, 50, 50),
background_color=(255, 250, 245)
)
page6 = Page(size=(400, 400), style=style6)
add_page_info(page6, "Generous Padding")
layouts.append(("generous", page6))
return layouts
def create_layout_showcase(layouts):
"""Create a showcase image displaying all layouts."""
print("\n Creating layout showcase...")
# Render all pages
images = [(name, page.render()) for name, page in layouts]
# Calculate grid layout (3×2)
padding = 15
title_height = 50
cols = 3
rows = 2
# Find max dimensions for each row/column
max_widths = []
for col in range(cols):
col_images = [images[row * cols + col][1]
for row in range(rows) if row * cols + col < len(images)]
if col_images:
max_widths.append(max(img.size[0] for img in col_images))
max_heights = []
for row in range(rows):
row_images = [images[row * cols + col][1]
for col in range(cols) if row * cols + col < len(images)]
if row_images:
max_heights.append(max(img.size[1] for img in row_images))
# Calculate total size
total_width = sum(max_widths) + padding * (cols + 1)
total_height = sum(max_heights) + padding * (rows + 1) + title_height
# Create combined image
combined = Image.new('RGB', (total_width, total_height), (235, 235, 235))
draw = ImageDraw.Draw(combined)
# Add title
try:
title_font = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 24)
except BaseException:
title_font = ImageFont.load_default()
title_text = "Page Layout Examples"
bbox = draw.textbbox((0, 0), title_text, font=title_font)
text_width = bbox[2] - bbox[0]
title_x = (total_width - text_width) // 2
draw.text((title_x, 15), title_text, fill=(50, 50, 50), font=title_font)
# Place images in grid
y_offset = title_height + padding
for row in range(rows):
x_offset = padding
for col in range(cols):
idx = row * cols + col
if idx < len(images):
name, img = images[idx]
# Center image in its cell
cell_width = max_widths[col]
cell_height = max_heights[row]
img_x = x_offset + (cell_width - img.size[0]) // 2
img_y = y_offset + (cell_height - img.size[1]) // 2
combined.paste(img, (img_x, img_y))
x_offset += max_widths[col] + padding if col < len(max_widths) else 0
y_offset += max_heights[row] + padding if row < len(max_heights) else 0
return combined
def main():
"""Demonstrate page layout variations."""
print("Page Layouts Example")
print("=" * 50)
# Create different layouts
layouts = create_layouts()
# Create showcase
combined_image = create_layout_showcase(layouts)
# Save output
output_dir = Path("docs/images")
output_dir.mkdir(parents=True, exist_ok=True)
output_path = output_dir / "example_03_page_layouts.png"
combined_image.save(output_path)
print("\n✓ Example completed!")
print(f" Output saved to: {output_path}")
print(f" Image size: {combined_image.size[0]}x{combined_image.size[1]} pixels")
print(f" Created {len(layouts)} layout examples")
return combined_image
if __name__ == "__main__":
main()

View File

@ -0,0 +1,364 @@
#!/usr/bin/env python3
"""
Table Rendering Example
This example demonstrates rendering HTML tables:
- Simple tables with headers
- Tables with multiple rows and columns
- Tables with colspan and borders
- Tables with formatted content
- Tables parsed from HTML using DocumentLayouter
Shows the HTML-first rendering pipeline.
"""
from pyWebLayout.abstract.block import Table
from pyWebLayout.style import Font
from pyWebLayout.io.readers.html_extraction import parse_html_string
from pyWebLayout.layout.document_layouter import DocumentLayouter
from pyWebLayout.style.page_style import PageStyle
from pyWebLayout.concrete.table import TableStyle
from pyWebLayout.concrete.page import Page
import sys
from pathlib import Path
from PIL import Image, ImageDraw
# Add pyWebLayout to path
sys.path.insert(0, str(Path(__file__).parent.parent))
def create_simple_table_example():
"""Create a simple table from HTML."""
print(" - Simple data table")
html = """
<table>
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>City</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alice</td>
<td>28</td>
<td>Paris</td>
</tr>
<tr>
<td>Bob</td>
<td>34</td>
<td>London</td>
</tr>
<tr>
<td>Charlie</td>
<td>25</td>
<td>Tokyo</td>
</tr>
</tbody>
</table>
"""
return html, "Simple Table"
def create_styled_table_example():
"""Create a table with custom styling."""
print(" - Styled table")
html = """
<table>
<caption>Monthly Sales Report</caption>
<thead>
<tr>
<th>Month</th>
<th>Revenue</th>
<th>Expenses</th>
<th>Profit</th>
</tr>
</thead>
<tbody>
<tr>
<td>January</td>
<td>$50,000</td>
<td>$30,000</td>
<td>$20,000</td>
</tr>
<tr>
<td>February</td>
<td>$55,000</td>
<td>$32,000</td>
<td>$23,000</td>
</tr>
<tr>
<td>March</td>
<td>$60,000</td>
<td>$35,000</td>
<td>$25,000</td>
</tr>
</tbody>
</table>
"""
return html, "Styled Table"
def create_complex_table_example():
"""Create a table with colspan."""
print(" - Complex table with colspan")
html = """
<table>
<caption>Product Specifications</caption>
<thead>
<tr>
<th>Product</th>
<th>Features</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>Laptop</td>
<td>16GB RAM, 512GB SSD</td>
<td>$1,299</td>
</tr>
<tr>
<td>Monitor</td>
<td>27 inch, 4K Resolution</td>
<td>$599</td>
</tr>
<tr>
<td>Keyboard</td>
<td>Mechanical, RGB</td>
<td>$129</td>
</tr>
</tbody>
</table>
"""
return html, "Complex Table"
def create_data_table_example():
"""Create a table with numerical data."""
print(" - Data table")
html = """
<table>
<caption>Test Results</caption>
<thead>
<tr>
<th>Test</th>
<th>Score</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Unit Tests</td>
<td>98%</td>
<td>Pass</td>
</tr>
<tr>
<td>Integration</td>
<td>95%</td>
<td>Pass</td>
</tr>
<tr>
<td>Performance</td>
<td>87%</td>
<td>Pass</td>
</tr>
</tbody>
</table>
"""
return html, "Data Table"
def render_table_example(
html: str,
title: str,
style_variant: int = 0,
page_size=(
500,
400)):
"""Render a table from HTML to an image using DocumentLayouter."""
# Create page with varying backgrounds
bg_colors = [
(255, 255, 255), # White
(250, 255, 250), # Light green tint
(255, 250, 245), # Light orange tint
(245, 250, 255), # Light blue tint
]
page_style = PageStyle(
border_width=2,
border_color=(200, 200, 200),
padding=(20, 20, 20, 20),
background_color=bg_colors[style_variant % len(bg_colors)]
)
page = Page(size=page_size, style=page_style)
# Parse HTML to get table
base_font = Font(font_size=12)
blocks = parse_html_string(html, base_font=base_font)
# Find the table block
table = None
for block in blocks:
if isinstance(block, Table):
table = block
break
# Table styles with different themes
table_styles = [
# Style 0: Classic blue header
TableStyle(
border_width=1,
border_color=(80, 80, 80),
cell_padding=(8, 10, 8, 10),
header_bg_color=(70, 130, 180), # Steel blue
cell_bg_color=(255, 255, 255),
alternate_row_color=(240, 248, 255) # Alice blue
),
# Style 1: Green theme
TableStyle(
border_width=2,
border_color=(34, 139, 34), # Forest green
cell_padding=(10, 12, 10, 12),
header_bg_color=(144, 238, 144), # Light green
cell_bg_color=(255, 255, 255),
alternate_row_color=(240, 255, 240) # Honeydew
),
# Style 2: Minimal style
TableStyle(
border_width=0,
border_color=(200, 200, 200),
cell_padding=(6, 8, 6, 8),
header_bg_color=(245, 245, 245),
cell_bg_color=(255, 255, 255),
alternate_row_color=None # No alternating
),
# Style 3: Bold borders
TableStyle(
border_width=3,
border_color=(0, 0, 0),
cell_padding=(10, 10, 10, 10),
header_bg_color=(255, 215, 0), # Gold
cell_bg_color=(255, 255, 255),
alternate_row_color=(255, 250, 205) # Lemon chiffon
),
]
table_style = table_styles[style_variant % len(table_styles)]
if table:
# Create DocumentLayouter
layouter = DocumentLayouter(page)
# Use DocumentLayouter to layout the table
layouter.layout_table(table, style=table_style)
# Get the rendered canvas
_ = page.draw # Ensure canvas exists
image = page._canvas
else:
# No table found - create empty page
_ = page.draw # Ensure canvas exists
draw = ImageDraw.Draw(page._canvas)
draw.text((page.border_size + 10, page.border_size + 50),
"No table found in HTML",
fill=(200, 0, 0))
image = page._canvas
return image
def combine_examples(examples):
"""Combine multiple table examples into a grid."""
print("\n Rendering table examples...")
images = []
for i, (html, title) in enumerate(examples):
img = render_table_example(html, title, style_variant=i)
images.append(img)
# Create grid (2x2)
padding = 15
cols = 2
rows = 2
img_width = images[0].size[0]
img_height = images[0].size[1]
total_width = cols * img_width + (cols + 1) * padding
total_height = rows * img_height + (rows + 1) * padding + 50 # Extra for main title
combined = Image.new('RGB', (total_width, total_height), (240, 240, 240))
draw = ImageDraw.Draw(combined)
# Add main title
from PIL import ImageFont
try:
main_font = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 20)
except BaseException:
main_font = ImageFont.load_default()
title_text = "Table Rendering Examples"
bbox = draw.textbbox((0, 0), title_text, font=main_font)
text_width = bbox[2] - bbox[0]
title_x = (total_width - text_width) // 2
draw.text((title_x, 15), title_text, fill=(50, 50, 50), font=main_font)
# Place images
y_offset = 50 + padding
for row in range(rows):
x_offset = padding
for col in range(cols):
idx = row * cols + col
if idx < len(images):
combined.paste(images[idx], (x_offset, y_offset))
x_offset += img_width + padding
y_offset += img_height + padding
return combined
def main():
"""Demonstrate table rendering."""
print("Table Rendering Example")
print("=" * 50)
# Create table examples
print("\n Creating table examples...")
examples = [
create_simple_table_example(),
create_styled_table_example(),
create_complex_table_example(),
create_data_table_example()
]
# Render and combine
combined_image = combine_examples(examples)
# Save output
output_dir = Path("docs/images")
output_dir.mkdir(parents=True, exist_ok=True)
output_path = output_dir / "example_04_table_rendering.png"
combined_image.save(output_path)
print("\n✓ Example completed!")
print(f" Output saved to: {output_path}")
print(f" Image size: {combined_image.size[0]}x{combined_image.size[1]} pixels")
print(f" Created {len(examples)} table examples")
return combined_image
if __name__ == "__main__":
main()

View File

@ -0,0 +1,272 @@
#!/usr/bin/env python3
"""
HTML Table with Images Example - End-to-End Rendering
This example demonstrates the complete pipeline:
1. HTML table source with <img> tags in cells
2. parse_html_string() converts HTML Abstract document structure
3. DocumentLayouter handles all layout and rendering
No custom rendering code needed - DocumentLayouter handles everything!
"""
from pyWebLayout.style import Font
from pyWebLayout.concrete.table import TableStyle
from pyWebLayout.layout.document_layouter import DocumentLayouter
from pyWebLayout.style.page_style import PageStyle
from pyWebLayout.concrete.page import Page
from pyWebLayout.io.readers.html_extraction import parse_html_string
import sys
from pathlib import Path
from PIL import Image
# Add pyWebLayout to path
sys.path.insert(0, str(Path(__file__).parent.parent))
def create_book_catalog_html():
"""Create HTML for a book catalog table with actual <img> tags."""
# Get base path for images - use absolute paths for the img src
data_path = Path(__file__).parent.parent / "tests" / "data"
html = f"""
<html>
<body>
<table>
<thead>
<tr>
<th>Cover</th>
<th>Title</th>
<th>Author</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td><img src="{data_path / 'cover 1.png'}" alt="The Great Adventure" /></td>
<td>The Great Adventure</td>
<td>John Smith</td>
<td><b>$19.99</b></td>
</tr>
<tr>
<td><img src="{data_path / 'cover 2.png'}" alt="Mystery of the Ages" /></td>
<td>Mystery of the Ages</td>
<td>Jane Doe</td>
<td><b>$24.99</b></td>
</tr>
<tr>
<td><img src="{data_path / 'cover 3.png'}" alt="Science Today" /></td>
<td>Science Today</td>
<td>Dr. Brown</td>
<td><b>$29.99</b></td>
</tr>
<tr>
<td><img src="{data_path / 'cover 4.png'}" alt="Art & Design" /></td>
<td>Art & Design</td>
<td>M. Artist</td>
<td><b>$34.99</b></td>
</tr>
</tbody>
</table>
</body>
</html>
"""
return html
def create_product_showcase_html():
"""Create HTML for a product showcase table with images."""
data_path = Path(__file__).parent.parent / "tests" / "data"
html = f"""
<html>
<body>
<table>
<thead>
<tr>
<th>Product</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><img src="{data_path / 'cover 1.png'}" alt="Premium Edition" /></td>
<td>Premium Edition - Hardcover with gold embossing</td>
</tr>
<tr>
<td><img src="{data_path / 'cover 2.png'}" alt="Collector's Item" /></td>
<td>Collector's Item - Limited print run</td>
</tr>
</tbody>
</table>
</body>
</html>
"""
return html
def render_html_with_layouter(html_string: str, title: str,
table_style: TableStyle,
page_size=(600, 500)):
"""
Render HTML using DocumentLayouter - the proper way!
This function demonstrates the correct usage:
1. Parse HTML Abstract blocks
2. Create Page
3. Create DocumentLayouter
4. Layout all blocks using layouter
Args:
html_string: HTML source containing table with <img> tags
title: Title for the output (for logging)
table_style: Table styling configuration
page_size: Page dimensions
Returns:
PIL Image with rendered content
"""
print(f"\n Processing '{title}'...")
# Step 1: Parse HTML to abstract blocks
print(" 1. Parsing HTML → Abstract blocks...")
base_font = Font(font_size=11)
blocks = parse_html_string(html_string, base_font=base_font)
print(f" → Parsed {len(blocks)} blocks")
# Step 2: Create page
print(" 2. Creating page...")
page_style = PageStyle(
border_width=2,
border_color=(180, 180, 180),
padding=(20, 20, 20, 20),
background_color=(255, 255, 255)
)
page = Page(size=page_size, style=page_style)
# Step 3: Create DocumentLayouter
print(" 3. Creating DocumentLayouter...")
layouter = DocumentLayouter(page)
# Step 4: Layout all blocks using the layouter
print(" 4. Laying out all blocks...")
for block in blocks:
# For tables, we can pass a custom style
from pyWebLayout.abstract.block import Table
if isinstance(block, Table):
success = layouter.layout_table(block, style=table_style)
else:
# For other blocks (paragraphs, headings, images), use layout_document
success = layouter.layout_document([block])
if not success:
print(f" ⚠ Warning: Block {type(block).__name__} didn't fit on page")
print(" ✓ Layout complete!")
# Step 5: Get the rendered canvas
# Note: Tables render directly onto page._canvas
# We access page.draw to ensure canvas is initialized
print(" 5. Getting rendered canvas...")
_ = page.draw # Ensure canvas exists
return page._canvas
def main():
"""Demonstrate end-to-end HTML table with images rendering using DocumentLayouter."""
print("HTML Table with Images Example - DocumentLayouter")
print("=" * 60)
print("\nThis example demonstrates:")
print(" 1. HTML with <img> tags inside <td> cells")
print(" 2. parse_html_string() automatically handles images")
print(" 3. DocumentLayouter handles all layout and rendering")
print(" 4. NO manual TableRenderer or custom rendering code!")
# Verify images exist
print("\n Checking for cover images...")
data_path = Path(__file__).parent.parent / "tests" / "data"
cover_count = 0
for i in range(1, 5):
cover_path = data_path / f"cover {i}.png"
if cover_path.exists():
cover_count += 1
print(f" ✓ Found cover {i}.png")
if cover_count == 0:
print(" ✗ No cover images found! This example requires cover images.")
return
# Create HTML sources with <img> tags
print("\n Creating HTML sources with <img> tags...")
print(" - Book catalog HTML")
book_html = create_book_catalog_html()
print(" - Product showcase HTML")
product_html = create_product_showcase_html()
# Define table styles
book_style = TableStyle(
border_width=1,
border_color=(100, 100, 100),
cell_padding=(8, 10, 8, 10),
header_bg_color=(70, 130, 180),
cell_bg_color=(255, 255, 255),
alternate_row_color=(245, 248, 250)
)
product_style = TableStyle(
border_width=2,
border_color=(60, 120, 60),
cell_padding=(10, 12, 10, 12),
header_bg_color=(144, 238, 144),
cell_bg_color=(255, 255, 255),
alternate_row_color=(240, 255, 240)
)
# Render using DocumentLayouter - the proper way!
print("\n Rendering with DocumentLayouter (HTML → Abstract → Layout → PNG)...")
book_image = render_html_with_layouter(
book_html,
"Book Catalog",
book_style,
page_size=(700, 600)
)
product_image = render_html_with_layouter(
product_html,
"Product Showcase",
product_style,
page_size=(600, 350)
)
# Combine images side by side
print("\n Combining output images...")
padding = 20
total_width = book_image.size[0] + product_image.size[0] + padding * 3
total_height = max(book_image.size[1], product_image.size[1]) + padding * 2
combined = Image.new('RGB', (total_width, total_height), (240, 240, 240))
combined.paste(book_image, (padding, padding))
combined.paste(product_image, (book_image.size[0] + padding * 2, padding))
# Save output
output_dir = Path("docs/images")
output_dir.mkdir(parents=True, exist_ok=True)
output_path = output_dir / "example_05_html_table_with_images.png"
combined.save(output_path)
print("\n✓ Example completed!")
print(f" Output saved to: {output_path}")
print(f" Image size: {combined.size[0]}x{combined.size[1]} pixels")
print("\nThe complete pipeline:")
print(" 1. HTML with <img> tags → parse_html_string() → Abstract blocks")
print(" 2. Abstract blocks → DocumentLayouter → Concrete objects")
print(" 3. Page.render() → PNG output")
print("\n ✓ Using DocumentLayouter - NO custom rendering code!")
return combined
if __name__ == "__main__":
main()

View File

@ -0,0 +1,292 @@
"""
Demonstration of functional elements (buttons, forms, links) with callback binding.
This example shows how to:
1. Create functional elements programmatically
2. Layout them on a page
3. Bind callbacks after layout using the CallbackRegistry
4. Simulate user interactions
This pattern is useful for:
- Manual GUI construction
- Applications where callbacks need access to runtime state
- Interactive document interfaces
"""
from pyWebLayout.concrete import Page
from pyWebLayout.abstract.functional import Button, Form, FormField, FormFieldType
from pyWebLayout.abstract import Paragraph, Word
from pyWebLayout.style import Font
from pyWebLayout.style.page_style import PageStyle
from pyWebLayout.layout.document_layouter import DocumentLayouter
import numpy as np
class SimpleApp:
"""
A simple application that demonstrates functional element usage.
This app has:
- A settings form
- Save and Cancel buttons
- Application state that callbacks can access
"""
def __init__(self):
self.settings = {
"username": "",
"theme": "light",
"notifications": True
}
self.saved = False
def on_save_click(self, point, **kwargs):
"""Callback for save button"""
print(f"Save button clicked at {point}")
self.saved = True
print("Settings saved!")
return "saved"
def on_cancel_click(self, point, **kwargs):
"""Callback for cancel button"""
print(f"Cancel button clicked at {point}")
print("Changes cancelled!")
return "cancelled"
def on_reset_click(self, point, **kwargs):
"""Callback for reset button"""
print(f"Reset button clicked at {point}")
self.settings = {
"username": "",
"theme": "light",
"notifications": True
}
print("Settings reset to defaults!")
return "reset"
def create_settings_page():
"""
Create a settings page with functional elements.
Returns:
Tuple of (page, app, element_ids) where element_ids maps
semantic names to registered callback ids
"""
# Create the application instance
app = SimpleApp()
# Create page
page = Page(size=(600, 800), style=PageStyle(border_width=10))
layouter = DocumentLayouter(page)
# Create content
font = Font(font_size=16, colour=(0, 0, 0))
# Title paragraph
title_font = Font(font_size=24, colour=(0, 0, 100))
title = Paragraph(title_font)
title.add_word(Word("Settings", title_font))
# Description paragraph
desc = Paragraph(font)
desc.add_word(Word("Configure", font))
desc.add_word(Word("your", font))
desc.add_word(Word("application", font))
desc.add_word(Word("preferences", font))
desc.add_word(Word("below.", font))
# Layout title and description
layouter.layout_paragraph(title)
page._current_y_offset += 10 # Add some spacing
layouter.layout_paragraph(desc)
page._current_y_offset += 20 # Add more spacing before form
# Create form
settings_form = Form(
form_id="settings-form",
action="/save-settings",
html_id="settings-form"
)
# Add form fields
username_field = FormField(
name="username",
field_type=FormFieldType.TEXT,
label="Username",
value="john_doe"
)
theme_field = FormField(
name="theme",
field_type=FormFieldType.SELECT,
label="Theme",
value="light",
options=[("light", "Light"), ("dark", "Dark")]
)
notifications_field = FormField(
name="notifications",
field_type=FormFieldType.CHECKBOX,
label="Enable Notifications",
value=True
)
settings_form.add_field(username_field)
settings_form.add_field(theme_field)
settings_form.add_field(notifications_field)
# Layout the form
success, field_ids = layouter.layout_form(settings_form)
if not success:
print("Warning: Form didn't fit on page!")
page._current_y_offset += 20 # Spacing before buttons
# Create buttons (NO callbacks yet - will be bound later)
save_button = Button(
label="Save Settings",
callback=None, # No callback yet!
html_id="save-btn"
)
cancel_button = Button(
label="Cancel",
callback=None, # No callback yet!
html_id="cancel-btn"
)
reset_button = Button(
label="Reset to Defaults",
callback=None, # No callback yet!
html_id="reset-btn"
)
# Layout buttons
button_font = Font(font_size=14, colour=(255, 255, 255))
success1, save_id = layouter.layout_button(save_button, font=button_font)
page._current_y_offset += 10 # Spacing between buttons
success2, cancel_id = layouter.layout_button(cancel_button, font=button_font)
page._current_y_offset += 10
success3, reset_id = layouter.layout_button(reset_button, font=button_font)
# ==============================================================
# IMPORTANT: Callbacks are bound AFTER layout is complete
# This allows callbacks to access the application instance
# ==============================================================
# Bind callbacks using the page's callback registry
page.callbacks.set_callback("save-btn", app.on_save_click)
page.callbacks.set_callback("cancel-btn", app.on_cancel_click)
page.callbacks.set_callback("reset-btn", app.on_reset_click)
# Track element ids for later reference
element_ids = {
"save_button": save_id,
"cancel_button": cancel_id,
"reset_button": reset_id,
"form_fields": field_ids
}
return page, app, element_ids
def demonstrate_callback_binding():
"""Demonstrate various callback binding patterns"""
print("=" * 60)
print("Functional Elements Demo: Manual GUI Construction")
print("=" * 60)
print()
# Create the page
page, app, element_ids = create_settings_page()
print(f"Page created with {page.callbacks.count()} interactable elements")
print()
# Show what's registered
print("Registered interactables:")
for id_name in page.callbacks.get_all_ids():
print(f" - {id_name}")
print()
# Show breakdown by type
print("Breakdown by type:")
for type_name in page.callbacks.get_all_types():
count = page.callbacks.count_by_type(type_name)
print(f" - {type_name}: {count}")
print()
# Simulate user clicking the save button
print("Simulating user interaction:")
print("-" * 60)
print()
# Get the save button
save_button = page.callbacks.get_by_id("save-btn")
print(f"Retrieved save button: {save_button}")
# Simulate a click at position (50, 200)
click_point = np.array([50, 200])
print(f"Simulating click at {click_point}...")
result = save_button.interact(click_point)
print(f"Button interaction returned: {result}")
print(f"App.saved state: {app.saved}")
print()
# Simulate clicking cancel
cancel_button = page.callbacks.get_by_id("cancel-btn")
print("Simulating cancel button click...")
result = cancel_button.interact(click_point)
print(f"Button interaction returned: {result}")
print()
# Simulate clicking reset
reset_button = page.callbacks.get_by_id("reset-btn")
print("Simulating reset button click...")
result = reset_button.interact(click_point)
print(f"Button interaction returned: {result}")
print()
# Demonstrate batch callback modification
print("-" * 60)
print("Demonstrating batch callback modification:")
print()
def log_all_clicks(point, **kwargs):
"""Generic click logger"""
print(f" [LOG] Button clicked at {point}")
return "logged"
# Set this callback for all buttons
count = page.callbacks.set_callbacks_by_type("button", log_all_clicks)
print(f"Set logging callback for {count} buttons")
print()
# Now clicking any button will just log
print("Clicking save button again (now with logging callback):")
result = save_button.interact(click_point)
print(f"Returned: {result}")
print()
# Render the page
print("-" * 60)
print("Rendering page...")
image = page.render()
print(f"Page rendered: {image.size}")
# Save to file
output_path = "functional_elements_demo.png"
image.save(output_path)
print(f"Saved to: {output_path}")
print()
print("=" * 60)
print("Demo complete!")
print("=" * 60)
if __name__ == "__main__":
demonstrate_callback_binding()

View File

@ -0,0 +1,452 @@
"""
Demonstration of pressed/depressed states for buttons and links with visual feedback.
This example shows:
1. How to use the InteractionHandler for automatic press/release cycles
2. How to manually manage states for custom event loops
3. How the dirty flag system tracks when re-rendering is needed
4. Visual differences between normal, hovered, and pressed states
The demo creates a page with buttons and links, then simulates clicking them
with proper visual feedback timing.
"""
from pyWebLayout.concrete import Page
from pyWebLayout.concrete.interaction_handler import InteractionHandler, InteractionStateManager
from pyWebLayout.abstract.functional import Button, Link, LinkType
from pyWebLayout.abstract import Paragraph, Word
from pyWebLayout.abstract.inline import LinkedWord
from pyWebLayout.style import Font
from pyWebLayout.style.page_style import PageStyle
from pyWebLayout.layout.document_layouter import DocumentLayouter
import numpy as np
import time
def create_interactive_demo_page():
"""
Create a page with various interactive elements demonstrating state changes.
"""
# Create page
page = Page(size=(600, 500), style=PageStyle(border_width=10))
layouter = DocumentLayouter(page)
# Create fonts
title_font = Font(font_size=24, colour=(0, 0, 100))
body_font = Font(font_size=16, colour=(0, 0, 0))
button_font = Font(font_size=14, colour=(255, 255, 255))
# Title
title = Paragraph(title_font)
title.add_word(Word("Interactive", title_font))
title.add_word(Word("Elements", title_font))
title.add_word(Word("Demo", title_font))
layouter.layout_paragraph(title)
page._current_y_offset += 15
# Description
desc = Paragraph(body_font)
desc.add_word(Word("Click", body_font))
desc.add_word(Word("the", body_font))
desc.add_word(Word("buttons", body_font))
desc.add_word(Word("and", body_font))
desc.add_word(Word("links", body_font))
desc.add_word(Word("below", body_font))
desc.add_word(Word("to", body_font))
desc.add_word(Word("see", body_font))
desc.add_word(Word("pressed", body_font))
desc.add_word(Word("state", body_font))
desc.add_word(Word("feedback!", body_font))
layouter.layout_paragraph(desc)
page._current_y_offset += 20
# Callback functions
def on_save():
print("💾 Save button clicked!")
return "saved"
def on_cancel():
print("❌ Cancel button clicked!")
return "cancelled"
def on_link_click(location, point):
print(f"🔗 Link clicked: {location} at {point}")
return location
# Create buttons
save_button = Button(
label="Save Document",
callback=lambda point, **kwargs: on_save(),
html_id="save-btn"
)
cancel_button = Button(
label="Cancel",
callback=lambda point, **kwargs: on_cancel(),
html_id="cancel-btn"
)
# Layout buttons
success1, save_id = layouter.layout_button(save_button, font=button_font)
page._current_y_offset += 12
success2, cancel_id = layouter.layout_button(cancel_button, font=button_font)
page._current_y_offset += 25
# Create paragraph with links
link_para = Paragraph(body_font)
link_para.add_word(Word("Visit", body_font))
link_para.add_word(Word("our", body_font))
# Add a link
internal_link = Link(
location="https://example.com",
link_type=LinkType.EXTERNAL,
callback=on_link_click,
title="Example website"
)
link_para.add_word(LinkedWord(
"website",
body_font,
location="https://example.com",
link_type=LinkType.EXTERNAL,
callback=on_link_click,
title="Example website"
))
link_para.add_word(Word("or", body_font))
# Add another link
docs_link = Link(
location="/docs",
link_type=LinkType.INTERNAL,
callback=on_link_click,
title="Documentation"
)
link_para.add_word(LinkedWord(
"documentation",
body_font,
location="/docs",
link_type=LinkType.INTERNAL,
callback=on_link_click,
title="Documentation"
))
link_para.add_word(Word("page.", body_font))
layouter.layout_paragraph(link_para)
return page, save_id, cancel_id
def demo_automatic_interaction():
"""
Demonstrate automatic interaction handling with InteractionHandler.
This shows the simplest usage pattern where InteractionHandler manages
the complete press/release cycle automatically.
"""
print("=" * 70)
print("Demo 1: Automatic Interaction with Visual Feedback")
print("=" * 70)
print()
# Create the page
page, save_id, cancel_id = create_interactive_demo_page()
# Create interaction handler
handler = InteractionHandler(page, press_duration_ms=150)
print("Initial render:")
initial_render = page.render()
initial_render.save("demo_07_initial.png")
print(f" ✓ Saved: demo_07_initial.png")
print(f" ✓ Page dirty flag: {page.is_dirty}")
print()
# Get the save button
save_button = page.callbacks.get_by_id("save-btn")
click_point = np.array([50, 150])
print("Simulating button click with automatic feedback...")
print(f" → Setting pressed state at t=0ms")
# Execute with automatic feedback
pressed_frame, released_frame, result = handler.execute_with_feedback(
save_button,
click_point
)
print(f" → Showing pressed state for 150ms")
print(f" → Executing callback")
print(f" → Result: {result}")
print(f" → Setting released state")
# Save the frames
pressed_frame.save("demo_07_pressed.png")
print(f" ✓ Saved: demo_07_pressed.png")
released_frame.save("demo_07_released.png")
print(f" ✓ Saved: demo_07_released.png")
print()
def demo_manual_state_management():
"""
Demonstrate manual state management for custom event loops.
This shows how an application with its own event loop can manage
states and check the dirty flag before re-rendering.
"""
print("=" * 70)
print("Demo 2: Manual State Management with Dirty Flag Checking")
print("=" * 70)
print()
# Create the page
page, save_id, cancel_id = create_interactive_demo_page()
# Initial render
print("Initial render:")
current_frame = page.render()
print(f" ✓ Page dirty: {page.is_dirty} (cleaned after render)")
print()
# Get the cancel button
cancel_button = page.callbacks.get_by_id("cancel-btn")
# Simulate mouse down
print("Mouse down event:")
# Set page reference if not already set
if not hasattr(cancel_button, '_page') or cancel_button._page is None:
cancel_button.set_page(page)
cancel_button.set_pressed(True)
print(f" ✓ Set pressed state")
print(f" ✓ Page dirty: {page.is_dirty} (needs re-render)")
# Check if we need to re-render
if page.is_dirty:
print(" → Re-rendering (dirty flag is set)")
current_frame = page.render()
current_frame.save("demo_07_manual_pressed.png")
print(f" ✓ Saved: demo_07_manual_pressed.png")
print(f" ✓ Page dirty: {page.is_dirty} (cleaned after render)")
print()
# Wait a bit
print("Waiting 150ms for visual feedback...")
time.sleep(0.15)
print()
# Execute callback
print("Executing callback:")
result = cancel_button.interact(np.array([50, 200]))
print(f" ✓ Result: {result}")
print()
# Simulate mouse up
print("Mouse up event:")
cancel_button.set_pressed(False)
print(f" ✓ Set released state")
print(f" ✓ Page dirty: {page.is_dirty} (needs re-render)")
# Check if we need to re-render
if page.is_dirty:
print(" → Re-rendering (dirty flag is set)")
current_frame = page.render()
current_frame.save("demo_07_manual_released.png")
print(f" ✓ Saved: demo_07_manual_released.png")
print(f" ✓ Page dirty: {page.is_dirty} (cleaned after render)")
print()
def demo_state_manager():
"""
Demonstrate the InteractionStateManager for hover/press tracking.
This shows how to use the high-level state manager that automatically
handles hover and press states based on cursor position.
"""
print("=" * 70)
print("Demo 3: InteractionStateManager for Hover and Press Tracking")
print("=" * 70)
print()
# Create the page
page, save_id, cancel_id = create_interactive_demo_page()
# Create state manager
state_mgr = InteractionStateManager(page)
# Initial render
print("Initial render:")
current_frame = page.render()
print(f" ✓ Rendered initial state")
print()
# Simulate cursor moving over a button
button_center = (150, 150)
print(f"Cursor moves to button position {button_center}:")
hover_frame = state_mgr.update_hover(button_center)
if hover_frame:
print(f" ✓ Hover state changed, page re-rendered")
hover_frame.save("demo_07_hover.png")
print(f" ✓ Saved: demo_07_hover.png")
print()
# Simulate mouse down
print(f"Mouse down at {button_center}:")
pressed_frame = state_mgr.handle_mouse_down(button_center)
if pressed_frame:
print(f" ✓ Pressed state set, page re-rendered")
pressed_frame.save("demo_07_state_mgr_pressed.png")
print(f" ✓ Saved: demo_07_state_mgr_pressed.png")
print()
# Wait for visual feedback
time.sleep(0.15)
# Simulate mouse up
print(f"Mouse up at {button_center}:")
released_frame, result = state_mgr.handle_mouse_up(button_center)
if released_frame:
print(f" ✓ Released state set, page re-rendered")
print(f" ✓ Callback result: {result}")
released_frame.save("demo_07_state_mgr_released.png")
print(f" ✓ Saved: demo_07_state_mgr_released.png")
print()
# Simulate cursor moving away
away_point = (50, 50)
print(f"Cursor moves away to {away_point}:")
away_frame = state_mgr.update_hover(away_point)
if away_frame:
print(f" ✓ Hover state cleared, page re-rendered")
away_frame.save("demo_07_no_hover.png")
print(f" ✓ Saved: demo_07_no_hover.png")
print()
def demo_performance_optimization():
"""
Demonstrate how the dirty flag prevents unnecessary re-renders.
"""
print("=" * 70)
print("Demo 4: Performance Optimization with Dirty Flag")
print("=" * 70)
print()
# Create the page
page, save_id, cancel_id = create_interactive_demo_page()
print("Scenario: Multiple state queries without changes")
print()
# Initial render
page.render()
print(f"1. After initial render - dirty: {page.is_dirty}")
# Check if dirty before rendering again
print(f"2. Check dirty flag: {page.is_dirty}")
if not page.is_dirty:
print(" → Skipping render (no changes)")
print()
# Now make a change
button = page.callbacks.get_by_id("save-btn")
print("3. Setting button to pressed state")
# Ensure page reference is set
if not hasattr(button, '_page') or button._page is None:
button.set_page(page)
button.set_pressed(True)
print(f" → dirty: {page.is_dirty}")
print()
# This time we need to render
print(f"4. Check dirty flag: {page.is_dirty}")
if page.is_dirty:
print(" → Re-rendering (state changed)")
page.render()
print(f" → dirty after render: {page.is_dirty}")
print()
print("Benefit: Only render when actual changes occur!")
print()
def create_animated_gif():
"""
Create an animated GIF showing the button press sequence.
"""
from PIL import Image
import os
print("=" * 70)
print("Creating Animated GIF")
print("=" * 70)
print()
# Check if the PNG files exist
png_files = [
"demo_07_initial.png",
"demo_07_pressed.png",
"demo_07_released.png"
]
if not all(os.path.exists(f) for f in png_files):
print(" ⚠ PNG files not found, skipping GIF creation")
return
# Load the images
initial = Image.open('demo_07_initial.png')
pressed = Image.open('demo_07_pressed.png')
released = Image.open('demo_07_released.png')
# Create animated GIF showing the button interaction sequence
# Sequence: initial (1000ms) -> pressed (200ms) -> released (500ms) -> loop
frames = [initial, pressed, released]
durations = [1000, 200, 500] # milliseconds per frame
output_path = "docs/images/example_07_button_animation.gif"
# Create docs/images directory if it doesn't exist
os.makedirs("docs/images", exist_ok=True)
# Save as animated GIF
initial.save(
output_path,
save_all=True,
append_images=[pressed, released],
duration=durations,
loop=0 # 0 means loop forever
)
print(f" ✓ Created: {output_path}")
print(f" ✓ Frames: {len(frames)}")
print(f" ✓ Sequence: initial (1000ms) → pressed (200ms) → released (500ms)")
print()
if __name__ == "__main__":
print("\n")
print("" + "" * 68 + "")
print("" + " " * 15 + "PRESSED STATE DEMONSTRATION" + " " * 26 + "")
print("" + "" * 68 + "")
print()
# Run all demos
demo_automatic_interaction()
print("\n")
demo_manual_state_management()
print("\n")
demo_state_manager()
print("\n")
demo_performance_optimization()
print("\n")
# Create animated GIF
create_animated_gif()
print("=" * 70)
print("All demos complete! Check the generated PNG files and animated GIF.")
print("=" * 70)

View File

@ -0,0 +1,227 @@
"""
Demonstration of bundled fonts in pyWebLayout.
This example shows:
1. How to use the bundled DejaVu font families
2. Different font variants (regular, bold, italic, bold-italic)
3. The three font families (Sans, Serif, Monospace)
4. Convenient Font.from_family() method for easy font selection
The demo creates a page showcasing all bundled fonts with different styles.
"""
from pyWebLayout.concrete import Page
from pyWebLayout.abstract import Paragraph, Word
from pyWebLayout.style import Font, FontWeight, FontStyle, BundledFont
from pyWebLayout.style.page_style import PageStyle
from pyWebLayout.layout.document_layouter import DocumentLayouter
def create_font_showcase_page():
"""
Create a page demonstrating all bundled fonts and variants.
"""
# Create page with some padding
page = Page(size=(800, 1000), style=PageStyle(border_width=20))
layouter = DocumentLayouter(page)
# Title
title_font = Font.from_family(
BundledFont.SANS,
font_size=32,
colour=(0, 0, 100),
weight=FontWeight.BOLD
)
title = Paragraph(title_font)
title.add_word(Word("Bundled", title_font))
title.add_word(Word("Fonts", title_font))
title.add_word(Word("Showcase", title_font))
layouter.layout_paragraph(title)
page._current_y_offset += 20
# Introduction
intro_font = Font.from_family(BundledFont.SANS, font_size=14, colour=(50, 50, 50))
intro = Paragraph(intro_font)
intro_text = "pyWebLayout bundles the DejaVu font family with three font types and four variants each."
for word in intro_text.split():
intro.add_word(Word(word, intro_font))
layouter.layout_paragraph(intro)
page._current_y_offset += 25
# --- Sans Serif Section ---
section_font = Font.from_family(
BundledFont.SANS,
font_size=20,
colour=(0, 100, 0),
weight=FontWeight.BOLD
)
sans_section = Paragraph(section_font)
sans_section.add_word(Word("Sans-Serif", section_font))
sans_section.add_word(Word("(DejaVu", section_font))
sans_section.add_word(Word("Sans)", section_font))
layouter.layout_paragraph(sans_section)
page._current_y_offset += 10
# Sans Regular
sans_regular = Font.from_family(BundledFont.SANS, font_size=16)
demo_text_paragraph(layouter, page, sans_regular, "Regular:")
# Sans Bold
sans_bold = Font.from_family(BundledFont.SANS, font_size=16, weight=FontWeight.BOLD)
demo_text_paragraph(layouter, page, sans_bold, "Bold:")
# Sans Italic
sans_italic = Font.from_family(BundledFont.SANS, font_size=16, style=FontStyle.ITALIC)
demo_text_paragraph(layouter, page, sans_italic, "Italic:")
# Sans Bold Italic
sans_bold_italic = Font.from_family(
BundledFont.SANS,
font_size=16,
weight=FontWeight.BOLD,
style=FontStyle.ITALIC
)
demo_text_paragraph(layouter, page, sans_bold_italic, "Bold Italic:")
page._current_y_offset += 20
# --- Serif Section ---
serif_section = Paragraph(section_font)
serif_section.add_word(Word("Serif", section_font))
serif_section.add_word(Word("(DejaVu", section_font))
serif_section.add_word(Word("Serif)", section_font))
layouter.layout_paragraph(serif_section)
page._current_y_offset += 10
# Serif Regular
serif_regular = Font.from_family(BundledFont.SERIF, font_size=16)
demo_text_paragraph(layouter, page, serif_regular, "Regular:")
# Serif Bold
serif_bold = Font.from_family(BundledFont.SERIF, font_size=16, weight=FontWeight.BOLD)
demo_text_paragraph(layouter, page, serif_bold, "Bold:")
# Serif Italic
serif_italic = Font.from_family(BundledFont.SERIF, font_size=16, style=FontStyle.ITALIC)
demo_text_paragraph(layouter, page, serif_italic, "Italic:")
# Serif Bold Italic
serif_bold_italic = Font.from_family(
BundledFont.SERIF,
font_size=16,
weight=FontWeight.BOLD,
style=FontStyle.ITALIC
)
demo_text_paragraph(layouter, page, serif_bold_italic, "Bold Italic:")
page._current_y_offset += 20
# --- Monospace Section ---
mono_section = Paragraph(section_font)
mono_section.add_word(Word("Monospace", section_font))
mono_section.add_word(Word("(DejaVu", section_font))
mono_section.add_word(Word("Sans", section_font))
mono_section.add_word(Word("Mono)", section_font))
layouter.layout_paragraph(mono_section)
page._current_y_offset += 10
# Mono Regular
mono_regular = Font.from_family(BundledFont.MONOSPACE, font_size=14)
demo_code_paragraph(layouter, page, mono_regular, "Regular:")
# Mono Bold
mono_bold = Font.from_family(BundledFont.MONOSPACE, font_size=14, weight=FontWeight.BOLD)
demo_code_paragraph(layouter, page, mono_bold, "Bold:")
# Mono Italic
mono_italic = Font.from_family(BundledFont.MONOSPACE, font_size=14, style=FontStyle.ITALIC)
demo_code_paragraph(layouter, page, mono_italic, "Italic:")
# Mono Bold Italic
mono_bold_italic = Font.from_family(
BundledFont.MONOSPACE,
font_size=14,
weight=FontWeight.BOLD,
style=FontStyle.ITALIC
)
demo_code_paragraph(layouter, page, mono_bold_italic, "Bold Italic:")
page._current_y_offset += 20
# Footer
footer_font = Font.from_family(BundledFont.SANS, font_size=12, colour=(100, 100, 100))
footer = Paragraph(footer_font)
footer_text = "All fonts are free and open source under the Bitstream Vera License."
for word in footer_text.split():
footer.add_word(Word(word, footer_font))
layouter.layout_paragraph(footer)
return page
def demo_text_paragraph(layouter, page, font, label):
"""Create a paragraph showing sample text with the given font."""
# Label in smaller font
label_font = Font.from_family(BundledFont.SANS, font_size=12, colour=(100, 100, 100))
label_para = Paragraph(label_font)
label_para.add_word(Word(label, label_font))
layouter.layout_paragraph(label_para)
page._current_y_offset += 5
# Sample text
para = Paragraph(font)
sample = "The quick brown fox jumps over the lazy dog. 0123456789"
for word in sample.split():
para.add_word(Word(word, font))
layouter.layout_paragraph(para)
page._current_y_offset += 8
def demo_code_paragraph(layouter, page, font, label):
"""Create a paragraph showing sample code with the given font."""
# Label in smaller font
label_font = Font.from_family(BundledFont.SANS, font_size=12, colour=(100, 100, 100))
label_para = Paragraph(label_font)
label_para.add_word(Word(label, label_font))
layouter.layout_paragraph(label_para)
page._current_y_offset += 5
# Sample code
para = Paragraph(font)
code = "def hello(): print('Hello, World!') # 0123456789"
for word in code.split():
para.add_word(Word(word, font))
layouter.layout_paragraph(para)
page._current_y_offset += 8
if __name__ == "__main__":
print("\n")
print("=" * 70)
print("Bundled Fonts Demonstration")
print("=" * 70)
print()
print("Creating font showcase page...")
page = create_font_showcase_page()
print("Rendering page...")
image = page.render()
output_file = "demo_08_bundled_fonts.png"
image.save(output_file)
print(f"Saved: {output_file}")
print()
print("=" * 70)
print("Demo complete!")
print()
print("The page showcases all bundled fonts:")
print(" - DejaVu Sans (Sans-serif)")
print(" - DejaVu Serif (Serif)")
print(" - DejaVu Sans Mono (Monospace)")
print()
print("Each family has 4 variants:")
print(" - Regular")
print(" - Bold")
print(" - Italic")
print(" - Bold Italic")
print("=" * 70)
print()

View File

@ -0,0 +1,367 @@
#!/usr/bin/env python3
"""
Pagination Example with PageBreak
This example demonstrates:
- Using PageBreak to force content onto new pages
- Multi-page document layout with automatic page creation
- Different content types across multiple pages
- Page numbering and document flow
- Combining text, images, and tables across pages
This shows how to create multi-page documents with explicit page breaks.
"""
import sys
from pathlib import Path
from PIL import Image, ImageDraw
# Add pyWebLayout to path
sys.path.insert(0, str(Path(__file__).parent.parent))
from pyWebLayout.concrete.page import Page
from pyWebLayout.style.page_style import PageStyle
from pyWebLayout.style.fonts import Font
from pyWebLayout.abstract.inline import Word
from pyWebLayout.abstract.block import Paragraph, PageBreak, Image as AbstractImage
from pyWebLayout.layout.document_layouter import DocumentLayouter
def create_sample_paragraph(text: str, font_size: int = 14) -> Paragraph:
"""Create a paragraph from plain text."""
font = Font(font_size=font_size, colour=(50, 50, 50))
paragraph = Paragraph(style=font)
for word in text.split():
paragraph.add_word(Word(word, font))
return paragraph
def create_title_paragraph(text: str) -> Paragraph:
"""Create a title paragraph with larger font."""
font = Font(font_size=24, colour=(0, 0, 100), weight='bold')
paragraph = Paragraph(style=font)
for word in text.split():
paragraph.add_word(Word(word, font))
return paragraph
def create_heading_paragraph(text: str) -> Paragraph:
"""Create a heading paragraph."""
font = Font(font_size=18, colour=(50, 50, 100), weight='bold')
paragraph = Paragraph(style=font)
for word in text.split():
paragraph.add_word(Word(word, font))
return paragraph
def create_placeholder_image(width: int, height: int, label: str) -> AbstractImage:
"""Create a placeholder image for demonstration."""
img = Image.new('RGB', (width, height), (200, 220, 240))
draw = ImageDraw.Draw(img)
# Draw border
draw.rectangle([0, 0, width-1, height-1], outline=(100, 120, 140), width=2)
# Add label
text_bbox = draw.textbbox((0, 0), label)
text_width = text_bbox[2] - text_bbox[0]
text_height = text_bbox[3] - text_bbox[1]
text_x = (width - text_width) // 2
text_y = (height - text_height) // 2
draw.text((text_x, text_y), label, fill=(80, 80, 120))
return AbstractImage(source=img)
def create_example_document_with_pagebreaks():
"""
Example: Multi-page document with explicit page breaks.
This demonstrates how PageBreak forces content onto new pages.
"""
print("\n Creating multi-page document with PageBreaks...")
# Define common page style
page_style = PageStyle(
border_width=2,
border_color=(100, 100, 150),
padding=(30, 40, 30, 40),
background_color=(255, 255, 255),
line_spacing=6
)
# Create document content with page breaks
content = [
# Page 1: Title and Introduction
create_title_paragraph("Multi-Page Document Example"),
create_sample_paragraph(
"This document demonstrates how to use PageBreak elements to control "
"document pagination. Each PageBreak forces subsequent content to start "
"on a new page, allowing you to structure multi-page documents precisely."
),
create_sample_paragraph(
"Page breaks are particularly useful for creating chapters, sections, or "
"ensuring that important content starts at the top of a fresh page rather "
"than being split across page boundaries."
),
# Force page break - next content will be on page 2
PageBreak(),
# Page 2: First Section
create_heading_paragraph("Section 1: Text Content"),
create_sample_paragraph(
"This is the second page of our document. It starts with a clean break "
"from the previous page, ensuring the section heading appears at the top."
),
create_sample_paragraph(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod "
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
"veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
"commodo consequat."
),
create_sample_paragraph(
"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum "
"dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non "
"proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
),
# Another page break
PageBreak(),
# Page 3: Images
create_heading_paragraph("Section 2: Visual Content"),
create_sample_paragraph(
"This page contains image content, demonstrating that page breaks work "
"correctly with different content types."
),
create_placeholder_image(300, 200, "Figure 1: Sample Image"),
create_sample_paragraph("The image above is placed on this dedicated page."),
# Final page break
PageBreak(),
# Page 4: Conclusion
create_heading_paragraph("Conclusion"),
create_sample_paragraph(
"This final page demonstrates that you can create complex multi-page "
"documents by strategically placing PageBreak elements in your content."
),
create_sample_paragraph(
"Key benefits of using PageBreak: 1) Control where pages start, "
"2) Prevent awkward content splits, 3) Create professional-looking "
"documents with proper sectioning, 4) Ensure important content gets "
"visual prominence at page tops."
),
create_sample_paragraph(
"Thank you for reviewing this pagination example. Try experimenting "
"with PageBreak placement to create your own multi-page documents!"
),
]
# Layout the document across multiple pages
pages = []
current_page = Page(size=(600, 800), style=page_style)
layouter = DocumentLayouter(current_page)
for element in content:
if isinstance(element, PageBreak):
# Save current page and create a new one
pages.append(current_page)
current_page = Page(size=(600, 800), style=page_style)
layouter = DocumentLayouter(current_page)
elif isinstance(element, Paragraph):
success, _, _ = layouter.layout_paragraph(element)
if not success:
# Page is full, create new page and retry
pages.append(current_page)
current_page = Page(size=(600, 800), style=page_style)
layouter = DocumentLayouter(current_page)
success, _, _ = layouter.layout_paragraph(element)
if not success:
print(" WARNING: Content too large for page")
elif isinstance(element, AbstractImage):
success = layouter.layout_image(element)
if not success:
# Image doesn't fit, try on new page
pages.append(current_page)
current_page = Page(size=(600, 800), style=page_style)
layouter = DocumentLayouter(current_page)
success = layouter.layout_image(element)
if not success:
print(" WARNING: Image too large for page")
# Add the final page
pages.append(current_page)
print(f" Created {len(pages)} pages")
return pages
def create_auto_pagination_example():
"""
Example: Document that automatically flows to multiple pages.
This shows the difference between automatic pagination (when content
doesn't fit) vs explicit PageBreak usage.
"""
print("\n Creating auto-paginated document (no explicit breaks)...")
page_style = PageStyle(
border_width=1,
border_color=(150, 150, 150),
padding=(20, 30, 20, 30),
background_color=(250, 250, 250),
line_spacing=5
)
# Create lots of content that will naturally overflow
content = [
create_heading_paragraph("Auto-Pagination Example"),
create_sample_paragraph(
"This document does NOT use PageBreak. Instead, it demonstrates how "
"content automatically flows to new pages when the current page is full."
),
]
# Add many paragraphs to force automatic page breaks
for i in range(1, 11):
content.append(
create_sample_paragraph(
f"Paragraph {i}: This is automatically laid out content. "
f"When this paragraph doesn't fit on the current page, the layouter "
f"will create a new page automatically. This is different from using "
f"PageBreak which forces a new page regardless of available space. "
f"Auto-pagination is useful for flowing content naturally."
)
)
# Layout across pages
pages = []
current_page = Page(size=(500, 600), style=page_style)
layouter = DocumentLayouter(current_page)
for element in content:
if isinstance(element, Paragraph):
success, _, _ = layouter.layout_paragraph(element)
if not success:
# Auto page break - content didn't fit
pages.append(current_page)
current_page = Page(size=(500, 600), style=page_style)
layouter = DocumentLayouter(current_page)
layouter.layout_paragraph(element)
pages.append(current_page)
print(f" Auto-created {len(pages)} pages")
return pages
def add_page_numbers(pages, start_number: int = 1):
"""Add page numbers to rendered pages."""
numbered_pages = []
font = Font(font_size=10, colour=(100, 100, 100))
for i, page in enumerate(pages, start=start_number):
# Render the page
img = page.render()
draw = ImageDraw.Draw(img)
# Add page number at bottom center
page_text = f"Page {i}"
bbox = draw.textbbox((0, 0), page_text)
text_width = bbox[2] - bbox[0]
x = (img.size[0] - text_width) // 2
y = img.size[1] - 20
draw.text((x, y), page_text, fill=(100, 100, 100))
numbered_pages.append(img)
return numbered_pages
def combine_pages_vertically(pages, title: str = ""):
"""Combine multiple pages into a vertical strip."""
if not pages:
return None
padding = 20
title_height = 40 if title else 0
# Calculate dimensions
page_width = pages[0].size[0]
page_height = pages[0].size[1]
total_width = page_width + 2 * padding
total_height = len(pages) * (page_height + padding) + padding + title_height
# Create combined image
combined = Image.new('RGB', (total_width, total_height), (240, 240, 240))
draw = ImageDraw.Draw(combined)
# Draw title if provided
if title:
from PIL import ImageFont
try:
title_font = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 16
)
except:
title_font = ImageFont.load_default()
bbox = draw.textbbox((0, 0), title, font=title_font)
text_width = bbox[2] - bbox[0]
title_x = (total_width - text_width) // 2
draw.text((title_x, 10), title, fill=(50, 50, 50), font=title_font)
# Place pages vertically
y_offset = title_height + padding
for page_img in pages:
combined.paste(page_img, (padding, y_offset))
y_offset += page_height + padding
return combined
def main():
"""Demonstrate pagination with PageBreak."""
print("Pagination Example with PageBreak")
print("=" * 50)
# Example 1: Explicit page breaks
pages1 = create_example_document_with_pagebreaks()
rendered_pages1 = add_page_numbers(pages1)
combined1 = combine_pages_vertically(
rendered_pages1,
"Example 1: Explicit PageBreak Usage"
)
# Example 2: Auto pagination
pages2 = create_auto_pagination_example()
rendered_pages2 = add_page_numbers(pages2)
combined2 = combine_pages_vertically(
rendered_pages2,
"Example 2: Automatic Pagination"
)
# Save outputs
output_dir = Path("docs/images")
output_dir.mkdir(parents=True, exist_ok=True)
output_path1 = output_dir / "example_08_pagination_explicit.png"
output_path2 = output_dir / "example_08_pagination_auto.png"
combined1.save(output_path1)
combined2.save(output_path2)
print("\n✓ Example completed!")
print(f" Output 1 saved to: {output_path1}")
print(f" - {len(pages1)} pages with explicit PageBreaks")
print(f" Output 2 saved to: {output_path2}")
print(f" - {len(pages2)} pages with auto-pagination")
return combined1, combined2
if __name__ == "__main__":
main()

View File

@ -0,0 +1,390 @@
#!/usr/bin/env python3
"""
Link Navigation Example
This example demonstrates:
- Creating clickable links with LinkedWord
- Different link types (INTERNAL, EXTERNAL, API, FUNCTION)
- Link styling with underlines and colors
- Link callbacks and event handling
- Interactive link states (hover, pressed)
- Organizing linked content in paragraphs
This shows how to create interactive documents with hyperlinks.
"""
import sys
from pathlib import Path
from typing import List
# Add pyWebLayout to path
sys.path.insert(0, str(Path(__file__).parent.parent))
from pyWebLayout.concrete.page import Page
from pyWebLayout.style.page_style import PageStyle
from pyWebLayout.style.fonts import Font
from pyWebLayout.abstract.inline import Word, LinkedWord
from pyWebLayout.abstract.functional import LinkType
from pyWebLayout.abstract.block import Paragraph
from pyWebLayout.layout.document_layouter import DocumentLayouter
# Track link clicks for demonstration
link_clicks = []
def link_callback(link_id: str):
"""Callback for link clicks"""
def callback():
link_clicks.append(link_id)
print(f" Link clicked: {link_id}")
return callback
def create_paragraph_with_links(
text_parts: List[tuple],
font_size: int = 14) -> Paragraph:
"""
Create a paragraph with mixed text and links.
Args:
text_parts: List of tuples where each is either:
('text', "word1 word2") for normal text
('link', "word", location, link_type, callback_id)
font_size: Base font size
Returns:
Paragraph with words and links
"""
font = Font(font_size=font_size, colour=(50, 50, 50))
paragraph = Paragraph(style=font)
for part in text_parts:
if part[0] == 'text':
# Add normal words
for word_text in part[1].split():
paragraph.add_word(Word(word_text, font))
elif part[0] == 'link':
# Add linked word
word_text, location, link_type, callback_id = part[1:]
callback = link_callback(callback_id)
linked_word = LinkedWord(
text=word_text,
style=font,
location=location,
link_type=link_type,
callback=callback,
title=f"Click to: {location}"
)
paragraph.add_word(linked_word)
return paragraph
def create_example_1_internal_links():
"""Example 1: Internal navigation links within a document."""
print("\n Creating Example 1: Internal links...")
page_style = PageStyle(
border_width=2,
border_color=(150, 150, 200),
padding=(20, 30, 20, 30),
background_color=(255, 255, 255),
line_spacing=6
)
page = Page(size=(500, 600), style=page_style)
layouter = DocumentLayouter(page)
# Title
title_font = Font(font_size=20, colour=(0, 0, 100), weight='bold')
title = Paragraph(style=title_font)
for word in "Internal Navigation Links".split():
title.add_word(Word(word, title_font))
# Content with internal links
intro = create_paragraph_with_links([
('text', "This document demonstrates"),
('link', "internal", "#section1", LinkType.INTERNAL, "goto_section1"),
('text', "navigation links that jump to different parts of the document."),
])
section1 = create_paragraph_with_links([
('text', "Jump to"),
('link', "Section 2", "#section2", LinkType.INTERNAL, "goto_section2"),
('text', "or"),
('link', "Section 3", "#section3", LinkType.INTERNAL, "goto_section3"),
('text', "within this document."),
])
section2 = create_paragraph_with_links([
('text', "You are in Section 2. Return to"),
('link', "top", "#top", LinkType.INTERNAL, "goto_top"),
('text', "or go to"),
('link', "Section 3", "#section3", LinkType.INTERNAL, "goto_section3_from2"),
])
section3 = create_paragraph_with_links([
('text', "This is Section 3. Go back to"),
('link', "Section 1", "#section1", LinkType.INTERNAL, "goto_section1_from3"),
('text', "or"),
('link', "top", "#top", LinkType.INTERNAL, "goto_top_from3"),
])
# Layout content
layouter.layout_paragraph(title)
layouter.layout_paragraph(intro)
layouter.layout_paragraph(section1)
layouter.layout_paragraph(section2)
layouter.layout_paragraph(section3)
return page
def create_example_2_external_links():
"""Example 2: External links to websites."""
print(" Creating Example 2: External links...")
page_style = PageStyle(
border_width=2,
border_color=(150, 200, 150),
padding=(20, 30, 20, 30),
background_color=(255, 255, 255),
line_spacing=6
)
page = Page(size=(500, 600), style=page_style)
layouter = DocumentLayouter(page)
# Title
title_font = Font(font_size=20, colour=(0, 100, 0), weight='bold')
title = Paragraph(style=title_font)
for word in "External Web Links".split():
title.add_word(Word(word, title_font))
# Content with external links
intro = create_paragraph_with_links([
('text', "Click"),
('link', "here", "https://example.com", LinkType.EXTERNAL, "visit_example"),
('text', "to visit an external website."),
])
resources = create_paragraph_with_links([
('text', "Useful resources:"),
('link', "Documentation", "https://docs.example.com", LinkType.EXTERNAL, "visit_docs"),
('text', "and"),
('link', "GitHub", "https://github.com/example", LinkType.EXTERNAL, "visit_github"),
])
more_links = create_paragraph_with_links([
('text', "Learn more at"),
('link', "Wikipedia", "https://wikipedia.org", LinkType.EXTERNAL, "visit_wiki"),
('text', "or check out"),
('link', "Python.org", "https://python.org", LinkType.EXTERNAL, "visit_python"),
])
# Layout content
layouter.layout_paragraph(title)
layouter.layout_paragraph(intro)
layouter.layout_paragraph(resources)
layouter.layout_paragraph(more_links)
return page
def create_example_3_api_links():
"""Example 3: API links that trigger actions."""
print(" Creating Example 3: API links...")
page_style = PageStyle(
border_width=2,
border_color=(200, 150, 150),
padding=(20, 30, 20, 30),
background_color=(255, 255, 255),
line_spacing=6
)
page = Page(size=(500, 600), style=page_style)
layouter = DocumentLayouter(page)
# Title
title_font = Font(font_size=20, colour=(150, 0, 0), weight='bold')
title = Paragraph(style=title_font)
for word in "API Action Links".split():
title.add_word(Word(word, title_font))
# Content with API links
settings = create_paragraph_with_links([
('text', "Click"),
('link', "Settings", "/api/settings", LinkType.API, "open_settings"),
('text', "to configure the application."),
])
actions = create_paragraph_with_links([
('text', "Actions:"),
('link', "Save", "/api/save", LinkType.API, "save_action"),
('text', "or"),
('link', "Export", "/api/export", LinkType.API, "export_action"),
('text', "your data."),
])
management = create_paragraph_with_links([
('text', "Manage:"),
('link', "Users", "/api/users", LinkType.API, "manage_users"),
('text', "or"),
('link', "Permissions", "/api/permissions", LinkType.API, "manage_perms"),
])
# Layout content
layouter.layout_paragraph(title)
layouter.layout_paragraph(settings)
layouter.layout_paragraph(actions)
layouter.layout_paragraph(management)
return page
def create_example_4_function_links():
"""Example 4: Function links that execute code."""
print(" Creating Example 4: Function links...")
page_style = PageStyle(
border_width=2,
border_color=(150, 200, 200),
padding=(20, 30, 20, 30),
background_color=(255, 255, 255),
line_spacing=6
)
page = Page(size=(500, 600), style=page_style)
layouter = DocumentLayouter(page)
# Title
title_font = Font(font_size=20, colour=(0, 120, 120), weight='bold')
title = Paragraph(style=title_font)
for word in "Function Execution Links".split():
title.add_word(Word(word, title_font))
# Content with function links
intro = create_paragraph_with_links([
('text', "These links execute"),
('link', "functions", "calculate()", LinkType.FUNCTION, "exec_calculate"),
('text', "directly in the application."),
])
calculations = create_paragraph_with_links([
('text', "Run:"),
('link', "analyze()", "analyze()", LinkType.FUNCTION, "exec_analyze"),
('text', "or"),
('link', "process()", "process()", LinkType.FUNCTION, "exec_process"),
])
utilities = create_paragraph_with_links([
('text', "Utilities:"),
('link', "validate()", "validate()", LinkType.FUNCTION, "exec_validate"),
('text', "and"),
('link', "cleanup()", "cleanup()", LinkType.FUNCTION, "exec_cleanup"),
])
# Layout content
layouter.layout_paragraph(title)
layouter.layout_paragraph(intro)
layouter.layout_paragraph(calculations)
layouter.layout_paragraph(utilities)
return page
def combine_pages_into_grid(pages, title):
"""Combine multiple pages into a 2x2 grid."""
from PIL import Image, ImageDraw, ImageFont
print("\n Combining pages into grid...")
# Render all pages
images = [page.render() for page in pages]
# Grid layout
padding = 20
title_height = 40
cols = 2
rows = 2
# Calculate dimensions
img_width = images[0].size[0]
img_height = images[0].size[1]
total_width = cols * img_width + (cols + 1) * padding
total_height = rows * img_height + (rows + 1) * padding + title_height
# Create combined image
combined = Image.new('RGB', (total_width, total_height), (240, 240, 240))
draw = ImageDraw.Draw(combined)
# Draw title
try:
title_font = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 18
)
except:
title_font = ImageFont.load_default()
# Center the title
bbox = draw.textbbox((0, 0), title, font=title_font)
text_width = bbox[2] - bbox[0]
title_x = (total_width - text_width) // 2
draw.text((title_x, 10), title, fill=(50, 50, 50), font=title_font)
# Place pages in grid
y_offset = title_height + padding
for row in range(rows):
x_offset = padding
for col in range(cols):
idx = row * cols + col
if idx < len(images):
combined.paste(images[idx], (x_offset, y_offset))
x_offset += img_width + padding
y_offset += img_height + padding
return combined
def main():
"""Demonstrate link navigation across different link types."""
global link_clicks
link_clicks = []
print("Link Navigation Example")
print("=" * 50)
# Create examples for each link type
pages = [
create_example_1_internal_links(),
create_example_2_external_links(),
create_example_3_api_links(),
create_example_4_function_links()
]
# Combine into demonstration image
combined_image = combine_pages_into_grid(
pages,
"Link Types: Internal | External | API | Function"
)
# Save output
output_dir = Path("docs/images")
output_dir.mkdir(parents=True, exist_ok=True)
output_path = output_dir / "example_09_link_navigation.png"
combined_image.save(output_path)
print("\n✓ Example completed!")
print(f" Output saved to: {output_path}")
print(f" Image size: {combined_image.size[0]}x{combined_image.size[1]} pixels")
print(f" Created {len(pages)} link type examples")
print(f" Total links created: {len(link_clicks)} callbacks registered")
return combined_image, link_clicks
if __name__ == "__main__":
main()

374
examples/10_forms_demo.py Normal file
View File

@ -0,0 +1,374 @@
#!/usr/bin/env python3
"""
Comprehensive Forms Example
This example demonstrates:
- All FormFieldType variations (TEXT, PASSWORD, EMAIL, etc.)
- Form layout with multiple fields
- Field labels and validation
- Form submission callbacks
- Organizing forms on pages
This shows how to create interactive forms with all available field types.
"""
import sys
from pathlib import Path
# Add pyWebLayout to path
sys.path.insert(0, str(Path(__file__).parent.parent))
from pyWebLayout.concrete.page import Page
from pyWebLayout.style.page_style import PageStyle
from pyWebLayout.style.fonts import Font
from pyWebLayout.abstract.functional import Form, FormField, FormFieldType
from pyWebLayout.layout.document_layouter import DocumentLayouter
from PIL import Image, ImageDraw
# Track form submissions
form_submissions = []
def form_submit_callback(form_id: str):
"""Callback for form submissions"""
def callback(data):
form_submissions.append((form_id, data))
print(f" Form submitted: {form_id} with data: {data}")
return callback
def create_example_1_text_fields():
"""Example 1: Text input fields"""
print("\n Creating Example 1: Text input fields...")
page_style = PageStyle(
border_width=2,
border_color=(150, 150, 200),
padding=(20, 30, 20, 30),
background_color=(255, 255, 255)
)
page = Page(size=(500, 600), style=page_style)
layouter = DocumentLayouter(page)
# Create form with text fields
form = Form(form_id="text_form", html_id="text_form", callback=form_submit_callback("text_form"))
# Add various text-based fields
form.add_field(FormField(
name="username",
label="Username",
field_type=FormFieldType.TEXT,
required=True
))
form.add_field(FormField(
name="email",
label="Email Address",
field_type=FormFieldType.EMAIL,
required=True
))
form.add_field(FormField(
name="password",
label="Password",
field_type=FormFieldType.PASSWORD,
required=True
))
form.add_field(FormField(
name="website",
label="Website URL",
field_type=FormFieldType.URL,
required=False
))
form.add_field(FormField(
name="bio",
label="Biography",
field_type=FormFieldType.TEXTAREA,
required=False
))
# Layout the form
font = Font(font_size=12, colour=(50, 50, 50))
success, field_ids = layouter.layout_form(form, font=font)
print(f" Laid out {len(field_ids)} text fields")
return page
def create_example_2_number_fields():
"""Example 2: Number and date/time fields"""
print(" Creating Example 2: Number and date/time fields...")
page_style = PageStyle(
border_width=2,
border_color=(150, 200, 150),
padding=(20, 30, 20, 30),
background_color=(255, 255, 255)
)
page = Page(size=(500, 600), style=page_style)
layouter = DocumentLayouter(page)
# Create form with number/date fields
form = Form(form_id="number_form", html_id="number_form", callback=form_submit_callback("number_form"))
form.add_field(FormField(
name="age",
label="Age",
field_type=FormFieldType.NUMBER,
required=True
))
form.add_field(FormField(
name="birth_date",
label="Birth Date",
field_type=FormFieldType.DATE,
required=True
))
form.add_field(FormField(
name="appointment",
label="Appointment Time",
field_type=FormFieldType.TIME,
required=False
))
form.add_field(FormField(
name="rating",
label="Rating (1-10)",
field_type=FormFieldType.RANGE,
required=False
))
form.add_field(FormField(
name="color",
label="Favorite Color",
field_type=FormFieldType.COLOR,
required=False
))
# Layout the form
font = Font(font_size=12, colour=(50, 50, 50))
success, field_ids = layouter.layout_form(form, font=font)
print(f" Laid out {len(field_ids)} number/date fields")
return page
def create_example_3_selection_fields():
"""Example 3: Checkbox, radio, and select fields"""
print(" Creating Example 3: Selection fields...")
page_style = PageStyle(
border_width=2,
border_color=(200, 150, 150),
padding=(20, 30, 20, 30),
background_color=(255, 255, 255)
)
page = Page(size=(500, 600), style=page_style)
layouter = DocumentLayouter(page)
# Create form with selection fields
form = Form(form_id="selection_form", html_id="selection_form", callback=form_submit_callback("selection_form"))
form.add_field(FormField(
name="newsletter",
label="Subscribe to Newsletter",
field_type=FormFieldType.CHECKBOX,
required=False
))
form.add_field(FormField(
name="terms",
label="Accept Terms and Conditions",
field_type=FormFieldType.CHECKBOX,
required=True
))
form.add_field(FormField(
name="gender",
label="Gender",
field_type=FormFieldType.RADIO,
required=False
))
form.add_field(FormField(
name="country",
label="Country",
field_type=FormFieldType.SELECT,
required=True
))
form.add_field(FormField(
name="hidden_token",
label="", # Hidden fields don't display labels
field_type=FormFieldType.HIDDEN,
required=False
))
# Layout the form
font = Font(font_size=12, colour=(50, 50, 50))
success, field_ids = layouter.layout_form(form, font=font)
print(f" Laid out {len(field_ids)} selection fields")
return page
def create_example_4_complete_form():
"""Example 4: Complete registration form with mixed field types"""
print(" Creating Example 4: Complete registration form...")
page_style = PageStyle(
border_width=2,
border_color=(150, 200, 200),
padding=(20, 30, 20, 30),
background_color=(255, 255, 255)
)
page = Page(size=(500, 700), style=page_style)
layouter = DocumentLayouter(page)
# Create comprehensive registration form
form = Form(form_id="registration_form", html_id="registration_form", callback=form_submit_callback("registration"))
# Personal information
form.add_field(FormField(
name="full_name",
label="Full Name",
field_type=FormFieldType.TEXT,
required=True
))
form.add_field(FormField(
name="email",
label="Email",
field_type=FormFieldType.EMAIL,
required=True
))
form.add_field(FormField(
name="password",
label="Password",
field_type=FormFieldType.PASSWORD,
required=True
))
form.add_field(FormField(
name="age",
label="Age",
field_type=FormFieldType.NUMBER,
required=True
))
# Preferences
form.add_field(FormField(
name="notifications",
label="Enable Notifications",
field_type=FormFieldType.CHECKBOX,
required=False
))
# Layout the form
font = Font(font_size=12, colour=(50, 50, 50))
success, field_ids = layouter.layout_form(form, font=font, field_spacing=15)
print(f" Laid out complete form with {len(field_ids)} fields")
return page
def combine_pages_into_grid(pages, title):
"""Combine multiple pages into a 2x2 grid."""
print("\n Combining pages into grid...")
# Render all pages
images = [page.render() for page in pages]
# Grid layout
padding = 20
title_height = 40
cols = 2
rows = 2
# Calculate dimensions
img_width = images[0].size[0]
img_height = images[0].size[1]
total_width = cols * img_width + (cols + 1) * padding
total_height = rows * img_height + (rows + 1) * padding + title_height
# Create combined image
combined = Image.new('RGB', (total_width, total_height), (240, 240, 240))
draw = ImageDraw.Draw(combined)
# Draw title
from PIL import ImageFont
try:
title_font = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 18
)
except:
title_font = ImageFont.load_default()
bbox = draw.textbbox((0, 0), title, font=title_font)
text_width = bbox[2] - bbox[0]
title_x = (total_width - text_width) // 2
draw.text((title_x, 10), title, fill=(50, 50, 50), font=title_font)
# Place pages in grid
y_offset = title_height + padding
for row in range(rows):
x_offset = padding
for col in range(cols):
idx = row * cols + col
if idx < len(images):
combined.paste(images[idx], (x_offset, y_offset))
x_offset += img_width + padding
y_offset += img_height + padding
return combined
def main():
"""Demonstrate comprehensive form field types."""
global form_submissions
form_submissions = []
print("Comprehensive Forms Example")
print("=" * 50)
# Create examples for different form types
pages = [
create_example_1_text_fields(),
create_example_2_number_fields(),
create_example_3_selection_fields(),
create_example_4_complete_form()
]
# Combine into demonstration image
combined_image = combine_pages_into_grid(
pages,
"Form Field Types: Text | Numbers | Selection | Complete"
)
# Save output
output_dir = Path("docs/images")
output_dir.mkdir(parents=True, exist_ok=True)
output_path = output_dir / "example_10_forms.png"
combined_image.save(output_path)
print("\n✓ Example completed!")
print(f" Output saved to: {output_path}")
print(f" Image size: {combined_image.size[0]}x{combined_image.size[1]} pixels")
print(f" Created {len(pages)} form examples")
print(f" Total form callbacks registered: {len(form_submissions)}")
return combined_image, form_submissions
if __name__ == "__main__":
main()

View File

@ -0,0 +1,240 @@
"""
Demonstration of dynamic font family switching in the ereader.
This example shows how to:
1. Initialize an ereader with content
2. Dynamically switch between different font families (Sans, Serif, Monospace)
3. Maintain reading position across font changes
4. Use the font family API
The ereader manager provides a high-level API for changing fonts on-the-fly
without losing your place in the document.
"""
from pyWebLayout.abstract import Paragraph, Heading, Word
from pyWebLayout.abstract.block import HeadingLevel
from pyWebLayout.style import Font
from pyWebLayout.style.fonts import BundledFont, FontWeight
from pyWebLayout.style.page_style import PageStyle
from pyWebLayout.layout.ereader_manager import create_ereader_manager
from PIL import Image
def create_sample_content():
"""Create sample document content with various text styles"""
blocks = []
# Create a default font for the content
default_font = Font.from_family(BundledFont.SANS, font_size=16)
heading_font = Font.from_family(BundledFont.SANS, font_size=24, weight=FontWeight.BOLD)
# Title
title = Heading(level=HeadingLevel.H1, style=heading_font)
for word in "Font Family Switching Demo".split():
title.add_word(Word(word, heading_font))
blocks.append(title)
# Introduction paragraph
intro_font = Font.from_family(BundledFont.SANS, font_size=16)
intro = Paragraph(intro_font)
intro_text = (
"This demonstration shows how the ereader can dynamically switch between "
"different font families while maintaining your reading position. "
"The three bundled font families (Sans, Serif, and Monospace) can be "
"changed on-the-fly without recreating the document."
)
for word in intro_text.split():
intro.add_word(Word(word, intro_font))
blocks.append(intro)
# Section 1
section1_heading = Heading(level=HeadingLevel.H2, style=heading_font)
for word in "Sans-Serif Font".split():
section1_heading.add_word(Word(word, heading_font))
blocks.append(section1_heading)
para1 = Paragraph(default_font)
text1 = (
"Sans-serif fonts like DejaVu Sans are clean and modern, making them "
"ideal for screen reading. They lack the decorative strokes (serifs) "
"found in traditional typefaces, which can improve legibility on digital displays. "
"Many ereader applications default to sans-serif fonts for this reason."
)
for word in text1.split():
para1.add_word(Word(word, default_font))
blocks.append(para1)
# Section 2
section2_heading = Heading(level=HeadingLevel.H2, style=heading_font)
for word in "Serif Font".split():
section2_heading.add_word(Word(word, heading_font))
blocks.append(section2_heading)
para2 = Paragraph(default_font)
text2 = (
"Serif fonts like DejaVu Serif have small decorative strokes at the ends "
"of letter strokes. These fonts are traditionally used in print media and "
"can give a more formal, classic appearance. Many readers prefer serif fonts "
"for long-form reading as they find them easier on the eyes."
)
for word in text2.split():
para2.add_word(Word(word, default_font))
blocks.append(para2)
# Section 3
section3_heading = Heading(level=HeadingLevel.H2, style=heading_font)
for word in "Monospace Font".split():
section3_heading.add_word(Word(word, heading_font))
blocks.append(section3_heading)
para3 = Paragraph(default_font)
text3 = (
"Monospace fonts like DejaVu Sans Mono have equal spacing between all characters. "
"They are commonly used for displaying code, technical documentation, and typewriter-style "
"text. While less common for general reading, some users prefer the uniform character "
"spacing for certain types of content."
)
for word in text3.split():
para3.add_word(Word(word, default_font))
blocks.append(para3)
# Final paragraph
conclusion = Paragraph(default_font)
conclusion_text = (
"The ability to switch fonts dynamically is a key feature of modern ereaders. "
"It allows readers to customize their reading experience based on personal preference, "
"lighting conditions, and content type. Try switching between the three font families "
"to see which one you prefer for different types of reading."
)
for word in conclusion_text.split():
conclusion.add_word(Word(word, default_font))
blocks.append(conclusion)
return blocks
def render_pages_with_different_fonts(manager, output_prefix="demo_11"):
"""Render the same page with different font families"""
print("\nRendering pages with different font families...")
print("=" * 70)
font_families = [
(None, "Original (Sans)"),
(BundledFont.SERIF, "Serif"),
(BundledFont.MONOSPACE, "Monospace"),
(BundledFont.SANS, "Sans (explicit)")
]
images = []
for font_family, name in font_families:
print(f"\nRendering with {name} font...")
# Switch font family
manager.set_font_family(font_family)
# Get current page
page = manager.get_current_page()
# Render to image
image = page.render()
filename = f"{output_prefix}_{name.lower().replace(' ', '_').replace('(', '').replace(')', '')}.png"
image.save(filename)
print(f" Saved: {filename}")
images.append((name, image))
return images
def demonstrate_font_switching():
"""Main demonstration function"""
print("\n")
print("=" * 70)
print("Font Family Switching Demonstration")
print("=" * 70)
print()
# Create sample content
print("Creating sample document...")
blocks = create_sample_content()
print(f" Created {len(blocks)} blocks")
# Initialize ereader manager
print("\nInitializing ereader manager...")
page_size = (600, 800)
manager = create_ereader_manager(
blocks,
page_size,
document_id="font_switching_demo"
)
print(f" Page size: {page_size[0]}x{page_size[1]}")
print(f" Initial font family: {manager.get_font_family()}")
# Render pages with different fonts
images = render_pages_with_different_fonts(manager)
# Show position info
print("\nPosition information after font switches:")
print(" " + "-" * 66)
pos_info = manager.get_position_info()
print(f" Current position: Block {pos_info['position']['block_index']}, "
f"Word {pos_info['position']['word_index']}")
print(f" Font family: {pos_info['font_family'] or 'Original'}")
print(f" Font scale: {pos_info['font_scale']}")
print(f" Reading progress: {pos_info['progress']:.1%}")
# Test navigation with font switching
print("\nTesting navigation with font switching...")
print(" " + "-" * 66)
# Reset to beginning
manager.jump_to_position(manager.current_position.__class__())
# Advance a few pages with serif font
manager.set_font_family(BundledFont.SERIF)
print(f" Switched to SERIF font")
for i in range(3):
next_page = manager.next_page()
if next_page:
print(f" Page {i+2}: Advanced successfully")
# Switch to monospace
manager.set_font_family(BundledFont.MONOSPACE)
print(f" Switched to MONOSPACE font")
current_page = manager.get_current_page()
print(f" Re-rendered current page with new font")
# Go back a page
prev_page = manager.previous_page()
if prev_page:
print(f" Navigated back successfully")
# Cache statistics
print("\nCache statistics:")
print(" " + "-" * 66)
stats = manager.get_cache_stats()
for key, value in stats.items():
print(f" {key}: {value}")
print()
print("=" * 70)
print("Demo complete!")
print()
print("Key features demonstrated:")
print(" ✓ Dynamic font family switching (Sans, Serif, Monospace)")
print(" ✓ Position preservation across font changes")
print(" ✓ Automatic cache invalidation on font change")
print(" ✓ Navigation with different fonts")
print(" ✓ Font family info in position tracking")
print()
print("The rendered pages show the same content in different font families.")
print("Notice how the layout adapts while maintaining readability.")
print("=" * 70)
print()
if __name__ == "__main__":
demonstrate_font_switching()

View File

@ -0,0 +1,312 @@
#!/usr/bin/env python3
"""
Table Text Wrapping Example
This example demonstrates the line wrapping functionality in table cells:
- Tables with long text that wraps across multiple lines
- Automatic word wrapping within cell boundaries
- Hyphenation support for long words
- Multiple paragraphs per cell
- Comparison of narrow vs. wide columns
Shows how the Line-based text layout system handles text overflow in tables.
"""
from pyWebLayout.io.readers.html_extraction import parse_html_string
from pyWebLayout.layout.document_layouter import DocumentLayouter
from pyWebLayout.style.page_style import PageStyle
from pyWebLayout.concrete.table import TableStyle
from pyWebLayout.concrete.page import Page
import sys
from pathlib import Path
from PIL import Image
# Add pyWebLayout to path
sys.path.insert(0, str(Path(__file__).parent.parent))
def create_narrow_columns_example():
"""Create a table with narrow columns to show aggressive wrapping."""
print(" - Narrow columns with text wrapping")
html = """
<table>
<thead>
<tr>
<th>Feature</th>
<th>Description</th>
<th>Benefits</th>
</tr>
</thead>
<tbody>
<tr>
<td>Automatic Line Wrapping</td>
<td>Text automatically wraps to fit within the available cell width, creating multiple lines as needed.</td>
<td>Improves readability and prevents horizontal overflow in tables.</td>
</tr>
<tr>
<td>Hyphenation Support</td>
<td>Long words are intelligently hyphenated using pyphen library or brute-force splitting when necessary.</td>
<td>Handles extraordinarily long words that wouldn't fit on a single line.</td>
</tr>
<tr>
<td>Multi-paragraph Cells</td>
<td>Each cell can contain multiple paragraphs or headings, all properly wrapped.</td>
<td>Allows rich content within table cells.</td>
</tr>
</tbody>
</table>
"""
return html, "Text Wrapping in Narrow Columns"
def create_mixed_content_example():
"""Create a table with both short and long content."""
print(" - Mixed content lengths")
html = """
<table>
<caption>Product Comparison</caption>
<thead>
<tr>
<th>Product</th>
<th>Short Description</th>
<th>Detailed Features</th>
</tr>
</thead>
<tbody>
<tr>
<td>Widget Pro</td>
<td>Premium</td>
<td>Advanced functionality with enterprise-grade reliability, comprehensive warranty coverage, and dedicated customer support available around the clock.</td>
</tr>
<tr>
<td>Widget Lite</td>
<td>Basic</td>
<td>Essential features for everyday use with straightforward operation and minimal learning curve.</td>
</tr>
<tr>
<td>Widget Max</td>
<td>Ultimate</td>
<td>Everything from Widget Pro plus additional customization options, API integration capabilities, and advanced analytics dashboard.</td>
</tr>
</tbody>
</table>
"""
return html, "Mixed Short and Long Content"
def create_technical_documentation_example():
"""Create a table like technical documentation."""
print(" - Technical documentation style")
html = """
<table>
<thead>
<tr>
<th>API Method</th>
<th>Parameters</th>
<th>Description</th>
<th>Return Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>render_table()</td>
<td>table, origin, width, draw, style</td>
<td>Renders a table with automatic text wrapping in cells. Uses the Line class for intelligent word placement and hyphenation.</td>
<td>Rendered table with calculated height and width properties.</td>
</tr>
<tr>
<td>add_word()</td>
<td>word, pretext</td>
<td>Attempts to add a word to the current line. If it doesn't fit, tries hyphenation strategies including pyphen and brute-force splitting.</td>
<td>Tuple of (success, overflow_text) indicating whether word was added and any remaining text.</td>
</tr>
<tr>
<td>calculate_spacing()</td>
<td>text_objects, width, min_spacing, max_spacing</td>
<td>Determines optimal spacing between words to achieve proper justification within the specified constraints.</td>
<td>Calculated spacing value and position offset for alignment.</td>
</tr>
</tbody>
</table>
"""
return html, "Technical Documentation Table"
def create_news_article_example():
"""Create a table with article-style content."""
print(" - News article layout")
html = """
<table>
<thead>
<tr>
<th>Date</th>
<th>Headline</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
<tr>
<td>2024-01-15</td>
<td>New Text Wrapping Feature</td>
<td>PyWebLayout now supports automatic line wrapping in table cells, bringing sophisticated text layout capabilities to table rendering. The implementation leverages the existing Line class infrastructure.</td>
</tr>
<tr>
<td>2024-01-10</td>
<td>Hyphenation Improvements</td>
<td>Enhanced hyphenation algorithms now include both dictionary-based pyphen hyphenation and intelligent brute-force splitting for edge cases.</td>
</tr>
<tr>
<td>2024-01-05</td>
<td>Performance Optimization</td>
<td>Table rendering performance improved through better caching and reduced font object creation overhead.</td>
</tr>
</tbody>
</table>
"""
return html, "News Article Layout"
def render_table_example(html, title, style_variant=0):
"""Render a single table example."""
from pyWebLayout.style import Font
from pyWebLayout.abstract.block import Table
# Parse HTML
base_font = Font(font_size=12)
blocks = parse_html_string(html, base_font=base_font)
# Find the table block
table = None
for block in blocks:
if isinstance(block, Table):
table = block
break
if not table:
print(f" Warning: No table found in {title}")
return None
# Create page style
page_style = PageStyle(
padding=(20, 20, 20, 20),
background_color=(255, 255, 255)
)
# Create page
page_size = (900, 600)
page = Page(size=page_size, style=page_style)
# Create table style variants
table_styles = [
# Default style
TableStyle(
border_width=1,
border_color=(0, 0, 0),
cell_padding=(8, 8, 8, 8),
header_bg_color=(240, 240, 240),
cell_bg_color=(255, 255, 255)
),
# Blue header style
TableStyle(
border_width=2,
border_color=(70, 130, 180),
cell_padding=(10, 10, 10, 10),
header_bg_color=(176, 196, 222),
cell_bg_color=(245, 250, 255)
),
# Minimal style
TableStyle(
border_width=1,
border_color=(200, 200, 200),
cell_padding=(6, 6, 6, 6),
header_bg_color=(250, 250, 250),
cell_bg_color=(255, 255, 255)
),
]
table_style = table_styles[style_variant % len(table_styles)]
# Create layouter and render table
layouter = DocumentLayouter(page)
layouter.layout_table(table, style=table_style)
# Get the rendered canvas
_ = page.draw # Ensure canvas exists
img = page._canvas
return img
def combine_examples(examples):
"""Combine multiple example images into one."""
images = []
titles = []
for html, title in examples:
img = render_table_example(html, title)
if img:
images.append(img)
titles.append(title)
if not images:
return None
# Calculate combined image size
max_width = max(img.width for img in images)
total_height = sum(img.height for img in images) + 40 * len(images) # Extra space between images
# Create combined image
combined = Image.new('RGB', (max_width, total_height), color=(255, 255, 255))
# Paste images
y_offset = 20
for img in images:
combined.paste(img, (0, y_offset))
y_offset += img.height + 40
return combined
def main():
"""Run the table text wrapping example."""
print("\nTable Text Wrapping Example")
print("=" * 50)
# Create examples
print("\n Creating table examples...")
examples = [
create_narrow_columns_example(),
create_mixed_content_example(),
create_technical_documentation_example(),
create_news_article_example(),
]
print("\n Rendering table examples...")
combined_image = combine_examples(examples)
if combined_image:
# Save the output
output_dir = Path(__file__).parent.parent / 'docs' / 'images'
output_dir.mkdir(parents=True, exist_ok=True)
output_path = output_dir / 'example_11_table_text_wrapping.png'
combined_image.save(str(output_path))
print("\n✓ Example completed!")
print(f" Output saved to: {output_path}")
print(f" Image size: {combined_image.width}x{combined_image.height} pixels")
print(f" Created {len(examples)} table examples with text wrapping")
else:
print("\n✗ Failed to generate examples")
if __name__ == '__main__':
main()

View File

@ -0,0 +1,121 @@
#!/usr/bin/env python3
"""
Simple Table Text Wrapping Example
A minimal example showing text wrapping in table cells.
Perfect for quick testing and demonstration.
"""
import sys
from pathlib import Path
# Add pyWebLayout to path
sys.path.insert(0, str(Path(__file__).parent.parent))
from pyWebLayout.io.readers.html_extraction import parse_html_string
from pyWebLayout.layout.document_layouter import DocumentLayouter
from pyWebLayout.style.page_style import PageStyle
from pyWebLayout.style import Font
from pyWebLayout.concrete.table import TableStyle
from pyWebLayout.concrete.page import Page
from pyWebLayout.abstract.block import Table
def main():
"""Create a simple table with text wrapping."""
print("\nSimple Table Text Wrapping Example")
print("=" * 50)
# HTML with a table containing long text
html = """
<table>
<caption>Text Wrapping Demonstration</caption>
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>This is a cell with quite a lot of text that will need to wrap across multiple lines.</td>
<td>Short text</td>
<td>Another cell with enough content to demonstrate the automatic line wrapping functionality.</td>
</tr>
<tr>
<td>Cell A</td>
<td>This middle cell contains a paragraph with several words that should wrap nicely within the available space.</td>
<td>Cell C</td>
</tr>
<tr>
<td>Words like supercalifragilisticexpialidocious might need hyphenation.</td>
<td>Normal text</td>
<td>The wrapping algorithm handles both regular word wrapping and hyphenation seamlessly.</td>
</tr>
</tbody>
</table>
"""
print("\n Parsing HTML and creating table...")
# Parse HTML
base_font = Font(font_size=12)
blocks = parse_html_string(html, base_font=base_font)
# Find table
table = None
for block in blocks:
if isinstance(block, Table):
table = block
break
if not table:
print(" ✗ No table found!")
return
print(" ✓ Table parsed successfully")
# Create page
page_style = PageStyle(
padding=(30, 30, 30, 30),
background_color=(255, 255, 255)
)
page = Page(size=(800, 600), style=page_style)
# Create table style
table_style = TableStyle(
border_width=2,
border_color=(70, 130, 180),
cell_padding=(10, 10, 10, 10),
header_bg_color=(176, 196, 222),
cell_bg_color=(245, 250, 255)
)
print(" Rendering table with text wrapping...")
# Layout and render
layouter = DocumentLayouter(page)
layouter.layout_table(table, style=table_style)
# Get rendered image
_ = page.draw
img = page._canvas
# Save output
output_path = Path(__file__).parent.parent / 'docs' / 'images' / 'example_11b_simple_wrapping.png'
output_path.parent.mkdir(parents=True, exist_ok=True)
img.save(str(output_path))
print(f"\n✓ Example completed!")
print(f" Output saved to: {output_path}")
print(f" Image size: {img.width}x{img.height} pixels")
print(f"\n The table demonstrates:")
print(f" • Automatic line wrapping in cells")
print(f" • Proper word spacing and alignment")
print(f" • Hyphenation for very long words")
print(f" • Multi-line text within cell boundaries")
if __name__ == '__main__':
main()

View File

@ -0,0 +1,254 @@
#!/usr/bin/env python3
"""
Demo: Optimized Table Column Width Layout
This example demonstrates the intelligent table column width optimization:
- Automatic width distribution based on content
- HTML width overrides (fixed column widths)
- Sampling for performance (large tables)
- Comparison: before (equal distribution) vs after (optimized)
The optimizer:
1. Samples first ~5 rows from each section
2. Measures minimum and preferred widths for each column
3. Distributes available space proportionally
4. Respects HTML width attributes
"""
from pyWebLayout.concrete.page import Page
from pyWebLayout.concrete.table import TableRenderer, TableStyle
from pyWebLayout.style.page_style import PageStyle
from pyWebLayout.style import Font
from pyWebLayout.abstract.block import Table, TableRow, TableCell, Paragraph
from pyWebLayout.abstract.inline import Word
from PIL import ImageDraw
def create_demo_table_1():
"""Create a table with varying content lengths (shows optimization)."""
table = Table()
table.caption = "Example 1: Optimized Width Distribution"
font = Font(font_size=11)
# Header
header_row = TableRow()
for text in ["ID", "Name", "Description"]:
cell = TableCell(is_header=True)
para = Paragraph(font)
para.add_word(Word(text, font))
cell.add_block(para)
header_row.add_cell(cell)
table.add_row(header_row, section="header")
# Body rows with varying content lengths
data = [
("1", "Alice", "Short description"),
("2", "Bob", "This is a much longer description that demonstrates how the optimizer allocates more space to columns with longer content"),
("3", "Charlie", "Medium length description here"),
("4", "Diana", "Another longer description that shows the column width optimization working effectively for content-heavy cells"),
]
for row_data in data:
row = TableRow()
for text in row_data:
cell = TableCell()
para = Paragraph(font)
for word in text.split():
para.add_word(Word(word, font))
cell.add_block(para)
row.add_cell(cell)
table.add_row(row, section="body")
return table
def create_demo_table_2():
"""Create a table with HTML width overrides."""
table = Table()
table.caption = "Example 2: Fixed Column Widths (HTML override)"
font = Font(font_size=11)
# Header with width attributes
header_row = TableRow()
# Fixed width column
cell1 = TableCell(is_header=True)
cell1.width = "80px" # HTML width override!
para1 = Paragraph(font)
para1.add_word(Word("ID", font))
para1.add_word(Word("(Fixed", font))
para1.add_word(Word("80px)", font))
cell1.add_block(para1)
header_row.add_cell(cell1)
# Auto-width columns
for text in ["Name (Auto)", "Description (Auto)"]:
cell = TableCell(is_header=True)
para = Paragraph(font)
for word in text.split():
para.add_word(Word(word, font))
cell.add_block(para)
header_row.add_cell(cell)
table.add_row(header_row, section="header")
# Body rows
data = [
("1", "Alice", "The first two columns adapt to remaining space"),
("2", "Bob", "ID column stays fixed at 80px width"),
("3", "Charlie", "Name and Description share the remaining width proportionally"),
]
for row_data in data:
row = TableRow()
# First cell also has fixed width
cell = TableCell()
cell.width = "80px"
para = Paragraph(font)
para.add_word(Word(row_data[0], font))
cell.add_block(para)
row.add_cell(cell)
# Other cells auto-width
for text in row_data[1:]:
cell = TableCell()
para = Paragraph(font)
for word in text.split():
para.add_word(Word(word, font))
cell.add_block(para)
row.add_cell(cell)
table.add_row(row, section="body")
return table
def create_demo_table_3():
"""Create a large table (demonstrates sampling)."""
table = Table()
table.caption = "Example 3: Large Table (uses sampling for performance)"
font = Font(font_size=10)
# Header
header_row = TableRow()
for text in ["Index", "Data A", "Data B", "Data C"]:
cell = TableCell(is_header=True)
para = Paragraph(font)
para.add_word(Word(text, font))
cell.add_block(para)
header_row.add_cell(cell)
table.add_row(header_row, section="header")
# Many body rows (only first ~5 will be sampled for measurement)
for i in range(50):
row = TableRow()
# Index
cell = TableCell()
para = Paragraph(font)
para.add_word(Word(str(i + 1), font))
cell.add_block(para)
row.add_cell(cell)
# Data columns with varying content
if i % 3 == 0:
data = ["Short", "Medium length", "Longer content here"]
elif i % 3 == 1:
data = ["Medium", "Short", "Also longer content"]
else:
data = ["Longer text", "Short", "Medium"]
for text in data:
cell = TableCell()
para = Paragraph(font)
for word in text.split():
para.add_word(Word(word, font))
cell.add_block(para)
row.add_cell(cell)
table.add_row(row, section="body")
return table
def main():
# Create page
page_style = PageStyle(
border_width=1,
padding=(20, 20, 20, 20),
background_color=(255, 255, 255)
)
page = Page(size=(800, 2200), style=page_style)
# Get canvas and draw
canvas = page._create_canvas()
page._canvas = canvas
page._draw = ImageDraw.Draw(canvas)
current_y = 30
# Table style
table_style = TableStyle(
border_width=1,
border_color=(100, 100, 100),
cell_padding=(8, 8, 8, 8),
header_bg_color=(220, 230, 240),
cell_bg_color=(255, 255, 255),
alternate_row_color=(248, 248, 248)
)
# Render Example 1: Optimized distribution
table1 = create_demo_table_1()
renderer1 = TableRenderer(
table1,
origin=(20, current_y),
available_width=760,
draw=page._draw,
style=table_style,
canvas=canvas
)
renderer1.render()
current_y += renderer1.height + 40
# Render Example 2: Fixed widths
table2 = create_demo_table_2()
renderer2 = TableRenderer(
table2,
origin=(20, current_y),
available_width=760,
draw=page._draw,
style=table_style,
canvas=canvas
)
renderer2.render()
current_y += renderer2.height + 40
# Render Example 3: Large table with sampling
table3 = create_demo_table_3()
renderer3 = TableRenderer(
table3,
origin=(20, current_y),
available_width=760,
draw=page._draw,
style=table_style,
canvas=canvas
)
renderer3.render()
# Save
output_path = "docs/images/example_12_optimized_table_layout.png"
canvas.save(output_path)
print(f"✓ Optimized table layout demo created!")
print(f" Output: {output_path}")
print(f" Image size: {canvas.size}")
print(f"\nExamples demonstrated:")
print(f" 1. Content-aware width distribution")
print(f" 2. HTML width overrides (80px fixed column)")
print(f" 3. Large table with sampling (50 rows, only ~5 measured)")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,291 @@
#!/usr/bin/env python3
"""
Demo: Table Pagination
This example demonstrates table pagination when content exceeds page height:
- Large table that spans multiple pages
- Automatic row-level pagination (entire rows move to next page)
- Continuation markers ("continued on next page", "continued from previous page")
- Headers repeated on each page
The pagination system:
1. Renders rows sequentially until page height limit reached
2. Moves entire row to next page if it doesn't fit
3. Repeats header row on continuation pages
4. Adds visual markers to show table continues
"""
from pyWebLayout.concrete.page import Page
from pyWebLayout.concrete.table import TableRenderer, TableStyle
from pyWebLayout.style.page_style import PageStyle
from pyWebLayout.style import Font
from pyWebLayout.abstract.block import Table, TableRow, TableCell, Paragraph
from pyWebLayout.abstract.inline import Word
from PIL import Image, ImageDraw
def create_large_table():
"""Create a table with many rows that will require pagination."""
table = Table()
table.caption = "Employee Directory (Paginated)"
font = Font(font_size=11)
# Header
header_row = TableRow()
for text in ["ID", "Name", "Department", "Email", "Phone"]:
cell = TableCell(is_header=True)
para = Paragraph(font)
para.add_word(Word(text, font))
cell.add_block(para)
header_row.add_cell(cell)
table.add_row(header_row, section="header")
# Many body rows (will span multiple pages)
departments = ["Engineering", "Sales", "Marketing", "HR", "Finance", "Operations", "Support"]
for i in range(60):
row = TableRow()
# ID
cell = TableCell()
para = Paragraph(font)
para.add_word(Word(f"EMP{i+1001}", font))
cell.add_block(para)
row.add_cell(cell)
# Name
cell = TableCell()
para = Paragraph(font)
names = ["Alice Johnson", "Bob Smith", "Charlie Brown", "Diana Lee",
"Eve Wilson", "Frank Miller", "Grace Davis", "Henry Taylor"]
para.add_word(Word(names[i % len(names)], font))
cell.add_block(para)
row.add_cell(cell)
# Department
cell = TableCell()
para = Paragraph(font)
para.add_word(Word(departments[i % len(departments)], font))
cell.add_block(para)
row.add_cell(cell)
# Email
cell = TableCell()
para = Paragraph(font)
email = f"{names[i % len(names)].lower().replace(' ', '.')}@company.com"
para.add_word(Word(email, font))
cell.add_block(para)
row.add_cell(cell)
# Phone
cell = TableCell()
para = Paragraph(font)
para.add_word(Word(f"+1-555-{(i*17)%1000:04d}", font))
cell.add_block(para)
row.add_cell(cell)
table.add_row(row, section="body")
return table
def render_table_with_pagination(table, page_size, max_pages=3):
"""
Render a table across multiple pages.
Args:
table: The table to render
page_size: Tuple of (width, height) for each page
max_pages: Maximum number of pages to render
Returns:
List of PIL Images (one per page)
"""
pages = []
page_style = PageStyle(
border_width=1,
padding=(20, 20, 20, 20),
background_color=(255, 255, 255)
)
table_style = TableStyle(
border_width=1,
border_color=(100, 100, 100),
cell_padding=(6, 8, 6, 8),
header_bg_color=(220, 230, 240),
cell_bg_color=(255, 255, 255),
alternate_row_color=(248, 248, 248)
)
# Get all rows
all_rows = list(table.all_rows())
header_rows = [row for section, row in all_rows if section == "header"]
body_rows = [row for section, row in all_rows if section == "body"]
# Calculate header height once
temp_page = Page(size=page_size, style=page_style)
temp_canvas = temp_page._create_canvas()
temp_draw = ImageDraw.Draw(temp_canvas)
# Create temporary table with just header to measure
header_table = Table()
header_table.caption = table.caption
for header_row in header_rows:
header_table.add_row(header_row, section="header")
header_renderer = TableRenderer(
header_table,
origin=(20, 20),
available_width=page_size[0] - 40,
draw=temp_draw,
style=table_style,
canvas=temp_canvas
)
header_height = header_renderer.height
# Available height for body rows
available_body_height = page_size[1] - 60 - header_height # margins + header
# Paginate body rows
current_page_rows = []
current_height = 0
page_num = 0
for i, body_row in enumerate(body_rows):
if page_num >= max_pages:
break
# Estimate row height (simplified - actual would measure each row)
# For this demo, assume ~30px per row
row_height = 35
if current_height + row_height > available_body_height and current_page_rows:
# Render current page
page_canvas = render_page(
table,
header_rows,
current_page_rows,
page_size,
page_style,
table_style,
page_num,
is_last=False
)
pages.append(page_canvas)
# Start new page
page_num += 1
current_page_rows = []
current_height = 0
current_page_rows.append(body_row)
current_height += row_height
# Render final page
if current_page_rows and page_num < max_pages:
page_canvas = render_page(
table,
header_rows,
current_page_rows,
page_size,
page_style,
table_style,
page_num,
is_last=(i == len(body_rows) - 1)
)
pages.append(page_canvas)
return pages
def render_page(table, header_rows, body_rows, page_size, page_style, table_style, page_num, is_last):
"""Render a single page with header and body rows."""
page = Page(size=page_size, style=page_style)
canvas = page._create_canvas()
page._canvas = canvas
page._draw = ImageDraw.Draw(canvas)
# Create table for this page
page_table = Table()
if page_num == 0:
page_table.caption = table.caption
else:
page_table.caption = f"{table.caption} (continued)"
# Add header rows
for header_row in header_rows:
page_table.add_row(header_row, section="header")
# Add body rows for this page
for body_row in body_rows:
page_table.add_row(body_row, section="body")
# Render table
renderer = TableRenderer(
page_table,
origin=(20, 20),
available_width=page_size[0] - 40,
draw=page._draw,
style=table_style,
canvas=canvas
)
renderer.render()
# Add continuation marker at bottom
if not is_last:
font = Font(font_size=10)
y_pos = page_size[1] - 30
page._draw.text(
(page_size[0] // 2 - 100, y_pos),
"(continued on next page)",
fill=(100, 100, 100),
font=font.font
)
# Add page number
page._draw.text(
(page_size[0] // 2 - 20, page_size[1] - 15),
f"Page {page_num + 1}",
fill=(150, 150, 150),
font=Font(font_size=9).font
)
return canvas
def main():
# Create large table
table = create_large_table()
# Render with pagination (3 pages max for demo)
page_size = (900, 700)
pages = render_table_with_pagination(table, page_size, max_pages=3)
# Combine pages side-by-side for visualization
total_width = page_size[0] * len(pages) + (len(pages) - 1) * 20 # 20px spacing
combined = Image.new('RGB', (total_width, page_size[1]), (240, 240, 240))
x_offset = 0
for i, page_canvas in enumerate(pages):
combined.paste(page_canvas, (x_offset, 0))
x_offset += page_size[0] + 20
# Save
output_path = "docs/images/example_13_table_pagination.png"
combined.save(output_path)
print(f"✓ Table pagination demo created!")
print(f" Output: {output_path}")
print(f" Pages rendered: {len(pages)}")
print(f" Image size: {combined.size}")
print(f"\nDemonstrates:")
print(f" - Large table (60 rows) paginated across {len(pages)} pages")
print(f" - Header repeated on each page")
print(f" - Continuation markers")
print(f" - Page numbers")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,312 @@
#!/usr/bin/env python3
"""
Demo: Working Interactive Table with Buttons
This example shows a fully working interactive table where buttons are
actually rendered inside table cells and can handle click events.
This uses a hybrid approach:
1. Tables are rendered normally for structure
2. Buttons are rendered on top at calculated positions
3. Click detection maps coordinates to button callbacks
"""
from pyWebLayout.concrete.page import Page
from pyWebLayout.concrete.table import TableRenderer, TableStyle
from pyWebLayout.concrete.functional import ButtonText
from pyWebLayout.abstract.functional import Button
from pyWebLayout.style.page_style import PageStyle
from pyWebLayout.style import Font
from pyWebLayout.abstract.block import Table, TableRow, TableCell, Paragraph
from pyWebLayout.abstract.inline import Word
from PIL import Image, ImageDraw
import numpy as np
def create_interactive_table():
"""Create a table structure (buttons will be overlaid)."""
table = Table()
table.caption = "User Management with Interactive Buttons"
font = Font(font_size=11)
# Header
header_row = TableRow()
for i, text in enumerate(["ID", "Name", "Email", "Actions"]):
cell = TableCell(is_header=True)
# Set width for Actions column
if text == "Actions":
cell.width = "220px" # Enough for 3 buttons
para = Paragraph(font)
para.add_word(Word(text, font))
cell.add_block(para)
header_row.add_cell(cell)
table.add_row(header_row, section="header")
# Body rows
users = [
("U001", "Alice Johnson", "alice@example.com"),
("U002", "Bob Smith", "bob@example.com"),
("U003", "Charlie Brown", "charlie@example.com"),
]
for user_id, name, email in users:
row = TableRow()
# ID
cell = TableCell()
para = Paragraph(font)
para.add_word(Word(user_id, font))
cell.add_block(para)
row.add_cell(cell)
# Name
cell = TableCell()
para = Paragraph(font)
para.add_word(Word(name, font))
cell.add_block(para)
row.add_cell(cell)
# Email
cell = TableCell()
para = Paragraph(font)
para.add_word(Word(email, font))
cell.add_block(para)
row.add_cell(cell)
# Actions - leave empty for buttons to be overlaid
# Set width hint to ensure space for 3 buttons
cell = TableCell()
cell.width = "220px" # Enough for 3 buttons (3 × 65px + padding)
para = Paragraph(font)
para.add_word(Word("", font)) # Empty placeholder
cell.add_block(para)
row.add_cell(cell)
table.add_row(row, section="body")
return table
def render_buttons_in_table(canvas, draw, table_origin, column_widths, row_heights, users):
"""
Render interactive buttons inside the table cells.
This calculates the exact position of each button based on the table
layout and renders ButtonText objects at those positions.
Args:
canvas: PIL Image canvas
draw: PIL ImageDraw object
table_origin: (x, y) position of table top-left
column_widths: List of column widths
row_heights: Dict with 'header', 'body', 'footer' keys
users: User data for button labels
Returns:
List of (button, bounds) for click detection
"""
button_font = Font(font_size=10)
buttons_with_bounds = []
# Calculate Actions column position (column 3, index 3)
actions_col_x = table_origin[0] + sum(column_widths[:3]) + 3 * 2 # +borders
actions_col_width = column_widths[3]
# Start after caption and header row
# Caption takes 20px + 10px spacing = 30px
caption_height = 30
header_height = row_heights.get("header", 30)
current_y = table_origin[1] + caption_height + header_height + 2 # +caption +header +border
for i, (user_id, name, email) in enumerate(users):
row_height = row_heights.get("body", 30) # All body rows have same height
# Position buttons horizontally in the Actions cell
button_x = actions_col_x + 10 # Padding from cell edge
button_y = current_y + (row_height - 30) // 2 # Center vertically
# Create buttons for this row
# Note: Button callbacks receive click point as first argument
buttons = [
("View", lambda point, uid=user_id: print(f"View {uid}")),
("Edit", lambda point, uid=user_id: print(f"Edit {uid}")),
("Delete", lambda point, uid=user_id: print(f"Delete {uid}"))
]
for label, callback in buttons:
# Create button
abstract_button = Button(label=label, callback=callback)
button_text = ButtonText(
button=abstract_button,
font=button_font,
draw=draw,
padding=(6, 12, 6, 12)
)
# Set position
button_text._origin = np.array([button_x, button_y])
# Render button
button_text.render()
# Store bounds for click detection
button_width = 60 # Approximate
button_height = 25
bounds = (button_x, button_y, button_x + button_width, button_y + button_height)
buttons_with_bounds.append((abstract_button, bounds))
# Move to next button position
button_x += 65
# Move to next row
current_y += row_height + 1 # +border
return buttons_with_bounds
def handle_click(click_pos, buttons_with_bounds):
"""
Handle a click event by checking if it's inside any button bounds.
Args:
click_pos: (x, y) tuple of click position
buttons_with_bounds: List of (button, bounds) tuples
Returns:
True if a button was clicked, False otherwise
"""
click_x, click_y = click_pos
for button, (x1, y1, x2, y2) in buttons_with_bounds:
if x1 <= click_x <= x2 and y1 <= click_y <= y2:
# Click is inside this button!
button.execute(click_pos)
return True
return False
def main():
# Create page
page_size = (900, 500) # Increased height to fit instructions
page_style = PageStyle(
border_width=1,
padding=(20, 20, 20, 20),
background_color=(255, 255, 255)
)
page = Page(size=page_size, style=page_style)
canvas = page._create_canvas()
page._canvas = canvas
page._draw = ImageDraw.Draw(canvas)
# Table style
table_style = TableStyle(
border_width=1,
border_color=(100, 100, 100),
cell_padding=(8, 10, 8, 10),
header_bg_color=(220, 230, 240),
cell_bg_color=(255, 255, 255),
alternate_row_color=(248, 248, 248)
)
# User data
users = [
("U001", "Alice Johnson", "alice@example.com"),
("U002", "Bob Smith", "bob@example.com"),
("U003", "Charlie Brown", "charlie@example.com"),
]
# Create and render table
table = create_interactive_table()
table_origin = (20, 30)
renderer = TableRenderer(
table,
origin=table_origin,
available_width=860,
draw=page._draw,
style=table_style,
canvas=canvas
)
renderer.render()
# Get table dimensions for button positioning
column_widths = renderer._column_widths
row_heights = renderer._row_heights
# Render interactive buttons on top of table
buttons_with_bounds = render_buttons_in_table(
canvas, page._draw, table_origin,
column_widths, row_heights, users
)
# Add instructions (position below the table)
# Calculate actual table height based on rows
header_height = row_heights.get("header", 30)
body_height = row_heights.get("body", 30) * len(users)
actual_table_height = header_height + body_height + (len(users) + 2) * 2 # +borders
inst_font = Font(font_size=12)
y_offset = table_origin[1] + actual_table_height + 50
page._draw.text(
(20, y_offset),
"Interactive Table Demo:",
fill=(50, 50, 50),
font=inst_font.font
)
note_font = Font(font_size=10)
page._draw.text(
(20, y_offset + 25),
"• Buttons are rendered at calculated positions within table cells",
fill=(80, 80, 80),
font=note_font.font
)
page._draw.text(
(20, y_offset + 45),
"• Click detection maps coordinates to button callbacks",
fill=(80, 80, 80),
font=note_font.font
)
page._draw.text(
(20, y_offset + 65),
"• Try simulated clicks below:",
fill=(80, 80, 80),
font=note_font.font
)
# Save
output_path = "docs/images/example_14_interactive_table.png"
canvas.save(output_path)
print(f"✓ Working interactive table demo created!")
print(f" Output: {output_path}")
print(f" Image size: {canvas.size}")
print(f"\nDemonstrating button click detection:")
# Simulate some clicks to demonstrate functionality
actions_col_x = table_origin[0] + sum(column_widths[:3]) + 6
caption_height = 30
header_height = row_heights.get("header", 30)
body_row_height = row_heights.get("body", 30)
# Calculate first body row position (after caption + header + border)
first_row_y = table_origin[1] + caption_height + header_height + 2
test_clicks = [
(100, 100, "Click outside table"),
(actions_col_x + 10, first_row_y + 15, "View button - Alice"),
(actions_col_x + 75, first_row_y + 15, "Edit button - Alice"),
(actions_col_x + 140, first_row_y + 15, "Delete button - Alice"),
(actions_col_x + 10, first_row_y + body_row_height + 17, "View button - Bob"),
]
for x, y, desc in test_clicks:
print(f"\n Click at ({x}, {y}) - {desc}:")
clicked = handle_click((x, y), buttons_with_bounds)
if not clicked:
print(f" No button at this position")
if __name__ == "__main__":
main()

310
examples/README.md Normal file
View File

@ -0,0 +1,310 @@
# PyWebLayout Examples
This directory contains example scripts demonstrating the pyWebLayout library.
## Getting Started Examples
These examples demonstrate the core rendering capabilities of pyWebLayout:
### 01. Simple Page Rendering
**`01_simple_page_rendering.py`** - Introduction to the Page system
```bash
python 01_simple_page_rendering.py
```
Demonstrates:
- Creating pages with different styles
- Setting borders, padding, and backgrounds
- Understanding page layout structure
- Basic rendering to images
![Page Rendering Example](../docs/images/example_01_page_rendering.png)
### 02. Text and Layout
**`02_text_and_layout.py`** - HTML parsing and text rendering
```bash
python 02_text_and_layout.py
```
Demonstrates:
- Parsing HTML content
- Text alignment options
- Font sizes and styles
- Document structure
![Text and Layout Example](../docs/images/example_02_text_and_layout.png)
### 03. Page Layouts
**`03_page_layouts.py`** - Different page configurations
```bash
python 03_page_layouts.py
```
Demonstrates:
- Various page sizes (portrait, landscape, square)
- Different aspect ratios
- Border and padding variations
- Color schemes
![Page Layouts Example](../docs/images/example_03_page_layouts.png)
### 04. Table Rendering
**`04_table_rendering.py`** - HTML table rendering with styling
```bash
python 04_table_rendering.py
```
Demonstrates:
- Rendering HTML tables
- Table headers and body rows
- Cell borders and padding
- Caption support
- Custom table styling
![Table Rendering Example](../docs/images/example_04_table_rendering.png)
### 05. Tables with Images
**`05_html_table_with_images.py`** - Tables containing images and mixed content
```bash
python 05_html_table_with_images.py
```
Demonstrates:
- Creating tables programmatically
- Adding images to table cells
- Book catalog and product showcase tables
- Mixed content (images and text) in cells
- Using cover images from test data
- HTML table parsing with `<img>` tags
![Table with Images Example](../docs/images/example_05_html_table_with_images.png)
### 06. Functional Elements (Interactive)
**`06_functional_elements_demo.py`** - Interactive buttons and forms with callbacks
```bash
python 06_functional_elements_demo.py
```
Demonstrates:
- Creating interactive buttons
- Building forms with multiple field types
- Post-layout callback binding
- CallbackRegistry system for managing interactables
- Accessing application state from callbacks
- Batch callback operations
- Simulating user interactions
![Functional Elements Example](../docs/images/example_06_functional_elements.png)
### 07. Button Pressed States (Interactive)
**`07_pressed_state_demo.py`** - Visual feedback for button interactions
```bash
python 07_pressed_state_demo.py
```
Demonstrates:
- Button pressed/released state management
- Visual feedback timing (150ms press duration)
- Automatic interaction handling with `InteractionHandler`
- Manual state management for custom event loops
- Dirty flag system for optimized re-rendering
- State tracking with `InteractionStateManager`
![Button Pressed State Animation](../docs/images/example_07_button_animation.gif)
*Animated GIF showing button press sequence: initial → pressed → released*
---
## 🆕 New Examples (2024-11)
These examples address critical coverage gaps and demonstrate advanced features:
### 08. Bundled Fonts Showcase
**`08_bundled_fonts_demo.py`** - Demonstration of all bundled fonts
```bash
python 08_bundled_fonts_demo.py
```
Demonstrates:
- DejaVu Sans (Sans-serif)
- DejaVu Serif (Serif)
- DejaVu Sans Mono (Monospace)
- All font variants: Regular, Bold, Italic, Bold Italic
![Bundled Fonts Example](../docs/images/demo_08_bundled_fonts.png)
### 08. Pagination with PageBreak ✅
**`08_pagination_demo.py`** - Multi-page documents with explicit and automatic pagination
```bash
python 08_pagination_demo.py
```
**Test Coverage:** [tests/examples/test_08_pagination_demo.py](../tests/examples/test_08_pagination_demo.py) - 11 tests
Demonstrates:
- Using `PageBreak` to force content onto new pages
- Multi-page document layout with explicit breaks
- Automatic pagination when content overflows
- Page numbering functionality
- Document flow control
- Combining pages into vertical strips
**Coverage Impact:** Fills critical gap - PageBreak layouter had NO examples before this!
![Pagination Example](../docs/images/example_08_pagination_explicit.png)
### 09. Link Navigation (NEW) ✅
**`09_link_navigation_demo.py`** - All link types and interactive navigation
```bash
python 09_link_navigation_demo.py
```
**Test Coverage:** [tests/examples/test_09_link_navigation_demo.py](../tests/examples/test_09_link_navigation_demo.py) - 10 tests
Demonstrates:
- **Internal links** - Document navigation (`#section1`, `#section2`)
- **External links** - Web URLs (`https://example.com`)
- **API links** - API endpoints (`/api/settings`, `/api/save`)
- **Function links** - Direct function calls (`calculate()`, `process()`)
- Link styling (underlined, color-coded by type)
- Link callbacks and interactivity
- Mixed text and link paragraphs
**Coverage Impact:** Comprehensive - All 4 LinkType variations demonstrated!
![Link Navigation Example](../docs/images/example_09_link_navigation.png)
### 10. Comprehensive Forms (NEW) ✅
**`10_forms_demo.py`** - All 14 form field types with validation
```bash
python 10_forms_demo.py
```
**Test Coverage:** [tests/examples/test_10_forms_demo.py](../tests/examples/test_10_forms_demo.py) - 9 tests
Demonstrates all 14 FormFieldType variations:
**Text-Based Fields:**
- TEXT, EMAIL, PASSWORD, URL, TEXTAREA
**Number/Date/Time Fields:**
- NUMBER, DATE, TIME, RANGE, COLOR
**Selection Fields:**
- CHECKBOX, RADIO, SELECT, HIDDEN
**Coverage Impact:** Complete - All 14 field types across 4 practical form examples!
![Comprehensive Forms Example](../docs/images/example_10_forms.png)
### 11. Table Text Wrapping (NEW) ✅
**`11_table_text_wrapping_demo.py`** - Automatic line wrapping in table cells
```bash
python 11_table_text_wrapping_demo.py
```
**Simple Version:** `11b_simple_table_wrapping.py` - Quick demonstration
Demonstrates:
- **Automatic line wrapping** - Text wraps across multiple lines within cells
- **Word hyphenation** - Long words are intelligently hyphenated
- **Narrow columns** - Aggressive wrapping for tight spaces
- **Mixed content** - Both short and long text in the same table
- **Technical documentation** - API reference style tables
- **News layouts** - Article-style table content
**Implementation:** Uses the Line class from `pyWebLayout.concrete.text` with:
- Word-by-word fitting with intelligent spacing
- Pyphen-based dictionary hyphenation
- Brute-force splitting for edge cases
- Proper baseline alignment and metrics
![Table Text Wrapping Example](../docs/images/example_11_table_text_wrapping.png)
---
## Running the Examples
All examples can be run directly from the examples directory:
```bash
cd examples
# Getting Started (01-07)
python 01_simple_page_rendering.py # Page layouts
python 02_text_and_layout.py # Text alignment with justified text
python 03_page_layouts.py # Various page sizes
python 04_table_rendering.py # Table styles
python 05_html_table_with_images.py # HTML tables with images
python 06_functional_elements_demo.py # Interactive buttons and forms
python 07_pressed_state_demo.py # Button pressed states (generates GIF)
# Advanced Features (08-11)
python 08_bundled_fonts_demo.py # Bundled font showcase
python 08_pagination_demo.py # Multi-page documents
python 09_link_navigation_demo.py # All link types
python 10_forms_demo.py # All form field types
python 11_table_text_wrapping_demo.py # Table text wrapping
python 11b_simple_table_wrapping.py # Simple wrapping demo
```
Output images are saved to the `docs/images/` directory.
## Recent Improvements
### ✅ Justified Text Fix (2024-11-10)
Lines using justified alignment now properly fill the entire width by:
- Calculating base spacing and remainder pixels
- Distributing remainder across word gaps to eliminate short lines
- Removing max_spacing constraint for true justification
**Affected examples:** 02, 11, 11b - All text now perfectly justified!
### ✅ Animated Button States (2024-11-10)
Example 07 now automatically generates an animated GIF showing button interactions:
- Initial state (1000ms)
- Pressed state (200ms)
- Released state (500ms)
- Loops continuously
**Output:** `docs/images/example_07_button_animation.gif`
### Running Tests
All new examples (08, 09, 10) include comprehensive test coverage:
```bash
# Run all example tests
python -m pytest tests/examples/ -v
# Run specific test file
python -m pytest tests/examples/test_08_pagination_demo.py -v
python -m pytest tests/examples/test_09_link_navigation_demo.py -v
python -m pytest tests/examples/test_10_forms_demo.py -v
```
**Total Test Coverage:** 30 tests (11 + 10 + 9), all passing ✅
## Additional Documentation
- `README_HTML_MULTIPAGE.md` - HTML multi-page rendering guide
- `../ARCHITECTURE.md` - Detailed explanation of the Abstract/Concrete architecture
- `../docs/images/README.md` - Visual documentation index with all examples
- `../pyWebLayout/layout/README_EREADER_API.md` - EbookReader API reference
## Debug/Development Scripts
Low-level debug and rendering scripts have been moved to the `scripts/` directory.

View File

@ -0,0 +1,252 @@
"""
Generate a demo image for README.md showing font family switching feature.
Creates a side-by-side comparison of the same content rendered in
Sans, Serif, and Monospace fonts.
"""
from pyWebLayout.abstract import Paragraph, Heading, Word
from pyWebLayout.abstract.block import HeadingLevel
from pyWebLayout.style import Font
from pyWebLayout.style.fonts import BundledFont, FontWeight
from pyWebLayout.style.page_style import PageStyle
from pyWebLayout.layout.ereader_manager import create_ereader_manager
from PIL import Image, ImageDraw, ImageFont
def create_demo_content():
"""Create concise demo content that fits nicely on a small page"""
blocks = []
# Title
title_font = Font.from_family(BundledFont.SANS, font_size=28, weight=FontWeight.BOLD)
title = Heading(level=HeadingLevel.H1, style=title_font)
for word in "The Adventure Begins".split():
title.add_word(Word(word, title_font))
blocks.append(title)
# Paragraph
body_font = Font.from_family(BundledFont.SANS, font_size=14)
para = Paragraph(body_font)
text = (
"In the quiet village of Millbrook, young Emma discovered an ancient map "
"hidden in her grandmother's attic. The parchment revealed a mysterious "
"forest path marked with symbols she had never seen before. With courage "
"in her heart and the map in her pocket, she set out at dawn to uncover "
"the secrets that lay beyond the old oak trees."
)
for word in text.split():
para.add_word(Word(word, body_font))
blocks.append(para)
return blocks
def render_with_font_family(blocks, page_size, font_family, family_name):
"""Render a page with a specific font family"""
manager = create_ereader_manager(
blocks,
page_size,
document_id=f"demo_{family_name.lower()}"
)
# Set font family (None means original/default)
manager.set_font_family(font_family)
# Get the first page
page = manager.get_current_page()
return page.render()
def create_comparison_image():
"""Create a side-by-side comparison of all three font families"""
# Page size for each panel
page_width = 400
page_height = 300
# Create demo content
print("Creating demo content...")
blocks = create_demo_content()
# Render with each font family
print("Rendering with Sans font...")
sans_image = render_with_font_family(
blocks, (page_width, page_height), BundledFont.SANS, "Sans"
)
print("Rendering with Serif font...")
serif_image = render_with_font_family(
blocks, (page_width, page_height), BundledFont.SERIF, "Serif"
)
print("Rendering with Monospace font...")
mono_image = render_with_font_family(
blocks, (page_width, page_height), BundledFont.MONOSPACE, "Monospace"
)
# Create a composite image with all three side by side
spacing = 20
label_height = 30
total_width = page_width * 3 + spacing * 4
total_height = page_height + label_height + spacing * 2
composite = Image.new('RGB', (total_width, total_height), color='#f5f5f5')
# Paste the three images
x_positions = [
spacing,
spacing * 2 + page_width,
spacing * 3 + page_width * 2
]
for img, x_pos in zip([sans_image, serif_image, mono_image], x_positions):
composite.paste(img, (x_pos, label_height + spacing))
# Add labels
draw = ImageDraw.Draw(composite)
# Try to use a nice font, fallback to default if not available
try:
label_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 20)
except:
label_font = ImageFont.load_default()
labels = ["Sans-Serif", "Serif", "Monospace"]
for label, x_pos in zip(labels, x_positions):
# Calculate text position to center it
bbox = draw.textbbox((0, 0), label, font=label_font)
text_width = bbox[2] - bbox[0]
text_x = x_pos + (page_width - text_width) // 2
draw.text((text_x, 5), label, fill='#333333', font=label_font)
# Save the image
output_path = "docs/images/font_family_switching.png"
composite.save(output_path, quality=95)
print(f"\n✓ Saved demo image to: {output_path}")
print(f" Image size: {total_width}x{total_height}")
return output_path
def create_single_vertical_comparison():
"""Create a vertical comparison that's better for README"""
# Page size for each panel
page_width = 700
page_height = 280
# Create demo content
print("\nCreating vertical comparison for README...")
blocks = create_demo_content()
# Render with each font family
print(" Rendering Sans...")
sans_image = render_with_font_family(
blocks, (page_width, page_height), BundledFont.SANS, "Sans"
)
print(" Rendering Serif...")
serif_image = render_with_font_family(
blocks, (page_width, page_height), BundledFont.SERIF, "Serif"
)
print(" Rendering Monospace...")
mono_image = render_with_font_family(
blocks, (page_width, page_height), BundledFont.MONOSPACE, "Monospace"
)
# Create a composite image stacked vertically
spacing = 15
label_width = 120
total_width = page_width + label_width + spacing * 2
total_height = page_height * 3 + spacing * 4
composite = Image.new('RGB', (total_width, total_height), color='#ffffff')
# Add a subtle border
draw = ImageDraw.Draw(composite)
draw.rectangle([(0, 0), (total_width-1, total_height-1)], outline='#e0e0e0', width=1)
# Paste the three images vertically
y_positions = [
spacing,
spacing * 2 + page_height,
spacing * 3 + page_height * 2
]
images_data = [
(sans_image, "Sans-Serif", "#4A90E2"),
(serif_image, "Serif", "#E94B3C"),
(mono_image, "Monospace", "#50C878")
]
# Try to use a nice font
try:
label_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 16)
small_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 11)
except:
label_font = ImageFont.load_default()
small_font = ImageFont.load_default()
for (img, label, color), y_pos in zip(images_data, y_positions):
# Paste the page image
composite.paste(img, (label_width + spacing, y_pos))
# Draw label background
draw.rectangle(
[(spacing, y_pos + 10), (label_width, y_pos + 40)],
fill=color
)
# Draw label text
draw.text(
(spacing + 10, y_pos + 17),
label,
fill='#ffffff',
font=label_font
)
# Draw font description
descriptions = {
"Sans-Serif": "Clean & Modern",
"Serif": "Classic & Formal",
"Monospace": "Code & Technical"
}
draw.text(
(spacing + 5, y_pos + 50),
descriptions[label],
fill='#666666',
font=small_font
)
# Save the image
output_path = "docs/images/font_family_switching_vertical.png"
composite.save(output_path, quality=95)
print(f" ✓ Saved: {output_path}")
print(f" Size: {total_width}x{total_height}")
return output_path
if __name__ == "__main__":
print("=" * 70)
print("Generating README Demo Images")
print("=" * 70)
# Create both versions
horizontal_path = create_comparison_image()
vertical_path = create_single_vertical_comparison()
print("\n" + "=" * 70)
print("Demo images generated successfully!")
print("=" * 70)
print(f"\nHorizontal comparison: {horizontal_path}")
print(f"Vertical comparison: {vertical_path}")
print("\nRecommended for README: vertical version")
print("\nMarkdown snippet:")
print("```markdown")
print("![Font Family Switching](docs/images/font_family_switching_vertical.png)")
print("```")
print()

Some files were not shown because too many files have changed in this diff Show More