"""Icon loader utility for host icons with fallback support.""" import os from pathlib import Path import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk, GdkPixbuf from models import HostType class IconLoader: """Manages loading of host icons with fallback to Material Icons.""" # Default icon size ICON_SIZE = 20 # Project root directory PROJECT_ROOT = Path(__file__).parent.parent ICONS_DIR = PROJECT_ROOT / "assets" / "icons" # Material Icons fallback mapping for host types HOST_TYPE_ICONS = { HostType.LINUX: "computer", HostType.WINDOWS: "desktop_windows", HostType.WINDOWS_SERVER: "dns", HostType.PROXMOX: "developer_board", HostType.ESXI: "developer_board", HostType.ROUTER: "router", HostType.SWITCH: "device_hub" } @classmethod def get_host_icon_widget(cls, host, size=None) -> Gtk.Widget: """Get an icon widget for a host, either custom SVG or Material Icon fallback. Args: host: Host object with optional icon field size: Icon size in pixels (default: ICON_SIZE) Returns: Gtk.Image if custom icon exists, Gtk.Label with Material Icon otherwise """ if size is None: size = cls.ICON_SIZE # Try custom icon first if host.icon: icon_widget = cls._load_custom_icon(host.icon, size) if icon_widget: return icon_widget # Fallback to Material Icons based on host type return cls._create_material_icon(host.host_type, size) @classmethod def _load_custom_icon(cls, icon_name: str, size: int) -> Gtk.Image: """Load a custom SVG icon from assets/icons directory. Args: icon_name: Name of the icon file without extension (e.g., 'ubuntu') size: Icon size in pixels Returns: Gtk.Image if icon exists, None otherwise """ # Try SVG first, then PNG for extension in ['.svg', '.png']: icon_path = cls.ICONS_DIR / f"{icon_name}{extension}" if icon_path.exists(): try: # Load and scale the icon pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size( str(icon_path), size, size ) image = Gtk.Image.new_from_pixbuf(pixbuf) return image except Exception as e: print(f"Failed to load icon {icon_path}: {e}") return None @classmethod def _create_material_icon(cls, host_type: HostType, size: int) -> Gtk.Label: """Create a Material Icon label for a host type. Args: host_type: HostType enum value size: Icon size in pixels Returns: Gtk.Label with Material Icon """ icon_name = cls.HOST_TYPE_ICONS.get(host_type, "computer") label = Gtk.Label() label.set_text(icon_name) label.get_style_context().add_class("material-icons") # Apply custom CSS for size css = f""" #{label.get_name()} {{ font-size: {size}px; }} """ return label @classmethod def get_service_icon(cls, service_type: str, is_accessible: bool) -> Gtk.Label: """Get a Material Icon for a service with color coding. Args: service_type: Service type string (e.g., 'SSH', 'Web GUI') is_accessible: Whether the service is currently accessible Returns: Gtk.Label with colored Material Icon """ # Service type to Material Icons mapping service_icons = { 'SSH': 'terminal', 'Web GUI': 'language', 'RDP': 'desktop_windows', 'VNC': 'monitor', 'SMB': 'folder_shared', 'Database': 'storage', 'FTP': 'cloud_upload' } icon_name = service_icons.get(service_type, 'settings') label = Gtk.Label() label.set_text(icon_name) # Apply color based on accessibility if is_accessible: label.get_style_context().add_class("service-icon-accessible") else: label.get_style_context().add_class("service-icon-inaccessible") return label