""" CalibrationDialog - главный диалог калибровки (tkinter) """ import tkinter as tk from tkinter import ttk, messagebox, filedialog from pathlib import Path class CalibrationDialog(tk.Toplevel): """Главное окно калибровки""" def __init__(self, parent, config_service): super().__init__(parent) self.parent = parent self.config_service = config_service self._blink_active = False self._blink_after_id = None self.title("Calibration Frames") self.geometry("650x500") self.minsize(600, 450) self.transient(parent) self.grab_set() self._create_ui() self._load_saved_settings() self._check_folder_path() self._center_window() def _create_ui(self): # Main frame main_frame = ttk.Frame(self, padding="25") main_frame.pack(fill='both', expand=True) # Title title_label = ttk.Label(main_frame, text="Calibration Frames", font=('Segoe UI', 18, 'bold')) title_label.pack(pady=(0, 15)) # Separator ttk.Separator(main_frame, orient='horizontal').pack(fill='x', pady=(0, 15)) # Camera selection camera_frame = ttk.Frame(main_frame) camera_frame.pack(fill='x', pady=5) ttk.Label(camera_frame, text="Camera:", font=('Segoe UI', 10, 'bold')).pack(side='left', padx=(0, 10)) self.camera_combo = ttk.Combobox(camera_frame, width=30) self.camera_combo.pack(side='left', fill='x', expand=True) # Folder selection folder_frame = ttk.Frame(main_frame) folder_frame.pack(fill='x', pady=5) ttk.Label(folder_frame, text="Folder:", font=('Segoe UI', 10, 'bold')).pack(side='left', padx=(0, 10)) folder_input_frame = ttk.Frame(folder_frame) folder_input_frame.pack(side='left', fill='x', expand=True) self.folder_entry = ttk.Entry(folder_input_frame) self.folder_entry.pack(side='left', fill='x', expand=True, padx=(0, 10)) self.browse_btn = tk.Button(folder_input_frame, text="Browse...", width=10, bg='#3c3c3c', fg='#e0e0e0', activebackground='#4c4c4c', relief='raised', borderwidth=1) self.browse_btn.config(command=self._browse_folder) self.browse_btn.pack(side='right') # Separator ttk.Separator(main_frame, orient='horizontal').pack(fill='x', pady=15) # Type buttons types_frame = ttk.Frame(main_frame) types_frame.pack(pady=10) self.bias_btn = tk.Button(types_frame, text="BIAS", font=('Segoe UI', 12, 'bold'), bg='#2196F3', fg='white', activebackground='#1976D2', width=12, height=2, command=lambda: self._open_calibration_type('bias')) self.bias_btn.pack(side='left', padx=10) self.dark_btn = tk.Button(types_frame, text="DARK", font=('Segoe UI', 12, 'bold'), bg='#9C27B0', fg='white', activebackground='#7B1FA2', width=12, height=2, command=lambda: self._open_calibration_type('dark')) self.dark_btn.pack(side='left', padx=10) self.flat_btn = tk.Button(types_frame, text="FLAT", font=('Segoe UI', 12, 'bold'), bg='#4CAF50', fg='white', activebackground='#388E3C', width=12, height=2, command=lambda: self._open_calibration_type('flat')) self.flat_btn.pack(side='left', padx=10) # Tips frame tips_frame = tk.Frame(main_frame, bg='#2d2d2d', relief='groove', bd=1) tips_frame.pack(fill='x', pady=15, padx=10) tk.Label(tips_frame, text="Tips:", font=('Segoe UI', 10, 'bold'), bg='#2d2d2d', fg='#FFD700').pack(anchor='w', padx=10, pady=(10, 5)) self.tips_label = tk.Label(tips_frame, text="• BIAS can be taken once a month (at home)\n• DARK must be taken on site at the same temperature\n• FLAT must be taken after session without changing focus", bg='#2d2d2d', fg='#e0e0e0', justify='left', font=('Segoe UI', 9)) self.tips_label.pack(anchor='w', padx=10, pady=(0, 10)) # Cancel button btn_frame = ttk.Frame(main_frame) btn_frame.pack(pady=10) ttk.Button(btn_frame, text="Cancel", command=self.destroy).pack() def _load_saved_settings(self): cameras = self.config_service.get_cameras() if cameras: self.camera_combo['values'] = cameras last_camera = self.config_service.get_last_camera() if last_camera and last_camera in cameras: self.camera_combo.set(last_camera) def _browse_folder(self): folder = filedialog.askdirectory(title="Select folder for calibration frames") if folder: self.folder_entry.delete(0, tk.END) self.folder_entry.insert(0, folder) self._stop_blinking() self.browse_btn.config(bg='#3c3c3c', fg='#e0e0e0') def _check_folder_path(self): if not self.folder_entry.get(): self._start_blinking() else: self._stop_blinking() def _start_blinking(self): self._blink_active = True def blink(): if not self._blink_active: return if self.browse_btn.cget('bg') == '#3c3c3c': self.browse_btn.config(bg='#f44336', fg='white') else: self.browse_btn.config(bg='#3c3c3c', fg='#e0e0e0') self._blink_after_id = self.after(1500, blink) blink() def _stop_blinking(self): self._blink_active = False if self._blink_after_id: self.after_cancel(self._blink_after_id) self._blink_after_id = None self.browse_btn.config(bg='#3c3c3c', fg='#e0e0e0') def _center_window(self): self.update_idletasks() x = self.parent.winfo_x() + (self.parent.winfo_width() // 2) - (self.winfo_width() // 2) y = self.parent.winfo_y() + (self.parent.winfo_height() // 2) - (self.winfo_height() // 2) self.geometry(f'+{x}+{y}') def _open_calibration_type(self, cal_type): if not self.folder_entry.get(): messagebox.showwarning("Warning", "Please select a folder to save calibration frames!", parent=self) self._start_blinking() return camera_name = self.camera_combo.get() if not camera_name: messagebox.showwarning("Warning", "Please enter or select a camera name!", parent=self) return from ui.dialogs.calibration_type_dialog import CalibrationTypeDialog dialog = CalibrationTypeDialog( self, cal_type, self.folder_entry.get(), camera_name, self.config_service ) self.wait_window(dialog)