Astro-Session-Watcher/ui/dialogs/calibration_dialog.py

281 lines
10 KiB
Python
Raw Normal View History

"""
CalibrationDialog - главный диалог калибровки
С выбором камеры, папки и типа кадров
"""
from PySide6.QtWidgets import (
QDialog, QVBoxLayout, QHBoxLayout, QGridLayout,
QLabel, QComboBox, QLineEdit, QPushButton, QFrame,
QMessageBox, QFileDialog, QWidget
)
from PySide6.QtCore import Qt, QTimer
from PySide6.QtGui import QFont
from services.config_service import ConfigService
class CalibrationDialog(QDialog):
"""Главное окно калибровки"""
def __init__(self, parent, config_service: ConfigService):
super().__init__(parent)
self.config_service = config_service
self.setWindowTitle("🌑 Калибровочные кадры")
self.setMinimumSize(600, 450)
self.resize(650, 500)
self._create_ui()
self._load_saved_settings()
# Таймер для мигания кнопки "Обзор"
self._browse_blink_timer = None
self._check_folder_path()
def _create_ui(self):
layout = QVBoxLayout(self)
layout.setSpacing(20)
layout.setContentsMargins(25, 25, 25, 25)
# Заголовок
title_label = QLabel("🌑 Калибровочные кадры")
title_font = QFont()
title_font.setPointSize(18)
title_font.setBold(True)
title_label.setFont(title_font)
layout.addWidget(title_label)
# Основная сетка
grid = QGridLayout()
grid.setVerticalSpacing(15)
grid.setHorizontalSpacing(15)
# Строка 0: Камера
camera_label = QLabel("📷 Камера:")
camera_label.setFont(QFont("", 10, QFont.Bold))
grid.addWidget(camera_label, 0, 0)
self.camera_combo = QComboBox()
self.camera_combo.setEditable(True)
self.camera_combo.setMinimumWidth(250)
grid.addWidget(self.camera_combo, 0, 1)
# Строка 1: Папка
folder_label = QLabel("📁 Папка:")
folder_label.setFont(QFont("", 10, QFont.Bold))
grid.addWidget(folder_label, 1, 0)
folder_widget = QWidget()
folder_layout = QHBoxLayout(folder_widget)
folder_layout.setContentsMargins(0, 0, 0, 0)
folder_layout.setSpacing(10)
self.folder_entry = QLineEdit()
self.folder_entry.setPlaceholderText("Выберите папку для сохранения калибровочных кадров")
folder_layout.addWidget(self.folder_entry)
self.browse_button = QPushButton("✨ Обзор")
self.browse_button.setFixedWidth(100)
self.browse_button.clicked.connect(self._browse_folder)
folder_layout.addWidget(self.browse_button)
grid.addWidget(folder_widget, 1, 1)
layout.addLayout(grid)
# Разделитель
separator = QFrame()
separator.setFrameShape(QFrame.HLine)
separator.setStyleSheet("background-color: #333333; max-height: 1px;")
layout.addWidget(separator)
# Кнопки типов кадров
types_layout = QHBoxLayout()
types_layout.setSpacing(20)
types_layout.setAlignment(Qt.AlignCenter)
self.bias_btn = QPushButton("⚪ BIAS")
self.bias_btn.setFixedSize(120, 50)
self.bias_btn.setStyleSheet("""
QPushButton {
background-color: #2196F3;
color: white;
font-weight: bold;
font-size: 14px;
border-radius: 6px;
}
QPushButton:hover {
background-color: #1976D2;
}
""")
self.bias_btn.clicked.connect(lambda: self._open_calibration_type('bias'))
self.dark_btn = QPushButton("🌑 DARK")
self.dark_btn.setFixedSize(120, 50)
self.dark_btn.setStyleSheet("""
QPushButton {
background-color: #9C27B0;
color: white;
font-weight: bold;
font-size: 14px;
border-radius: 6px;
}
QPushButton:hover {
background-color: #7B1FA2;
}
""")
self.dark_btn.clicked.connect(lambda: self._open_calibration_type('dark'))
self.flat_btn = QPushButton("📖 FLAT")
self.flat_btn.setFixedSize(120, 50)
self.flat_btn.setStyleSheet("""
QPushButton {
background-color: #4CAF50;
color: white;
font-weight: bold;
font-size: 14px;
border-radius: 6px;
}
QPushButton:hover {
background-color: #388E3C;
}
""")
self.flat_btn.clicked.connect(lambda: self._open_calibration_type('flat'))
types_layout.addWidget(self.bias_btn)
types_layout.addWidget(self.dark_btn)
types_layout.addWidget(self.flat_btn)
layout.addLayout(types_layout)
# Совет
tips_frame = QFrame()
tips_frame.setStyleSheet("""
QFrame {
background-color: #2d2d2d;
border-radius: 8px;
padding: 10px;
}
""")
tips_layout = QVBoxLayout(tips_frame)
tips_title = QLabel("💡 Совет")
tips_title.setFont(QFont("", 11, QFont.Bold))
tips_layout.addWidget(tips_title)
self.tips_label = QLabel(
"• BIAS снимаются один раз на месяц (можно дома)\n"
"• DARK снимаются на месте съёмки при той же температуре\n"
"• FLAT снимаются после сессии без изменения фокуса"
)
self.tips_label.setWordWrap(True)
tips_layout.addWidget(self.tips_label)
layout.addWidget(tips_frame)
# Кнопки отмена/закрыть
buttons_layout = QHBoxLayout()
buttons_layout.addStretch()
cancel_btn = QPushButton("❌ Отмена")
cancel_btn.clicked.connect(self.reject)
buttons_layout.addWidget(cancel_btn)
layout.addLayout(buttons_layout)
def _load_saved_settings(self):
"""Загружает сохранённые камеры"""
cameras = self.config_service.get_cameras()
if cameras:
self.camera_combo.addItems(cameras)
last_camera = self.config_service.get_last_camera()
if last_camera and last_camera in cameras:
self.camera_combo.setCurrentText(last_camera)
def _browse_folder(self):
"""Выбор папки для калибровочных кадров"""
folder = QFileDialog.getExistingDirectory(self, "Выберите папку для калибровочных кадров")
if folder:
self.folder_entry.setText(folder)
self._stop_browse_blinking()
def _check_folder_path(self):
"""Проверяет, заполнено ли поле пути и запускает мигание если нет"""
if not self.folder_entry.text():
self._start_browse_blinking()
else:
self._stop_browse_blinking()
def _start_browse_blinking(self):
"""Запускает мигание кнопки 'Обзор' зелёным цветом"""
self._browse_blink_timer = QTimer()
self._browse_blink_timer.timeout.connect(self._do_browse_blink)
self._browse_blink_timer.start(500)
def _do_browse_blink(self):
"""Мигание кнопки"""
current_style = self.browse_button.styleSheet()
if "background-color: #4CAF50" in current_style:
self.browse_button.setStyleSheet("""
QPushButton {
background-color: #2196F3;
color: white;
font-weight: bold;
border-radius: 4px;
}
""")
else:
self.browse_button.setStyleSheet("""
QPushButton {
background-color: #4CAF50;
color: white;
font-weight: bold;
border-radius: 4px;
}
""")
def _stop_browse_blinking(self):
"""Останавливает мигание кнопки"""
if self._browse_blink_timer:
self._browse_blink_timer.stop()
self._browse_blink_timer = None
self.browse_button.setStyleSheet("""
QPushButton {
background-color: #2196F3;
color: white;
font-weight: bold;
border-radius: 4px;
}
""")
def _open_calibration_type(self, cal_type: str):
"""Открывает дочернее окно для выбранного типа калибровки"""
if not self.folder_entry.text():
QMessageBox.warning(self, "Внимание", "Сначала выберите папку для сохранения!")
self._start_browse_blinking()
return
camera_name = self.camera_combo.currentText()
if not camera_name:
QMessageBox.warning(self, "Внимание", "Введите или выберите название камеры!")
return
from ui.dialogs.calibration_type_dialog import CalibrationTypeDialog
dialog = CalibrationTypeDialog(
self,
cal_type,
self.folder_entry.text(),
camera_name,
self.config_service
)
if dialog.exec():
# После успешной съёмки
QMessageBox.information(self, "Успех", f"Съёмка {cal_type.upper()} завершена!")
def reject(self):
"""Закрытие диалога"""
if hasattr(self, '_browse_blink_timer') and self._browse_blink_timer:
self._browse_blink_timer.stop()
super().reject()