""" Overlay Window Module. ====================== Premium High-Fidelity Overlay for Whisper Voice. Features glassmorphism, pulsating status indicators, and smart positioning. """ from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel from PySide6.QtCore import Qt, Slot, QPoint, QPropertyAnimation, QEasingCurve from PySide6.QtGui import QColor, QFont, QGuiApplication from src.ui.visualizer import AudioVisualizer from src.ui.styles import Theme, StyleGenerator, load_modern_fonts from src.ui.components import FramelessWindow, ModernFrame class OverlayWindow(FramelessWindow): """ The main transparent overlay (The Pill). Refactored for 2026 Premium Aesthetics. """ def __init__(self): super().__init__() self.setFixedSize(320, 95) # Main Layout self.master_layout = QVBoxLayout(self) self.master_layout.setContentsMargins(10, 10, 10, 10) # The Glass Pill Container self.pill = ModernFrame() self.pill.setStyleSheet(StyleGenerator.get_glass_card(radius=24)) self.master_layout.addWidget(self.pill) # Layout inside the pill self.layout = QHBoxLayout(self.pill) self.layout.setContentsMargins(20, 10, 20, 10) self.layout.setSpacing(15) # Status Visualization (Left Dot) self.status_dot = QWidget() self.status_dot.setFixedSize(14, 14) self.status_dot.setStyleSheet(f"background-color: {Theme.ACCENT_CYAN}; border-radius: 7px; border: 2px solid white;") self.layout.addWidget(self.status_dot) # Text/Visualizer Stack self.content_stack = QVBoxLayout() self.content_stack.setSpacing(2) self.content_stack.setContentsMargins(0, 0, 0, 0) self.status_label = QLabel("READY") self.status_label.setFont(load_modern_fonts()) self.status_label.setStyleSheet(f"color: white; font-weight: 800; font-size: 11px; letter-spacing: 2px;") self.content_stack.addWidget(self.status_label) self.visualizer = AudioVisualizer() self.visualizer.setFixedHeight(30) self.content_stack.addWidget(self.visualizer) self.layout.addLayout(self.content_stack) # Animations self.pulse_timer = None # Use style-based pulsing to avoid window flags issues # Initial State self.hide() self.first_show = True def showEvent(self, event): """Handle positioning and config updates.""" from src.core.config import ConfigManager config = ConfigManager() self.setWindowOpacity(config.get("opacity")) if self.first_show: self.center_above_taskbar() self.first_show = False super().showEvent(event) def center_above_taskbar(self): screen = QGuiApplication.primaryScreen() if not screen: return avail_rect = screen.availableGeometry() x = avail_rect.x() + (avail_rect.width() - self.width()) // 2 y = avail_rect.bottom() - self.height() - 15 self.move(x, y) @Slot(str) def update_status(self, text: str): """Updates the status text and visual indicator.""" self.status_label.setText(text.upper()) if "RECORDING" in text.upper(): color = Theme.ACCENT_GREEN elif "THINKING" in text.upper(): color = Theme.ACCENT_PURPLE else: color = Theme.ACCENT_CYAN self.status_dot.setStyleSheet(f"background-color: {color}; border-radius: 7px; border: 2px solid white;") @Slot(float) def update_visualizer(self, amp: float): self.visualizer.set_amplitude(amp)