EG/ui/icon_manager.py
2026-02-28 15:11:22 +08:00

155 lines
5.1 KiB
Python

"""
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)