# -*- coding: utf-8 -*- import tkinter as tk from tkinter import ttk, messagebox import logging from typing import Dict, Any, Type from pymsc.core.mission_logic import MissionLogic from pymsc.utils.logger import CustomLogger from pymsc.gui.script_manager import get_script_manager from pymsc.gui.components.command_widgets import ( CommandFrameCheckBox, CommandFrameComboBox, CommandFrameSpinBox, CommandFrameLabels, CommandFrameControls ) class MainWindow: """ Main Application Window. Uses a ttk.Notebook for real tab management. """ def __init__(self, root: tk.Tk): self.root = root self.root.title("PyMsc - Mission Computer Radar Control") # Core Components self.logic = MissionLogic() self.logger = CustomLogger() self.script_manager = get_script_manager() # Tab management self.tabs: Dict[str, tk.Frame] = {} self._setup_layout() # Start GUI refresh loop (Main Thread) self.root.after(100, self.gui_refresh_loop) def _setup_layout(self): """Organizes the main UI with a Top Toolbar, Central Notebook, and Bottom Log.""" # 1. Top Toolbar (for global buttons like Script Manager) self.toolbar = ttk.Frame(self.root, relief="flat", padding=5) self.toolbar.pack(side=tk.TOP, fill=tk.X) self.script_btn = ttk.Button( self.toolbar, text="SCRIPT MANAGER", command=lambda: self.script_manager.open_manager_gui(self.root) ) self.script_btn.pack(side=tk.RIGHT, padx=5) # 2. Main Tabbed Interface (Notebook) self.notebook = ttk.Notebook(self.root) self.notebook.pack(side=tk.TOP, fill=tk.BOTH, expand=True, padx=5, pady=5) # 3. Log Area (Bottom) self.log_container = ttk.Frame(self.root, relief="sunken", borderwidth=1) self.log_container.pack(side=tk.BOTTOM, fill=tk.X, padx=5, pady=5) self.logger.setup_tkinter_logging(self.log_container) def add_page(self, title: str, page_class: Type[tk.Frame]): """ Instantiates a page class and adds it as a new tab in the Notebook. """ page_instance = page_class(parent=self.notebook, controller=self) self.notebook.add(page_instance, text=title.upper()) self.tabs[title] = page_instance def gui_refresh_loop(self): """ Periodically refreshes widgets only in the currently active tab. """ # Get the currently selected tab widget current_tab_id = self.notebook.select() if current_tab_id: # The notebook.select() returns the widget name, # we need to find the widget instance current_tab_widget = self.root.nametowidget(current_tab_id) self._refresh_widgets_recursive(current_tab_widget) self.root.after(100, self.gui_refresh_loop) def _refresh_widgets_recursive(self, container: tk.Widget): """Traverses the widget tree to find and update PyMsc custom components.""" for child in container.winfo_children(): # Check if it's one of our custom command widgets is_custom = isinstance(child, ( CommandFrameCheckBox, CommandFrameComboBox, CommandFrameSpinBox, CommandFrameLabels, CommandFrameControls )) if is_custom: child.check_updated_value() # Continue searching if the child has its own children (like sub-frames) if child.winfo_children(): self._refresh_widgets_recursive(child) def start_mission(self): """Initializes 1553 and starts sync threads.""" config = {"ip": "127.0.0.1", "send_port": 5001, "recv_port": 5002} success = self.logic.initialize_system(config) if success: self.logic.start_mission() else: self.logger.get_logger().error("Hardware initialization failed.") def on_close(self): """Stops background logic before closing the window.""" self.logic.stop_mission() self.root.destroy()