#!/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()