pyWebLayout/examples/10_forms_demo.py
2025-11-12 12:03:27 +00:00

375 lines
9.9 KiB
Python

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