|
|
""" |
|
|
UI Tools |
|
|
2D overlay elements for text, bars, and HUD components |
|
|
""" |
|
|
from typing import Dict, Any, Optional |
|
|
from backend.storage import storage |
|
|
|
|
|
|
|
|
def render_text_on_screen( |
|
|
scene_id: str, |
|
|
text: str, |
|
|
x: float = 50.0, |
|
|
y: float = 10.0, |
|
|
font_size: int = 24, |
|
|
color: str = "#ffffff", |
|
|
text_id: Optional[str] = None, |
|
|
font_family: str = "Arial", |
|
|
text_align: str = "center", |
|
|
background_color: Optional[str] = None, |
|
|
padding: int = 8 |
|
|
) -> Dict[str, Any]: |
|
|
""" |
|
|
Render text on the screen as a 2D overlay. |
|
|
|
|
|
Args: |
|
|
scene_id: ID of the scene |
|
|
text: The text to display |
|
|
x: Horizontal position in percentage (0=left edge, 50=center, 100=right edge) |
|
|
y: Vertical position in percentage (0=top edge, 50=center, 100=bottom edge) |
|
|
font_size: Font size in pixels (default: 24) |
|
|
color: Text color as hex (default: "#ffffff") |
|
|
text_id: Optional unique identifier for this text element (for updates/removal) |
|
|
font_family: CSS font family (default: "Arial") |
|
|
text_align: Text alignment - "left", "center", "right" (default: "center") |
|
|
background_color: Optional background color (e.g., "#000000" for black box behind text) |
|
|
padding: Padding around text in pixels when background is set (default: 8) |
|
|
|
|
|
Returns: |
|
|
Dictionary with text element info and message |
|
|
""" |
|
|
scene = storage.get(scene_id) |
|
|
if not scene: |
|
|
raise ValueError(f"Scene '{scene_id}' not found") |
|
|
|
|
|
if "ui_elements" not in scene: |
|
|
scene["ui_elements"] = [] |
|
|
|
|
|
|
|
|
if not text_id: |
|
|
text_id = f"text_{len([e for e in scene['ui_elements'] if e.get('element_type') == 'text'])}" |
|
|
|
|
|
|
|
|
scene["ui_elements"] = [e for e in scene["ui_elements"] if e.get("id") != text_id] |
|
|
|
|
|
|
|
|
x = max(0.0, min(100.0, x)) |
|
|
y = max(0.0, min(100.0, y)) |
|
|
|
|
|
text_element = { |
|
|
"id": text_id, |
|
|
"element_type": "text", |
|
|
"text": text, |
|
|
"x": x, |
|
|
"y": y, |
|
|
"font_size": font_size, |
|
|
"color": color, |
|
|
"font_family": font_family, |
|
|
"text_align": text_align, |
|
|
"background_color": background_color, |
|
|
"padding": padding, |
|
|
"visible": True |
|
|
} |
|
|
|
|
|
scene["ui_elements"].append(text_element) |
|
|
storage.save(scene) |
|
|
|
|
|
return { |
|
|
"scene_id": scene_id, |
|
|
"text_id": text_id, |
|
|
"message": f"Rendered text '{text[:30]}{'...' if len(text) > 30 else ''}' at ({x}%, {y}%)", |
|
|
"text_element": text_element |
|
|
} |
|
|
|
|
|
|
|
|
def render_bar_on_screen( |
|
|
scene_id: str, |
|
|
x: float = 10.0, |
|
|
y: float = 10.0, |
|
|
width: float = 200.0, |
|
|
height: float = 20.0, |
|
|
value: float = 100.0, |
|
|
max_value: float = 100.0, |
|
|
bar_color: str = "#00ff00", |
|
|
background_color: str = "#333333", |
|
|
border_color: Optional[str] = "#ffffff", |
|
|
bar_id: Optional[str] = None, |
|
|
label: Optional[str] = None, |
|
|
show_value: bool = False |
|
|
) -> Dict[str, Any]: |
|
|
""" |
|
|
Render a progress/health bar on the screen as a 2D overlay. |
|
|
|
|
|
Args: |
|
|
scene_id: ID of the scene |
|
|
x: Horizontal position in percentage (0=left edge, 50=center, 100=right edge) |
|
|
y: Vertical position in percentage (0=top edge, 50=center, 100=bottom edge) |
|
|
width: Bar width in pixels (default: 200) |
|
|
height: Bar height in pixels (default: 20) |
|
|
value: Current value (default: 100) |
|
|
max_value: Maximum value (default: 100) |
|
|
bar_color: Fill color for the bar (default: "#00ff00" green) |
|
|
background_color: Background color (default: "#333333" dark gray) |
|
|
border_color: Optional border color (default: "#ffffff" white) |
|
|
bar_id: Optional unique identifier for this bar (for updates/removal) |
|
|
label: Optional label text above the bar |
|
|
show_value: Show numeric value on the bar (default: False) |
|
|
|
|
|
Returns: |
|
|
Dictionary with bar element info and message |
|
|
""" |
|
|
scene = storage.get(scene_id) |
|
|
if not scene: |
|
|
raise ValueError(f"Scene '{scene_id}' not found") |
|
|
|
|
|
if "ui_elements" not in scene: |
|
|
scene["ui_elements"] = [] |
|
|
|
|
|
|
|
|
if not bar_id: |
|
|
bar_id = f"bar_{len([e for e in scene['ui_elements'] if e.get('element_type') == 'bar'])}" |
|
|
|
|
|
|
|
|
scene["ui_elements"] = [e for e in scene["ui_elements"] if e.get("id") != bar_id] |
|
|
|
|
|
|
|
|
x = max(0.0, min(100.0, x)) |
|
|
y = max(0.0, min(100.0, y)) |
|
|
value = max(0.0, min(max_value, value)) |
|
|
percentage = (value / max_value) * 100.0 if max_value > 0 else 0.0 |
|
|
|
|
|
bar_element = { |
|
|
"id": bar_id, |
|
|
"element_type": "bar", |
|
|
"x": x, |
|
|
"y": y, |
|
|
"width": width, |
|
|
"height": height, |
|
|
"value": value, |
|
|
"max_value": max_value, |
|
|
"percentage": percentage, |
|
|
"bar_color": bar_color, |
|
|
"background_color": background_color, |
|
|
"border_color": border_color, |
|
|
"label": label, |
|
|
"show_value": show_value, |
|
|
"visible": True |
|
|
} |
|
|
|
|
|
scene["ui_elements"].append(bar_element) |
|
|
storage.save(scene) |
|
|
|
|
|
label_str = f"'{label}' " if label else "" |
|
|
return { |
|
|
"scene_id": scene_id, |
|
|
"bar_id": bar_id, |
|
|
"message": f"Rendered {label_str}bar at ({x}%, {y}%) - {value}/{max_value} ({percentage:.0f}%)", |
|
|
"bar_element": bar_element |
|
|
} |
|
|
|
|
|
|
|
|
def remove_ui_element(scene_id: str, element_id: str) -> Dict[str, Any]: |
|
|
""" |
|
|
Remove a UI element from the screen. |
|
|
|
|
|
Args: |
|
|
scene_id: ID of the scene |
|
|
element_id: ID of the UI element to remove (text_id or bar_id) |
|
|
|
|
|
Returns: |
|
|
Dictionary with confirmation message |
|
|
""" |
|
|
scene = storage.get(scene_id) |
|
|
if not scene: |
|
|
raise ValueError(f"Scene '{scene_id}' not found") |
|
|
|
|
|
if "ui_elements" not in scene or not scene["ui_elements"]: |
|
|
raise ValueError("Scene has no UI elements") |
|
|
|
|
|
original_count = len(scene["ui_elements"]) |
|
|
scene["ui_elements"] = [e for e in scene["ui_elements"] if e.get("id") != element_id] |
|
|
|
|
|
if len(scene["ui_elements"]) == original_count: |
|
|
raise ValueError(f"UI element '{element_id}' not found") |
|
|
|
|
|
storage.save(scene) |
|
|
|
|
|
return { |
|
|
"scene_id": scene_id, |
|
|
"message": f"Removed UI element '{element_id}'", |
|
|
"element_id": element_id |
|
|
} |
|
|
|
|
|
|
|
|
def get_ui_elements(scene_id: str) -> Dict[str, Any]: |
|
|
""" |
|
|
Get all UI elements in the scene. |
|
|
|
|
|
Args: |
|
|
scene_id: ID of the scene |
|
|
|
|
|
Returns: |
|
|
Dictionary with all UI elements |
|
|
""" |
|
|
scene = storage.get(scene_id) |
|
|
if not scene: |
|
|
raise ValueError(f"Scene '{scene_id}' not found") |
|
|
|
|
|
ui_elements = scene.get("ui_elements", []) |
|
|
|
|
|
return { |
|
|
"scene_id": scene_id, |
|
|
"ui_elements": ui_elements, |
|
|
"count": len(ui_elements) |
|
|
} |
|
|
|