Files
VPNTray/utils/icon_loader.py
2025-09-07 23:33:55 +02:00

142 lines
4.5 KiB
Python

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