Initial commit of WhisperVoice

This commit is contained in:
Your Name
2026-01-24 17:03:52 +02:00
commit 9ff0e8d108
118 changed files with 6102 additions and 0 deletions

210
src/ui/components.py Normal file
View File

@@ -0,0 +1,210 @@
"""
Modern Components Library.
==========================
Contains custom-painted widgets that move beyond the standard 'amateur' Qt look.
Implements smooth animations, hardware acceleration, and glassmorphism.
"""
from PySide6.QtWidgets import (
QPushButton, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QGraphicsDropShadowEffect, QFrame, QAbstractButton
)
from PySide6.QtCore import Qt, QPropertyAnimation, QEasingCurve, Property, QRect, QPoint, Signal, Slot
from PySide6.QtGui import QPainter, QColor, QBrush, QPen, QLinearGradient, QFont
from src.ui.styles import Theme
class GlassButton(QPushButton):
"""A premium button with gradient hover effects and smooth scaling."""
def __init__(self, text, parent=None, accent_color=Theme.ACCENT_CYAN):
super().__init__(text, parent)
self.accent = QColor(accent_color)
self.setCursor(Qt.PointingHandCursor)
self.setFixedHeight(40)
self._hover_opacity = 0.0
self.setStyleSheet(f"""
QPushButton {{
background-color: rgba(255, 255, 255, 0.05);
border: 1px solid {Theme.BORDER_SUBTLE};
color: {Theme.TEXT_SECONDARY};
border-radius: 8px;
padding: 0 20px;
font-size: 13px;
font-weight: 600;
}}
""")
# Hover Animation
self.anim = QPropertyAnimation(self, b"hover_opacity")
self.anim.setDuration(200)
self.anim.setStartValue(0.0)
self.anim.setEndValue(1.0)
self.anim.setEasingCurve(QEasingCurve.OutCubic)
@Property(float)
def hover_opacity(self): return self._hover_opacity
@hover_opacity.setter
def hover_opacity(self, value):
self._hover_opacity = value
self.update()
def enterEvent(self, event):
self.anim.setDirection(QPropertyAnimation.Forward)
self.anim.start()
super().enterEvent(event)
def leaveEvent(self, event):
self.anim.setDirection(QPropertyAnimation.Backward)
self.anim.start()
super().leaveEvent(event)
def paintEvent(self, event):
"""Custom paint for the glow effect."""
super().paintEvent(event)
if self._hover_opacity > 0:
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
# Subtle Glow Border
color = QColor(self.accent)
color.setAlphaF(self._hover_opacity * 0.5)
painter.setPen(QPen(color, 1.5))
painter.setBrush(Qt.NoBrush)
painter.drawRoundedRect(self.rect().adjusted(1,1,-1,-1), 8, 8)
# Text Glow color shift
self.setStyleSheet(f"""
QPushButton {{
background-color: rgba(255, 255, 255, {0.05 + (self._hover_opacity * 0.05)});
border: 1px solid {Theme.BORDER_SUBTLE};
color: white;
border-radius: 8px;
padding: 0 20px;
font-size: 13px;
font-weight: 600;
}}
""")
class ModernSwitch(QAbstractButton):
"""A sleek iOS-style toggle switch."""
def __init__(self, parent=None, active_color=Theme.ACCENT_GREEN):
super().__init__(parent)
self.setCheckable(True)
self.setFixedSize(44, 24)
self._thumb_pos = 3.0
self.active_color = QColor(active_color)
self.anim = QPropertyAnimation(self, b"thumb_pos")
self.anim.setDuration(200)
self.anim.setEasingCurve(QEasingCurve.InOutCubic)
@Property(float)
def thumb_pos(self): return self._thumb_pos
@thumb_pos.setter
def thumb_pos(self, value):
self._thumb_pos = value
self.update()
def nextCheckState(self):
super().nextCheckState()
self.anim.stop()
if self.isChecked():
self.anim.setEndValue(23.0)
else:
self.anim.setEndValue(3.0)
self.anim.start()
def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
# Background
bg_color = QColor("#2d2d3d")
if self.isChecked():
bg_color = self.active_color
painter.setBrush(bg_color)
painter.setPen(Qt.NoPen)
painter.drawRoundedRect(self.rect(), 12, 12)
# Thumb
painter.setBrush(Qt.white)
painter.drawEllipse(QPoint(self._thumb_pos + 9, 12), 9, 9)
class ModernFrame(QFrame):
"""A base frame with rounded corners and a shadow."""
def __init__(self, parent=None):
super().__init__(parent)
self.setObjectName("premiumFrame")
self.setStyleSheet(f"""
#premiumFrame {{
background-color: {Theme.BG_CARD};
border: 1px solid {Theme.BORDER_SUBTLE};
border-radius: 12px;
}}
""")
self.shadow = QGraphicsDropShadowEffect(self)
self.shadow.setBlurRadius(25)
self.shadow.setXOffset(0)
self.shadow.setYOffset(8)
self.shadow.setColor(QColor(0, 0, 0, 180))
self.setGraphicsEffect(self.shadow)
from PySide6.QtWidgets import (
QPushButton, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QGraphicsDropShadowEffect, QFrame, QAbstractButton, QSlider
)
class ModernSlider(QSlider):
"""A custom painted modern slider with a glowing knob."""
def __init__(self, orientation=Qt.Horizontal, parent=None):
super().__init__(orientation, parent)
self.setStyleSheet(f"""
QSlider::groove:horizontal {{
border: 1px solid {Theme.BG_DARK};
height: 4px;
background: {Theme.BG_DARK};
margin: 2px 0;
border-radius: 2px;
}}
QSlider::handle:horizontal {{
background: {Theme.ACCENT_CYAN};
border: 2px solid white;
width: 16px;
height: 16px;
margin: -7px 0;
border-radius: 8px;
}}
QSlider::add-page:horizontal {{
background: {Theme.BG_DARK};
}}
QSlider::sub-page:horizontal {{
background: {Theme.ACCENT_CYAN};
border-radius: 2px;
}}
""")
class FramelessWindow(QWidget):
"""Base class for all premium windows to handle dragging and frameless logic."""
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.NoDropShadowWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
self._drag_pos = None
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self._drag_pos = event.globalPosition().toPoint() - self.frameGeometry().topLeft()
event.accept()
def mouseMoveEvent(self, event):
if event.buttons() & Qt.LeftButton:
self.move(event.globalPosition().toPoint() - self._drag_pos)
event.accept()