""" Custom Spinner Widget A professionally designed animated spinner with rotating arc design. """ from PyQt5.QtWidgets import QWidget from PyQt5.QtCore import Qt, QTimer, QRect, QSize from PyQt5.QtGui import QPainter, QPen, QColor, QBrush class Spinner(QWidget): """ A custom rotating spinner widget with smooth arc animation. Features: - Smooth rotating arc design - Customizable colors and sizes - Professional appearance """ def __init__(self, parent=None, size: int = 60, color: str = "#3498db"): """ Initialize the spinner. Args: parent: Parent widget size: Size of the spinner in pixels color: Color of the spinner (hex or color name) """ super().__init__(parent) self.size = size self.color = QColor(color) self.angle = 0 self.setMinimumSize(size + 20, size + 20) self.setMaximumSize(size + 20, size + 20) # Animation timer self.timer = QTimer() self.timer.timeout.connect(self._rotate) self.timer.start(30) # ~33 FPS for smooth animation def _rotate(self): """Update rotation angle.""" self.angle = (self.angle + 6) % 360 # Rotate 6 degrees each frame self.update() def paintEvent(self, event): """Paint the spinner.""" painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) # Center the spinner center_x = self.width() // 2 center_y = self.height() // 2 # Draw rotating arc pen = QPen(self.color) pen.setWidth(4) pen.setCapStyle(Qt.RoundCap) painter.setPen(pen) # Draw the spinning arc rect = QRect(center_x - self.size // 2, center_y - self.size // 2, self.size, self.size) start_angle = self.angle * 16 # Qt uses 1/16 degree units span_angle = 120 * 16 # 120 degree arc painter.drawArc(rect, start_angle, span_angle) # Draw subtle background circle bg_pen = QPen(QColor("#ecf0f1")) bg_pen.setWidth(3) painter.setPen(bg_pen) painter.drawEllipse(rect) def stop(self): """Stop the spinner animation.""" self.timer.stop() def start(self): """Start the spinner animation.""" self.timer.start(30) def set_color(self, color: str): """ Change the spinner color. Args: color: Color in hex or color name """ self.color = QColor(color) self.update() class DotsSpinner(QWidget): """ An alternative spinner with rotating dots around a circle. """ def __init__(self, parent=None, size: int = 60, color: str = "#3498db", dot_count: int = 8): """ Initialize the dots spinner. Args: parent: Parent widget size: Size of the spinner in pixels color: Color of the spinner dots dot_count: Number of rotating dots """ super().__init__(parent) self.size = size self.color = QColor(color) self.angle = 0 self.dot_count = dot_count self.setMinimumSize(size + 20, size + 20) self.setMaximumSize(size + 20, size + 20) # Animation timer self.timer = QTimer() self.timer.timeout.connect(self._rotate) self.timer.start(30) def _rotate(self): """Update rotation angle.""" self.angle = (self.angle + 360 / self.dot_count / 8) % 360 self.update() def paintEvent(self, event): """Paint the spinner with rotating dots.""" painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) # Center the spinner center_x = self.width() // 2 center_y = self.height() // 2 # Draw rotating dots import math radius = self.size // 2 dot_radius = 3 for i in range(self.dot_count): # Calculate angle for this dot dot_angle = (self.angle + (360 / self.dot_count) * i) * math.pi / 180 # Calculate position x = center_x + radius * math.cos(dot_angle) y = center_y + radius * math.sin(dot_angle) # Fade effect - dots fade out as they come to the back opacity = (i / self.dot_count + 0.5) % 1.0 color = QColor(self.color) color.setAlpha(int(255 * opacity)) # Draw dot painter.setPen(Qt.NoPen) painter.setBrush(color) painter.drawEllipse(int(x - dot_radius), int(y - dot_radius), dot_radius * 2, dot_radius * 2) def stop(self): """Stop the spinner animation.""" self.timer.stop() def start(self): """Start the spinner animation.""" self.timer.start(30) def set_color(self, color: str): """ Change the spinner color. Args: color: Color in hex or color name """ self.color = QColor(color) self.update()