180 lines
No EOL
6.9 KiB
Python
180 lines
No EOL
6.9 KiB
Python
"""
|
|
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) |