# 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
