""" Icon manager compatibility layer for the ImGui-only runtime. This module keeps the legacy public API so older imports do not break immediately. """ from dataclasses import dataclass from pathlib import Path from typing import Dict, Optional, Tuple @dataclass(frozen=True) class IconHandle: """Lightweight icon placeholder used by legacy call sites.""" path: str = "" def isNull(self) -> bool: return not self.path def pixmap(self, _size: Optional[Tuple[int, int]] = None) -> "IconHandle": return self class IconManager: def __init__(self): self.icon_cache: Dict[str, IconHandle] = {} self.icon_directory = self._get_icon_directory() self.default_icon = IconHandle("") self.icon_map = { "app_logo": "logo.png", "select_tool": "select_tool.png", "move_tool": "move_tool.png", "rotate_tool": "rotate_tool.png", "scale_tool": "scale_tool.png", "new_file": "new_file.png", "open_file": "open_file.png", "save_file": "save_file.png", "exit": "exit.png", "object_3d": "object_3d.png", "light": "light.png", "camera": "camera.png", "terrain": "terrain.png", "script": "script.png", "success": "success.png", "warning": "warning.png", "error": "error.png", "info": "info.png", "up_arrow": "up_arrows.png", "down_arrow": "down_arrows.png", "left_arrow": "left_arrows.png", "right_arrow": "right_arrows.png", "solid_down_arrows": "solid_down_arrows.png", "solid_right_arrows": "solid_right_arrows.png", "minimize_icon": "minimize_icon.png", "windowing_icon": "windowing_icon.png", "close_icon": "close_icon.png", "success_icon": "success_icon.png", "warning_icon": "warning_icon.png", "fail_icon": "delete_fail_icon.png", "property_select_image": "property_select_image.png", } def _get_icon_directory(self) -> str: current_dir = Path(__file__).resolve().parent project_root = current_dir.parent icon_dir = project_root / "icons" return str(icon_dir) def _resolve_icon_path(self, icon_name: str) -> Path: if icon_name in self.icon_map: file_name = self.icon_map[icon_name] else: file_name = icon_name if not file_name.lower().endswith((".png", ".jpg", ".jpeg", ".svg", ".ico")): file_name += ".png" return Path(self.icon_directory) / file_name def get_icon(self, icon_name: str, _size: Optional[Tuple[int, int]] = None) -> IconHandle: if icon_name in self.icon_cache: return self.icon_cache[icon_name] icon_path = self._resolve_icon_path(icon_name) if icon_path.exists(): icon = IconHandle(str(icon_path)) self.icon_cache[icon_name] = icon return icon return self.default_icon def get_icon_path(self, icon_name: str) -> str: icon_path = self._resolve_icon_path(icon_name) return str(icon_path) if icon_path.exists() else "" def has_icon(self, icon_name: str) -> bool: return bool(self.get_icon_path(icon_name)) def add_icon(self, icon_name: str, icon_path: str) -> bool: path_obj = Path(icon_path) if not path_obj.exists(): return False self.icon_cache[icon_name] = IconHandle(str(path_obj)) return True def refresh_cache(self): self.icon_cache.clear() def get_available_icons(self) -> list: available_icons = sorted(self.icon_map.keys()) icon_dir = Path(self.icon_directory) if icon_dir.exists(): for p in icon_dir.iterdir(): if p.suffix.lower() in {".png", ".jpg", ".jpeg", ".svg", ".ico"}: name = p.stem if name not in available_icons: available_icons.append(name) return sorted(available_icons) def get_cache_info(self) -> dict: return { "cached_icons": len(self.icon_cache), "icon_directory": self.icon_directory, "available_icons": len(self.get_available_icons()), "cache_keys": list(self.icon_cache.keys()), } def debug_info(self): info = self.get_cache_info() print(f"icon_directory: {info['icon_directory']}") print(f"cached_icons: {info['cached_icons']}") print(f"available_icons: {info['available_icons']}") _icon_manager: Optional[IconManager] = None def get_icon_manager() -> IconManager: global _icon_manager if _icon_manager is None: _icon_manager = IconManager() return _icon_manager def get_icon(icon_name: str, size: Optional[Tuple[int, int]] = None) -> IconHandle: return get_icon_manager().get_icon(icon_name, size) def get_icon_path(icon_name: str) -> str: return get_icon_manager().get_icon_path(icon_name) def has_icon(icon_name: str) -> bool: return get_icon_manager().has_icon(icon_name)