117 lines
3.6 KiB
Python
117 lines
3.6 KiB
Python
"""Base class for geometry demo screens."""
|
|
import mcrfpy
|
|
import sys
|
|
import os
|
|
import math
|
|
|
|
# Add scripts path for geometry module
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..', 'src', 'scripts'))
|
|
from geometry import *
|
|
|
|
# Screen resolution
|
|
SCREEN_WIDTH = 1024
|
|
SCREEN_HEIGHT = 768
|
|
|
|
|
|
def screen_angle_between(p1, p2):
|
|
"""
|
|
Calculate angle from p1 to p2 in screen coordinates.
|
|
In screen coords, Y increases downward, so we negate dy.
|
|
Returns angle in degrees where 0=right, 90=up, 180=left, 270=down.
|
|
"""
|
|
dx = p2[0] - p1[0]
|
|
dy = p1[1] - p2[1] # Negate because screen Y is inverted
|
|
angle = math.degrees(math.atan2(dy, dx))
|
|
if angle < 0:
|
|
angle += 360
|
|
return angle
|
|
|
|
|
|
class GeometryDemoScreen:
|
|
"""Base class for geometry demo screens."""
|
|
|
|
name = "Base Screen"
|
|
description = "Override this description"
|
|
|
|
def __init__(self, scene_name):
|
|
self.scene_name = scene_name
|
|
mcrfpy.createScene(scene_name)
|
|
self.ui = mcrfpy.sceneUI(scene_name)
|
|
self.timers = [] # Track timer names for cleanup
|
|
self._timer_configs = [] # Store timer configs for restart
|
|
|
|
def setup(self):
|
|
"""Override to set up the screen content."""
|
|
pass
|
|
|
|
def cleanup(self):
|
|
"""Clean up timers when leaving screen."""
|
|
for timer_name in self.timers:
|
|
try:
|
|
mcrfpy.delTimer(timer_name)
|
|
except:
|
|
pass
|
|
|
|
def restart_timers(self):
|
|
"""Re-register timers after cleanup."""
|
|
for name, callback, interval in self._timer_configs:
|
|
try:
|
|
mcrfpy.setTimer(name, callback, interval)
|
|
except Exception as e:
|
|
print(f"Timer restart failed: {e}")
|
|
|
|
def get_screenshot_name(self):
|
|
"""Return the screenshot filename for this screen."""
|
|
return f"{self.scene_name}.png"
|
|
|
|
def add_title(self, text, y=10):
|
|
"""Add a title caption centered at top."""
|
|
title = mcrfpy.Caption(text=text, pos=(SCREEN_WIDTH // 2, y))
|
|
title.fill_color = mcrfpy.Color(255, 255, 255)
|
|
title.outline = 2
|
|
title.outline_color = mcrfpy.Color(0, 0, 0)
|
|
self.ui.append(title)
|
|
return title
|
|
|
|
def add_description(self, text, y=50):
|
|
"""Add a description caption."""
|
|
desc = mcrfpy.Caption(text=text, pos=(50, y))
|
|
desc.fill_color = mcrfpy.Color(200, 200, 200)
|
|
self.ui.append(desc)
|
|
return desc
|
|
|
|
def add_label(self, text, x, y, color=(200, 200, 200)):
|
|
"""Add a label caption."""
|
|
label = mcrfpy.Caption(text=text, pos=(x, y))
|
|
label.fill_color = mcrfpy.Color(*color)
|
|
self.ui.append(label)
|
|
return label
|
|
|
|
def create_grid(self, grid_size, pos, size, cell_size=16):
|
|
"""Create a grid for visualization."""
|
|
grid = mcrfpy.Grid(
|
|
grid_size=grid_size,
|
|
pos=pos,
|
|
size=size
|
|
)
|
|
grid.fill_color = mcrfpy.Color(20, 20, 30)
|
|
self.ui.append(grid)
|
|
return grid
|
|
|
|
def color_grid_cell(self, grid, x, y, color):
|
|
"""Color a specific grid cell."""
|
|
try:
|
|
point = grid.at(x, y)
|
|
point.color = mcrfpy.Color(*color) if isinstance(color, tuple) else color
|
|
except:
|
|
pass # Out of bounds
|
|
|
|
def add_timer(self, name, callback, interval):
|
|
"""Add a timer and track it for cleanup/restart."""
|
|
if callback is None:
|
|
print(f"Warning: Timer '{name}' callback is None, skipping")
|
|
return
|
|
mcrfpy.setTimer(name, callback, interval)
|
|
self.timers.append(name)
|
|
self._timer_configs.append((name, callback, interval))
|