pyWebLayout/demo_viewport_system.py
Duncan Tourolle df775ee462
Some checks failed
Python CI / test (push) Has been cancelled
view port based browser and test
2025-06-08 17:00:41 +02:00

225 lines
7.4 KiB
Python

#!/usr/bin/env python3
"""
Demo script showing the viewport system in action.
This demonstrates how the viewport provides a movable window into large content,
enabling efficient scrolling without rendering the entire content at once.
"""
import os
from PIL import Image
from pyWebLayout.concrete import (
Viewport, ScrollablePageContent, Text, Box, RenderableImage
)
from pyWebLayout.style.fonts import Font, FontWeight
from pyWebLayout.style.layout import Alignment
def create_large_document_content():
"""Create a large document to demonstrate viewport scrolling"""
# Create scrollable content container
content = ScrollablePageContent(content_width=800, initial_height=100)
# Add a title
title_font = Font(font_size=24, weight=FontWeight.BOLD)
title = Text("Large Document Demo", title_font)
content.add_child(title)
# Add spacing
content.add_child(Box((0, 0), (1, 20)))
# Add many paragraphs to create a long document
paragraph_font = Font(font_size=14)
for i in range(50):
# Section header
section_font = Font(font_size=18, weight=FontWeight.BOLD)
header = Text(f"Section {i+1}", section_font)
content.add_child(header)
# Add some spacing
content.add_child(Box((0, 0), (1, 10)))
# Add paragraph content
paragraphs = [
f"This is paragraph {i+1}, line 1. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
f"This is paragraph {i+1}, line 2. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
f"This is paragraph {i+1}, line 3. Ut enim ad minim veniam, quis nostrud exercitation ullamco.",
f"This is paragraph {i+1}, line 4. Duis aute irure dolor in reprehenderit in voluptate velit esse.",
f"This is paragraph {i+1}, line 5. Excepteur sint occaecat cupidatat non proident, sunt in culpa."
]
for para_text in paragraphs:
para = Text(para_text, paragraph_font)
content.add_child(para)
content.add_child(Box((0, 0), (1, 5))) # Line spacing
# Add section spacing
content.add_child(Box((0, 0), (1, 15)))
return content
def demo_viewport_rendering():
"""Demonstrate viewport rendering at different scroll positions"""
print("Creating large document content...")
content = create_large_document_content()
print(f"Content size: {content.get_content_height()} pixels tall")
# Create viewport
viewport = Viewport(viewport_size=(800, 600), background_color=(255, 255, 255))
# Add content to viewport
viewport.add_content(content)
print(f"Viewport content size: {viewport.content_size}")
print(f"Max scroll Y: {viewport.max_scroll_y}")
# Create output directory
os.makedirs("output/viewport_demo", exist_ok=True)
# Render viewport at different scroll positions
scroll_positions = [
(0, "top"),
(viewport.max_scroll_y // 4, "quarter"),
(viewport.max_scroll_y // 2, "middle"),
(viewport.max_scroll_y * 3 // 4, "three_quarters"),
(viewport.max_scroll_y, "bottom")
]
for scroll_y, label in scroll_positions:
print(f"Rendering viewport at scroll position {scroll_y} ({label})...")
# Scroll to position
viewport.scroll_to(0, scroll_y)
# Get scroll info
scroll_info = viewport.get_scroll_info()
print(f" Scroll progress: {scroll_info['scroll_progress_y']:.2%}")
print(f" Visible elements: {len(viewport.get_visible_elements())}")
# Render viewport
viewport_img = viewport.render()
# Save image
output_path = f"output/viewport_demo/viewport_{label}.png"
viewport_img.save(output_path)
print(f" Saved: {output_path}")
print("\nViewport demo complete!")
return viewport
def demo_hit_testing():
"""Demonstrate hit testing in the viewport"""
print("\nTesting hit detection...")
# Create simple content for hit testing
content = ScrollablePageContent(content_width=800, initial_height=100)
# Add clickable elements
for i in range(10):
text = Text(f"Clickable text item {i}", Font(font_size=16))
content.add_child(text)
content.add_child(Box((0, 0), (1, 20))) # Spacing
# Create viewport
viewport = Viewport(viewport_size=(800, 300))
viewport.add_content(content)
# Test hit detection at different scroll positions
test_points = [(100, 50), (200, 100), (300, 150)]
for scroll_y in [0, 100, 200]:
viewport.scroll_to(0, scroll_y)
print(f"\nAt scroll position {scroll_y}:")
for point in test_points:
hit_element = viewport.hit_test(point)
if hit_element:
element_text = getattr(hit_element, '_text', 'Unknown element')
print(f" Point {point}: Hit '{element_text}'")
else:
print(f" Point {point}: No element")
def demo_scroll_methods():
"""Demonstrate different scrolling methods"""
print("\nTesting scroll methods...")
# Create content
content = ScrollablePageContent(content_width=800, initial_height=100)
for i in range(20):
text = Text(f"Line {i+1}: This is some sample text for scrolling demo", Font(font_size=14))
content.add_child(text)
content.add_child(Box((0, 0), (1, 5)))
# Create viewport
viewport = Viewport(viewport_size=(800, 200))
viewport.add_content(content)
print(f"Content height: {viewport.content_size[1]}")
print(f"Viewport height: {viewport.viewport_size[1]}")
print(f"Max scroll Y: {viewport.max_scroll_y}")
# Test different scroll methods
print("\nTesting scroll methods:")
# Scroll by lines
print("Scrolling down 5 lines...")
for i in range(5):
viewport.scroll_line_down(20)
print(f" After line {i+1}: offset = {viewport.viewport_offset}")
# Scroll by pages
print("Scrolling down 1 page...")
viewport.scroll_page_down()
print(f" After page down: offset = {viewport.viewport_offset}")
# Scroll to bottom
print("Scrolling to bottom...")
viewport.scroll_to_bottom()
print(f" At bottom: offset = {viewport.viewport_offset}")
# Scroll to top
print("Scrolling to top...")
viewport.scroll_to_top()
print(f" At top: offset = {viewport.viewport_offset}")
def main():
"""Run all viewport demos"""
print("=== Viewport System Demo ===")
# Demo 1: Basic viewport rendering
viewport = demo_viewport_rendering()
# Demo 2: Hit testing
demo_hit_testing()
# Demo 3: Scroll methods
demo_scroll_methods()
print("\n=== Demo Complete ===")
print("Check the output/viewport_demo/ directory for rendered images.")
# Show final scroll info
scroll_info = viewport.get_scroll_info()
print(f"\nFinal viewport state:")
print(f" Content size: {scroll_info['content_size']}")
print(f" Viewport size: {scroll_info['viewport_size']}")
print(f" Current offset: {scroll_info['offset']}")
print(f" Scroll progress: {scroll_info['scroll_progress_y']:.1%}")
print(f" Can scroll up: {scroll_info['can_scroll_up']}")
print(f" Can scroll down: {scroll_info['can_scroll_down']}")
if __name__ == "__main__":
main()