timer_window.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. """Fullscreen timer display window."""
  2. from PyQt6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QApplication
  3. from PyQt6.QtCore import QTimer, Qt, pyqtSignal
  4. from PyQt6.QtGui import QFont, QScreen
  5. class TimerWindow(QWidget):
  6. finished = pyqtSignal()
  7. def __init__(self, timer, monitor_index=0, position=0):
  8. super().__init__()
  9. self.timer_model = timer
  10. self.remaining_seconds = timer.duration
  11. self.monitor_index = monitor_index
  12. self.position = position # 0 for left half, 1 for right half
  13. self.countdown_timer = None
  14. self.is_paused = False
  15. self.init_ui()
  16. self.start_countdown()
  17. def init_ui(self):
  18. # Set window flags for fullscreen
  19. self.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint)
  20. # Set background color
  21. self.setStyleSheet(f"background-color: {self.timer_model.bg_color};")
  22. # Layout
  23. layout = QVBoxLayout(self)
  24. layout.setContentsMargins(50, 50, 50, 50)
  25. # Timer title
  26. self.title_label = QLabel(self.timer_model.name)
  27. self.title_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
  28. self.title_label.setStyleSheet(f"color: {self.timer_model.text_color};")
  29. title_font = QFont("Arial", self.timer_model.font_size // 3, QFont.Weight.Bold)
  30. self.title_label.setFont(title_font)
  31. layout.addWidget(self.title_label)
  32. # Timer label
  33. self.time_label = QLabel(self.format_time(self.remaining_seconds))
  34. self.time_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
  35. self.time_label.setStyleSheet(f"color: {self.timer_model.text_color};")
  36. font = QFont("Arial", self.timer_model.font_size, QFont.Weight.Bold)
  37. self.time_label.setFont(font)
  38. layout.addWidget(self.time_label)
  39. # Control buttons
  40. control_layout = QHBoxLayout()
  41. control_layout.addStretch()
  42. button_font = QFont("Arial", 16, QFont.Weight.Bold)
  43. button_style = f"""
  44. QPushButton {{
  45. background-color: rgba(255, 255, 255, 0.2);
  46. color: {self.timer_model.text_color};
  47. border: 2px solid {self.timer_model.text_color};
  48. border-radius: 10px;
  49. padding: 15px 30px;
  50. min-width: 120px;
  51. }}
  52. QPushButton:hover {{
  53. background-color: rgba(255, 255, 255, 0.3);
  54. }}
  55. QPushButton:pressed {{
  56. background-color: rgba(255, 255, 255, 0.4);
  57. }}
  58. """
  59. self.pause_btn = QPushButton("Pause")
  60. self.pause_btn.setFont(button_font)
  61. self.pause_btn.setStyleSheet(button_style)
  62. self.pause_btn.clicked.connect(self.toggle_pause)
  63. control_layout.addWidget(self.pause_btn)
  64. self.stop_btn = QPushButton("Stop")
  65. self.stop_btn.setFont(button_font)
  66. self.stop_btn.setStyleSheet(button_style)
  67. self.stop_btn.clicked.connect(self.stop_timer)
  68. control_layout.addWidget(self.stop_btn)
  69. self.restart_btn = QPushButton("Restart")
  70. self.restart_btn.setFont(button_font)
  71. self.restart_btn.setStyleSheet(button_style)
  72. self.restart_btn.clicked.connect(self.restart_timer)
  73. control_layout.addWidget(self.restart_btn)
  74. control_layout.addStretch()
  75. layout.addLayout(control_layout)
  76. # Position on selected monitor
  77. self.position_on_monitor()
  78. # Show fullscreen
  79. self.showFullScreen()
  80. def position_on_monitor(self):
  81. screens = QApplication.screens()
  82. if self.monitor_index < len(screens):
  83. screen = screens[self.monitor_index]
  84. geometry = screen.geometry()
  85. else:
  86. # Fallback to primary screen
  87. screen = QApplication.primaryScreen()
  88. geometry = screen.geometry()
  89. # Split screen in half if position is 0 or 1
  90. if self.position == 0:
  91. # Left half
  92. self.setGeometry(geometry.x(), geometry.y(),
  93. geometry.width() // 2, geometry.height())
  94. elif self.position == 1:
  95. # Right half
  96. self.setGeometry(geometry.x() + geometry.width() // 2, geometry.y(),
  97. geometry.width() // 2, geometry.height())
  98. else:
  99. # Full screen (shouldn't happen with current logic)
  100. self.setGeometry(geometry)
  101. def start_countdown(self):
  102. self.countdown_timer = QTimer(self)
  103. self.countdown_timer.timeout.connect(self.update_timer)
  104. self.countdown_timer.start(1000) # Update every second
  105. def update_timer(self):
  106. if not self.is_paused:
  107. self.remaining_seconds -= 1
  108. if self.remaining_seconds <= 0:
  109. self.countdown_timer.stop()
  110. self.time_label.setText("TIME'S UP!")
  111. self.pause_btn.setEnabled(False)
  112. self.restart_btn.setEnabled(True)
  113. QTimer.singleShot(3000, self.close_window) # Close after 3 seconds
  114. else:
  115. self.time_label.setText(self.format_time(self.remaining_seconds))
  116. def format_time(self, seconds):
  117. hours = seconds // 3600
  118. minutes = (seconds % 3600) // 60
  119. secs = seconds % 60
  120. if hours > 0:
  121. return f"{hours:02d}:{minutes:02d}:{secs:02d}"
  122. else:
  123. return f"{minutes:02d}:{secs:02d}"
  124. def toggle_pause(self):
  125. """Toggle pause/resume state."""
  126. self.is_paused = not self.is_paused
  127. if self.is_paused:
  128. self.pause_btn.setText("Resume")
  129. else:
  130. self.pause_btn.setText("Pause")
  131. def restart_timer(self):
  132. """Restart the timer from the beginning."""
  133. self.remaining_seconds = self.timer_model.duration
  134. self.time_label.setText(self.format_time(self.remaining_seconds))
  135. self.is_paused = False
  136. self.pause_btn.setText("Pause")
  137. self.pause_btn.setEnabled(True)
  138. if not self.countdown_timer.isActive():
  139. self.countdown_timer.start(1000)
  140. def stop_timer(self):
  141. """Stop the timer and close the window."""
  142. if self.countdown_timer and self.countdown_timer.isActive():
  143. self.countdown_timer.stop()
  144. self.close_window()
  145. def close_window(self):
  146. self.finished.emit()
  147. self.close()
  148. def keyPressEvent(self, event):
  149. # Allow ESC key to close the timer
  150. if event.key() == Qt.Key.Key_Escape:
  151. self.stop_timer()
  152. # Space bar to pause/resume
  153. elif event.key() == Qt.Key.Key_Space:
  154. self.toggle_pause()
  155. super().keyPressEvent(event)