You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

82 lines
2.6 KiB
Python

"""
System Tray Icon Handler
Manages the application in the system tray
"""
import pystray
import logging
from typing import Callable, Optional
from PIL import Image, ImageDraw
logger = logging.getLogger(__name__)
class SystemTrayIcon:
def __init__(self, app_name: str):
self.app_name = app_name
self.icon: Optional[pystray.Icon] = None
self.status_text = "Initializing..."
self.on_quit: Optional[Callable] = None
self.on_show: Optional[Callable] = None
def _create_image(self, status: str = "ready") -> Image.Image:
"""Create a simple tray icon image"""
size = 64
color_map = {
'ready': (0, 200, 0),
'running': (0, 150, 200),
'error': (200, 0, 0),
'waiting': (200, 150, 0),
}
color = color_map.get(status, (128, 128, 128))
image = Image.new('RGB', (size, size), color)
draw = ImageDraw.Draw(image)
draw.rectangle([0, 0, size-1, size-1], outline=(0, 0, 0), width=2)
return image
def set_status(self, status: str, text: str):
"""Update the tray icon status"""
self.status_text = text
if self.icon:
self.icon.update_menu()
def create_menu(self) -> pystray.Menu:
"""Create the context menu for the tray icon"""
menu_items = [
pystray.MenuItem(f"📊 {self.app_name}", action=None),
pystray.MenuItem("" * 30, action=None),
pystray.MenuItem("Status: " + self.status_text, action=None),
pystray.MenuItem("" * 30, action=None),
pystray.MenuItem("Quit", self._on_quit_click),
]
return pystray.Menu(*menu_items)
def _on_quit_click(self, icon, item):
"""Handle quit click"""
if self.on_quit:
self.on_quit()
if self.icon:
self.icon.stop()
def run(self):
"""Run the tray icon"""
try:
self.icon = pystray.Icon(
name=self.app_name,
icon=self._create_image('running'),
menu=self.create_menu(),
title=self.app_name
)
self.icon.run()
except Exception as e:
logger.error(f"Error running tray icon: {e}")
def stop(self):
"""Stop the tray icon"""
if self.icon:
self.icon.stop()
def set_callbacks(self, on_quit: Optional[Callable] = None, on_show: Optional[Callable] = None):
"""Set callback functions"""
self.on_quit = on_quit
self.on_show = on_show