"""Timer widget for displaying in the main window.""" from PyQt6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QFrame from PyQt6.QtCore import QTimer, Qt, pyqtSignal from PyQt6.QtGui import QFont class TimerWidget(QFrame): finished = pyqtSignal() time_updated = pyqtSignal(int) # Emits remaining seconds state_changed = pyqtSignal(bool) # Emits is_paused state def __init__(self, timer, is_mirror=False): super().__init__() self.timer_model = timer self.remaining_seconds = timer.duration self.is_paused = False self.is_mirror = is_mirror self.countdown_timer = None self.init_ui() if not is_mirror: self.start_countdown() def init_ui(self): # Frame styling self.setFrameStyle(QFrame.Shape.Box | QFrame.Shadow.Raised) self.setLineWidth(2) self.setStyleSheet(f""" QFrame {{ background-color: {self.timer_model.bg_color}; border: 3px solid {self.timer_model.text_color}; border-radius: 10px; margin: 5px; }} """) # Main layout layout = QVBoxLayout(self) layout.setContentsMargins(20, 20, 20, 20) # Timer title self.title_label = QLabel(self.timer_model.name) self.title_label.setAlignment(Qt.AlignmentFlag.AlignCenter) self.title_label.setStyleSheet(f"color: {self.timer_model.text_color}; border: none;") title_font = QFont("Arial", 18, QFont.Weight.Bold) self.title_label.setFont(title_font) layout.addWidget(self.title_label) # Timer display self.time_label = QLabel(self.format_time(self.remaining_seconds)) self.time_label.setAlignment(Qt.AlignmentFlag.AlignCenter) self.time_label.setStyleSheet(f"color: {self.timer_model.text_color}; border: none;") time_font = QFont("Arial", 48, QFont.Weight.Bold) self.time_label.setFont(time_font) layout.addWidget(self.time_label) # Control buttons control_layout = QHBoxLayout() button_style = f""" QPushButton {{ background-color: rgba(255, 255, 255, 0.2); color: {self.timer_model.text_color}; border: 2px solid {self.timer_model.text_color}; border-radius: 5px; padding: 10px 20px; font-size: 14px; font-weight: bold; }} QPushButton:hover {{ background-color: rgba(255, 255, 255, 0.3); }} QPushButton:pressed {{ background-color: rgba(255, 255, 255, 0.4); }} """ self.pause_btn = QPushButton("Pause") self.pause_btn.setStyleSheet(button_style) self.pause_btn.clicked.connect(self.toggle_pause) control_layout.addWidget(self.pause_btn) self.restart_btn = QPushButton("Restart") self.restart_btn.setStyleSheet(button_style) self.restart_btn.clicked.connect(self.restart_timer) control_layout.addWidget(self.restart_btn) self.stop_btn = QPushButton("Stop") self.stop_btn.setStyleSheet(button_style) self.stop_btn.clicked.connect(self.stop_timer) control_layout.addWidget(self.stop_btn) layout.addLayout(control_layout) # Hide controls for mirror widgets if self.is_mirror: self.pause_btn.hide() self.restart_btn.hide() self.stop_btn.hide() # Set minimum size self.setMinimumHeight(200) def start_countdown(self): self.countdown_timer = QTimer(self) self.countdown_timer.timeout.connect(self.update_timer) self.countdown_timer.start(1000) # Update every second def update_timer(self): if not self.is_paused: self.remaining_seconds -= 1 if self.remaining_seconds <= 0: self.countdown_timer.stop() self.time_label.setText("TIME'S UP!") self.pause_btn.setEnabled(False) self.time_updated.emit(0) QTimer.singleShot(3000, self.close_timer) # Close after 3 seconds else: self.time_label.setText(self.format_time(self.remaining_seconds)) self.time_updated.emit(self.remaining_seconds) def format_time(self, seconds): hours = seconds // 3600 minutes = (seconds % 3600) // 60 secs = seconds % 60 if hours > 0: return f"{hours:02d}:{minutes:02d}:{secs:02d}" else: return f"{minutes:02d}:{secs:02d}" def toggle_pause(self): """Toggle pause/resume state.""" self.is_paused = not self.is_paused if self.is_paused: self.pause_btn.setText("Resume") else: self.pause_btn.setText("Pause") self.state_changed.emit(self.is_paused) def restart_timer(self): """Restart the timer from the beginning.""" self.remaining_seconds = self.timer_model.duration self.time_label.setText(self.format_time(self.remaining_seconds)) self.is_paused = False self.pause_btn.setText("Pause") self.pause_btn.setEnabled(True) if not self.countdown_timer.isActive(): self.countdown_timer.start(1000) self.time_updated.emit(self.remaining_seconds) self.state_changed.emit(self.is_paused) def stop_timer(self): """Stop the timer and remove widget.""" if self.countdown_timer and self.countdown_timer.isActive(): self.countdown_timer.stop() self.close_timer() def close_timer(self): """Emit finished signal to remove this widget.""" self.finished.emit() def sync_with(self, source_widget): """Sync this mirror widget with the source widget.""" self.remaining_seconds = source_widget.remaining_seconds self.is_paused = source_widget.is_paused self.time_label.setText(self.format_time(self.remaining_seconds)) def update_display(self, remaining_seconds): """Update the display with new time (for mirror widgets).""" self.remaining_seconds = remaining_seconds if remaining_seconds <= 0: self.time_label.setText("TIME'S UP!") else: self.time_label.setText(self.format_time(remaining_seconds)) def update_state(self, is_paused): """Update the paused state (for mirror widgets).""" self.is_paused = is_paused