Files
MonitorSwitcher/ui/tray.py

91 lines
3.1 KiB
Python

import queue
import logging
import pystray
from PIL import Image, ImageDraw
logger = logging.getLogger(__name__)
_COLORS = {"dp": "#1565C0", "hdmi": "#B71C1C", "default": "#455A64"}
def _make_icon(label: str, color: str) -> Image.Image:
img = Image.new("RGBA", (64, 64), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
draw.ellipse([2, 2, 62, 62], fill=color)
text = label[:2].upper()
bbox = draw.textbbox((0, 0), text)
tw = bbox[2] - bbox[0]
th = bbox[3] - bbox[1]
draw.text(((64 - tw) // 2, (64 - th) // 2), text, fill="white")
return img
def _color_for(profile_id: str) -> str:
if "dp" in profile_id:
return _COLORS["dp"]
if "hdmi" in profile_id:
return _COLORS["hdmi"]
return _COLORS["default"]
class TrayApp:
def __init__(self, config_manager, switcher, settings_queue: queue.Queue):
self._config_manager = config_manager
self._switcher = switcher
self._settings_queue = settings_queue
self._icon: pystray.Icon | None = None
switcher.on_switch(self._on_profile_switched)
def _build_menu(self) -> pystray.Menu:
config = self._config_manager.get()
items = []
for profile in config.get("profiles", []):
pid = profile["id"]
name = profile["name"]
items.append(
pystray.MenuItem(
name,
lambda _, p=pid: self._switcher.apply_profile(p),
checked=lambda item, p=pid: (
self._config_manager.get_active_profile_id() == p
),
radio=True,
)
)
items.append(pystray.Menu.SEPARATOR)
items.append(pystray.MenuItem("Ustawienia", self._request_settings))
items.append(pystray.MenuItem("Wyjscie", self._exit))
return pystray.Menu(*items)
def _on_profile_switched(self, profile_id: str) -> None:
if self._icon is None:
return
profile = self._config_manager.get_profile(profile_id)
label = profile["name"][:2] if profile else "??"
title = profile["name"] if profile else profile_id
self._icon.icon = _make_icon(label, _color_for(profile_id))
self._icon.title = f"MonitorSwitcher \u2014 {title}"
self._icon.update_menu()
def _request_settings(self, icon=None, item=None) -> None:
self._settings_queue.put("open_settings")
def _exit(self, icon=None, item=None) -> None:
self._settings_queue.put("exit")
if self._icon:
self._icon.stop()
def run_tray(self) -> None:
active_id = self._config_manager.get_active_profile_id()
profile = self._config_manager.get_profile(active_id)
label = profile["name"][:2] if profile else "MS"
title = f"MonitorSwitcher \u2014 {profile['name']}" if profile else "MonitorSwitcher"
self._icon = pystray.Icon(
"MonitorSwitcher",
_make_icon(label, _color_for(active_id)),
title=title,
menu=self._build_menu(),
)
self._icon.run()