pyWebLayout/test_monospace_demo.py
Duncan Tourolle d0153c6397
All checks were successful
Python CI / test (push) Successful in 5m17s
Fix tests
2025-06-22 19:26:40 +02:00

251 lines
8.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
Simple demonstration of mono-space font testing concepts.
"""
from pyWebLayout.concrete.text import Text, Line
from pyWebLayout.style.fonts import Font
from pyWebLayout.style.layout import Alignment
def main():
print("=== Mono-space Font Testing Demo ===\n")
# Create a regular font
font = Font(font_size=12)
print("1. Character Width Variance Analysis:")
print("-" * 40)
# Test different characters to show width variance
test_chars = "iIlLmMwW"
widths = {}
for char in test_chars:
text = Text(char, font)
widths[char] = text.width
print(f" '{char}': {text.width:3d}px")
min_w = min(widths.values())
max_w = max(widths.values())
variance = max_w - min_w
print(f"\n Range: {min_w}-{max_w}px (variance: {variance}px)")
print(f" Ratio: {max_w/min_w:.1f}x difference")
print("\n2. Why This Matters for Testing:")
print("-" * 40)
# Show how same-length strings have different widths
word1 = "ill" # narrow
word2 = "WWW" # wide
text1 = Text(word1, font)
text2 = Text(word2, font)
print(f" '{word1}' (3 chars): {text1.width}px")
print(f" '{word2}' (3 chars): {text2.width}px")
print(f" Same length, {abs(text1.width - text2.width)}px difference!")
print("\n3. Line Capacity Prediction:")
print("-" * 40)
line_width = 100
print(f" Line width: {line_width}px")
# Test how many characters fit
test_cases = [
("narrow chars", "i" * 20),
("wide chars", "W" * 10),
("mixed text", "Hello World")
]
for name, text_str in test_cases:
text_obj = Text(text_str, font)
fits = "YES" if text_obj.width <= line_width else "NO"
print(f" {name:12}: '{text_str[:10]}...' ({len(text_str)} chars, {text_obj.width}px) → {fits}")
print("\n4. With Mono-space Fonts:")
print("-" * 40)
# Try to use an actual mono-space font
mono_font = None
mono_paths = [
"/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf",
"/usr/share/fonts/truetype/liberation/LiberationMono-Regular.ttf",
"/System/Library/Fonts/Monaco.ttf",
"C:/Windows/Fonts/consola.ttf"
]
import os
for path in mono_paths:
if os.path.exists(path):
try:
mono_font = Font(font_path=path, font_size=12)
print(f" Using actual mono-space font: {os.path.basename(path)}")
break
except:
continue
if mono_font:
# Test actual mono-space character consistency
mono_test_chars = "iIlLmMwW"
mono_widths = {}
for char in mono_test_chars:
text = Text(char, mono_font)
mono_widths[char] = text.width
mono_min = min(mono_widths.values())
mono_max = max(mono_widths.values())
mono_variance = mono_max - mono_min
print(f" Mono-space character widths:")
for char, width in mono_widths.items():
print(f" '{char}': {width}px")
print(f" Range: {mono_min}-{mono_max}px (variance: {mono_variance}px)")
# Compare to regular font variance
regular_variance = max_w - min_w
improvement = regular_variance / max(1, mono_variance)
print(f" Improvement: {improvement:.1f}x more consistent!")
# Test line capacity with actual mono-space
mono_char_width = mono_widths['M'] # Use actual width
capacity = line_width // mono_char_width
print(f"\n Actual mono-space line capacity:")
print(f" Each character: {mono_char_width}px")
print(f" Line capacity: {capacity} characters")
# Prove consistency with different character combinations
test_strings = [
"i" * capacity,
"W" * capacity,
"M" * capacity,
"l" * capacity
]
print(f" Testing {capacity}-character strings:")
all_same_width = True
first_width = None
for test_str in test_strings:
text_obj = Text(test_str, mono_font)
if first_width is None:
first_width = text_obj.width
elif abs(text_obj.width - first_width) > 2: # Allow 2px tolerance
all_same_width = False
print(f" '{test_str[0]}' × {len(test_str)}: {text_obj.width}px")
if all_same_width:
print(f" ✓ ALL {capacity}-character strings have the same width!")
else:
print(f" ⚠ Some variance detected (font may not be perfectly mono-space)")
else:
print(" No mono-space font found - showing theoretical values:")
mono_char_width = 8 # Typical mono-space width
capacity = line_width // mono_char_width
print(f" Each character: {mono_char_width}px (theoretical)")
print(f" Line capacity: {capacity} characters")
print(f" ANY {capacity}-character string would fit!")
print(f" Layout calculations become simple math")
print("\n5. Line Fitting Test:")
print("-" * 40)
# Test actual line fitting
line = Line(
spacing=(2, 4),
origin=(0, 0),
size=(line_width, 20),
font=font,
halign=Alignment.LEFT
)
test_word = "development" # 11 characters
word_obj = Text(test_word, font)
print(f" Test word: '{test_word}' ({len(test_word)} chars, {word_obj.width}px)")
print(f" Line width: {line_width}px")
result = line.add_word(test_word, font)
if result is None:
print(" Result: Word fits completely")
else:
if line.text_objects:
added = line.text_objects[0].text
print(f" Result: Added '{added}', remaining '{result}'")
else:
print(" Result: Word rejected completely")
# Use actual mono font width if available, otherwise theoretical
if mono_font:
actual_mono_width = mono_widths['M']
print(f"\n With actual mono-space ({actual_mono_width}px/char):")
print(f" Word would be: {len(test_word)} × {actual_mono_width} = {len(test_word) * actual_mono_width}px")
if len(test_word) * actual_mono_width <= line_width:
print(" → Would fit completely")
else:
chars_that_fit = line_width // actual_mono_width
print(f" → Would need breaking after {chars_that_fit} characters")
else:
theoretical_mono_width = 8
print(f"\n With theoretical mono-space ({theoretical_mono_width}px/char):")
print(f" Word would be: {len(test_word)} × {theoretical_mono_width} = {len(test_word) * theoretical_mono_width}px")
if len(test_word) * theoretical_mono_width <= line_width:
print(" → Would fit completely")
else:
chars_that_fit = line_width // theoretical_mono_width
print(f" → Would need breaking after {chars_that_fit} characters")
print("\n=== Conclusion ===")
print("Mono-space fonts make testing predictable because:")
print("- Character width is constant")
print("- Line capacity is calculable")
print("- Word fitting is based on character count")
print("- Layout behavior is deterministic")
# Check if test_output directory exists, if so save a simple visual
import os
if os.path.exists("test_output"):
print(f"\nCreating visual test output...")
# Create a simple line rendering test
from pyWebLayout.concrete.page import Page, Container
page = Page(size=(400, 200))
container = Container(
origin=(0, 0),
size=(380, 180),
direction='vertical',
spacing=5,
padding=(10, 10, 10, 10)
)
# Add title
title = Text("Character Width Variance Demo", font)
container.add_child(title)
# Add test lines showing different characters
for char_type, char in [("Narrow", "i"), ("Wide", "W"), ("Average", "n")]:
line_text = f"{char_type}: {char * 10}"
text_obj = Text(line_text, font)
container.add_child(text_obj)
page.add_child(container)
image = page.render()
output_path = os.path.join("test_output", "monospace_demo.png")
image.save(output_path)
print(f"Visual demo saved to: {output_path}")
if __name__ == "__main__":
main()