McRogueFace/tests/demo/demo_main.py

193 lines
6.2 KiB
Python

#!/usr/bin/env python3
"""
McRogueFace Feature Demo System
Usage:
Headless (screenshots): ./mcrogueface --headless --exec tests/demo/demo_main.py
Interactive: ./mcrogueface tests/demo/demo_main.py
In headless mode, generates screenshots for each feature screen.
In interactive mode, provides a menu to navigate between screens.
"""
import mcrfpy
from mcrfpy import automation
import sys
import os
# Note: Engine runs --exec scripts twice - we use this to our advantage
# First run sets up scenes, second run's timer fires after game loop starts
# Add parent to path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# Import screen modules
from demo.screens.caption_demo import CaptionDemo
from demo.screens.frame_demo import FrameDemo
from demo.screens.primitives_demo import PrimitivesDemo
from demo.screens.grid_demo import GridDemo
from demo.screens.animation_demo import AnimationDemo
from demo.screens.color_demo import ColorDemo
# All demo screens in order
DEMO_SCREENS = [
CaptionDemo,
FrameDemo,
PrimitivesDemo,
GridDemo,
AnimationDemo,
ColorDemo,
]
class DemoRunner:
"""Manages the demo system."""
def __init__(self):
self.screens = []
self.current_index = 0
self.headless = self._detect_headless()
self.screenshot_dir = os.path.join(os.path.dirname(__file__), "screenshots")
def _detect_headless(self):
"""Detect if running in headless mode."""
# Check window resolution - headless mode has a default resolution
try:
win = mcrfpy.Window.get()
# In headless mode, Window.get() still returns an object
# Check if we're in headless by looking for the indicator
return str(win).find("headless") >= 0
except:
return True
def setup_all_screens(self):
"""Initialize all demo screens."""
for i, ScreenClass in enumerate(DEMO_SCREENS):
scene_name = f"demo_{i:02d}_{ScreenClass.name.lower().replace(' ', '_')}"
screen = ScreenClass(scene_name)
screen.setup()
self.screens.append(screen)
def create_menu(self):
"""Create the main menu screen."""
mcrfpy.createScene("menu")
ui = mcrfpy.sceneUI("menu")
# Title
title = mcrfpy.Caption(text="McRogueFace Demo", pos=(400, 30))
title.fill_color = mcrfpy.Color(255, 255, 255)
title.outline = 2
title.outline_color = mcrfpy.Color(0, 0, 0)
ui.append(title)
subtitle = mcrfpy.Caption(text="Feature Showcase", pos=(400, 70))
subtitle.fill_color = mcrfpy.Color(180, 180, 180)
ui.append(subtitle)
# Menu items
for i, screen in enumerate(self.screens):
y = 130 + i * 50
# Button frame
btn = mcrfpy.Frame(pos=(250, y), size=(300, 40))
btn.fill_color = mcrfpy.Color(50, 50, 70)
btn.outline = 1
btn.outline_color = mcrfpy.Color(100, 100, 150)
ui.append(btn)
# Button text
label = mcrfpy.Caption(text=f"{i+1}. {screen.name}", pos=(20, 8))
label.fill_color = mcrfpy.Color(200, 200, 255)
btn.children.append(label)
# Store index for click handler
btn.name = f"menu_{i}"
# Instructions
instr = mcrfpy.Caption(text="Press 1-6 to view demos, ESC to return to menu", pos=(200, 500))
instr.fill_color = mcrfpy.Color(150, 150, 150)
ui.append(instr)
def run_headless(self):
"""Run in headless mode - generate all screenshots."""
print(f"Generating {len(self.screens)} demo screenshots...")
# Ensure screenshot directory exists
os.makedirs(self.screenshot_dir, exist_ok=True)
# Use timer to take screenshots after game loop renders each scene
self.current_index = 0
self.render_wait = 0
def screenshot_cycle(runtime):
if self.render_wait == 0:
# Set scene and wait for render
if self.current_index >= len(self.screens):
print("Done!")
sys.exit(0)
return
screen = self.screens[self.current_index]
mcrfpy.setScene(screen.scene_name)
self.render_wait = 1
elif self.render_wait < 2:
# Wait additional frame
self.render_wait += 1
else:
# Take screenshot
screen = self.screens[self.current_index]
filename = os.path.join(self.screenshot_dir, screen.get_screenshot_name())
automation.screenshot(filename)
print(f" [{self.current_index+1}/{len(self.screens)}] {filename}")
self.current_index += 1
self.render_wait = 0
if self.current_index >= len(self.screens):
print("Done!")
sys.exit(0)
mcrfpy.setTimer("screenshot", screenshot_cycle, 50)
def run_interactive(self):
"""Run in interactive mode with menu."""
self.create_menu()
def handle_key(key, state):
if state != "start":
return
# Number keys 1-9 for direct screen access
if key in [f"Num{n}" for n in "123456789"]:
idx = int(key[-1]) - 1
if idx < len(self.screens):
mcrfpy.setScene(self.screens[idx].scene_name)
# ESC returns to menu
elif key == "Escape":
mcrfpy.setScene("menu")
# Q quits
elif key == "Q":
sys.exit(0)
# Register keyboard handler on menu scene
mcrfpy.setScene("menu")
mcrfpy.keypressScene(handle_key)
# Also register keyboard handler on all demo scenes
for screen in self.screens:
mcrfpy.setScene(screen.scene_name)
mcrfpy.keypressScene(handle_key)
# Start on menu
mcrfpy.setScene("menu")
def main():
"""Main entry point."""
runner = DemoRunner()
runner.setup_all_screens()
if runner.headless:
runner.run_headless()
else:
runner.run_interactive()
# Run when executed
main()