From 5ff168611274c593b8f32e9ee007b296a8a43916 Mon Sep 17 00:00:00 2001 From: VALLONGOL Date: Tue, 10 Jun 2025 14:18:30 +0200 Subject: [PATCH] add new icon, refactor live tab --- flightmonitor/assets/icons/play_icon.png | Bin 0 -> 9645 bytes flightmonitor/assets/icons/stop_icon.png | Bin 0 -> 9199 bytes flightmonitor/gui/main_window.py | 6 +- .../gui/panels/function_notebook_panel.py | 193 +++++++++++++----- 4 files changed, 142 insertions(+), 57 deletions(-) create mode 100644 flightmonitor/assets/icons/play_icon.png create mode 100644 flightmonitor/assets/icons/stop_icon.png diff --git a/flightmonitor/assets/icons/play_icon.png b/flightmonitor/assets/icons/play_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8c0c499c38e0a9e82ba3b2264f82a4e0cd17e220 GIT binary patch literal 9645 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 literal 0 HcmV?d00001 diff --git a/flightmonitor/assets/icons/stop_icon.png b/flightmonitor/assets/icons/stop_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a0c58da99561970c4a727d622fc43c1cf02d7d99 GIT binary patch literal 9199 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 literal 0 HcmV?d00001 diff --git a/flightmonitor/gui/main_window.py b/flightmonitor/gui/main_window.py index cc19989..ff5c116 100644 --- a/flightmonitor/gui/main_window.py +++ b/flightmonitor/gui/main_window.py @@ -18,7 +18,7 @@ from .panels.map_tools_panel import MapToolsPanel from .panels.map_info_panel import MapInfoPanel from .panels.selected_flight_details_panel import SelectedFlightDetailsPanel from .panels.views_notebook_panel import ViewsNotebookPanel -from .panels.function_notebook_panel import FunctionNotebookPanel +from .panels.function_notebook_panel import FunctionNotebookPanel, DEFAULT_PROFILE_NAME try: from ..map.map_canvas_manager import MapCanvasManager @@ -211,6 +211,10 @@ class MainWindow: else: self._update_map_placeholder("Map functionality disabled (Import Error).") + # MODIFICA: Invochiamo il caricamento del profilo di default da qui, + # dopo che la mappa è stata programmata per l'inizializzazione. + self.root.after(250, lambda: self.controller.load_area_profile(DEFAULT_PROFILE_NAME)) + self.function_notebook_panel._on_tab_change() module_logger.info("MainWindow fully initialized.") diff --git a/flightmonitor/gui/panels/function_notebook_panel.py b/flightmonitor/gui/panels/function_notebook_panel.py index 5c37631..a2f714d 100644 --- a/flightmonitor/gui/panels/function_notebook_panel.py +++ b/flightmonitor/gui/panels/function_notebook_panel.py @@ -3,8 +3,15 @@ Panel managing the area profiles, BBox input, and the function notebooks. """ import tkinter as tk -from tkinter import ttk, messagebox +from tkinter import ttk, messagebox, font as tkFont from typing import Dict, Any, Optional +import os + +try: + from PIL import Image, ImageTk + PIL_AVAILABLE = True +except ImportError: + PIL_AVAILABLE = False from ...utils.logger import get_logger from ...data import config as app_config @@ -13,6 +20,19 @@ from ...data.area_profile_manager import DEFAULT_PROFILE_NAME module_logger = get_logger(__name__) +ICON_PATH = os.path.join(os.path.dirname(__file__), '..', '..', 'assets', 'icons') +PLAY_ICON_PATH = os.path.join(ICON_PATH, 'play_icon.png') +STOP_ICON_PATH = os.path.join(ICON_PATH, 'stop_icon.png') + +# Definiamo i colori per i bottoni +COLOR_START_BG = "#28a745" # Verde +COLOR_START_ACTIVE = "#218838" +COLOR_STOP_BG = "#dc3545" # Rosso +COLOR_STOP_ACTIVE = "#c82333" +COLOR_DISABLED_BG = "#e0e0e0" # Grigio chiaro +COLOR_DISABLED_FG = "#a0a0a0" # Grigio scuro per il testo +COLOR_TEXT = "black" + class FunctionNotebookPanel: """ Manages the combined Area Profiles, BBox, and Function Notebooks panel. @@ -21,7 +41,10 @@ class FunctionNotebookPanel: self.parent_frame = parent_frame self.controller = controller - # --- Tkinter Variables --- + self.play_icon: Optional[tk.PhotoImage] = None + self.stop_icon: Optional[tk.PhotoImage] = None + + # ... (il resto del costruttore rimane uguale) ... self.lat_min_var = tk.StringVar() self.lon_min_var = tk.StringVar() self.lat_max_var = tk.StringVar() @@ -30,51 +53,62 @@ class FunctionNotebookPanel: self._build_ui() self.update_profile_list() + + # Seleziona il valore nella combobox, ma non carica ancora i dati self.set_selected_profile(DEFAULT_PROFILE_NAME) + + # RIMOSSA: La chiamata a _on_profile_selected() viene ora gestita da MainWindow module_logger.debug("FunctionNotebookPanel (unified) initialized.") + def _load_icons(self): + if not PIL_AVAILABLE: return + try: + icon_size = (32, 32) # Icone più grandi + play_img = Image.open(PLAY_ICON_PATH).resize(icon_size, Image.Resampling.LANCZOS) + self.play_icon = ImageTk.PhotoImage(play_img) + + stop_img = Image.open(STOP_ICON_PATH).resize(icon_size, Image.Resampling.LANCZOS) + self.stop_icon = ImageTk.PhotoImage(stop_img) + except Exception as e: + module_logger.warning(f"Could not load icons: {e}. Buttons will be text-only.") + def _build_ui(self): + self._load_icons() + button_font = tkFont.Font(family="Helvetica", size=10, weight="bold") + # --- Main Container for Area Management --- area_frame = ttk.LabelFrame(self.parent_frame, text="Area Profiles & BBox", padding=10) area_frame.pack(side=tk.TOP, fill=tk.X, padx=2, pady=(0, 5)) # Configure grid for the area frame area_frame.columnconfigure(1, weight=1) + # MODIFICA: Assegna lo stesso peso anche alla quarta colonna + area_frame.columnconfigure(3, weight=1) # --- Row 0: Profile Selection and Buttons --- profile_controls_frame = ttk.Frame(area_frame) profile_controls_frame.grid(row=0, column=0, columnspan=4, sticky="ew", pady=(0, 10)) - profile_controls_frame.columnconfigure(0, weight=1) # Let combobox expand - - self.profile_combobox = ttk.Combobox( - profile_controls_frame, textvariable=self.selected_profile_var, state="readonly" - ) + profile_controls_frame.columnconfigure(0, weight=1) + + self.profile_combobox = ttk.Combobox(profile_controls_frame, textvariable=self.selected_profile_var, state="readonly") self.profile_combobox.grid(row=0, column=0, sticky="ew", padx=(0, 5)) self.profile_combobox.bind("<>", self._on_profile_selected) - new_button = ttk.Button(profile_controls_frame, text="New", command=self._on_new_profile, width=5) new_button.grid(row=0, column=1, padx=(0, 2)) - save_button = ttk.Button(profile_controls_frame, text="Save", command=self._on_save_profile, width=5) save_button.grid(row=0, column=2, padx=(0, 2)) - delete_button = ttk.Button(profile_controls_frame, text="Delete", command=self._on_delete_profile, width=7) delete_button.grid(row=0, column=3) - - # --- Row 1 & 2: Bounding Box Entries --- ttk.Label(area_frame, text="Lat Min:").grid(row=1, column=0, padx=(0, 2), pady=2, sticky=tk.W) self.lat_min_entry = ttk.Entry(area_frame, textvariable=self.lat_min_var) self.lat_min_entry.grid(row=1, column=1, padx=(0, 5), pady=2, sticky=tk.EW) - ttk.Label(area_frame, text="Lon Min:").grid(row=1, column=2, padx=(5, 2), pady=2, sticky=tk.W) self.lon_min_entry = ttk.Entry(area_frame, textvariable=self.lon_min_var) self.lon_min_entry.grid(row=1, column=3, padx=(0, 0), pady=2, sticky=tk.EW) - ttk.Label(area_frame, text="Lat Max:").grid(row=2, column=0, padx=(0, 2), pady=2, sticky=tk.W) self.lat_max_entry = ttk.Entry(area_frame, textvariable=self.lat_max_var) self.lat_max_entry.grid(row=2, column=1, padx=(0, 5), pady=2, sticky=tk.EW) - ttk.Label(area_frame, text="Lon Max:").grid(row=2, column=2, padx=(5, 2), pady=2, sticky=tk.W) self.lon_max_entry = ttk.Entry(area_frame, textvariable=self.lon_max_var) self.lon_max_entry.grid(row=2, column=3, padx=(0, 0), pady=2, sticky=tk.EW) @@ -84,44 +118,81 @@ class FunctionNotebookPanel: self.function_notebook.pack(side=tk.TOP, fill=tk.BOTH, expand=True, padx=2, pady=2) # --- Live Tab --- - live_tab_frame = ttk.Frame(self.function_notebook, padding=10) + live_tab_frame = ttk.Frame(self.function_notebook, padding=(0, 10, 0, 0)) # Aggiunto padding self.function_notebook.add(live_tab_frame, text="Live Monitor") - self.start_live_button = ttk.Button(live_tab_frame, text="Start Live Monitoring", command=self._on_start_live_monitoring) - self.start_live_button.pack(side=tk.LEFT, padx=5, pady=5) - self.stop_live_button = ttk.Button(live_tab_frame, text="Stop Live Monitoring", command=self._on_stop_live_monitoring, state=tk.DISABLED) - self.stop_live_button.pack(side=tk.LEFT, padx=5, pady=5) - # --- Historical Download Tab --- + # Usiamo pack per un controllo migliore sull'allineamento verticale + button_container = ttk.Frame(live_tab_frame) + button_container.pack(side=tk.TOP, fill=tk.X, expand=False, anchor='n') + + # Frame interni per centrare i bottoni orizzontalmente + left_spacer = ttk.Frame(button_container) + left_spacer.pack(side=tk.LEFT, expand=True) + + self.start_live_button = tk.Button( + button_container, + text="Start Live", + image=self.play_icon, + compound=tk.TOP, + command=self._on_start_live_monitoring, + font=button_font, + bg=COLOR_START_BG, + fg=COLOR_TEXT, + activebackground=COLOR_START_ACTIVE, + activeforeground=COLOR_TEXT, + relief=tk.RAISED, + borderwidth=2, + padx=10, + pady=5 + ) + self.start_live_button.pack(side=tk.LEFT, padx=15, pady=5) + + self.stop_live_button = tk.Button( + button_container, + text="Stop Live", + image=self.stop_icon, + compound=tk.TOP, + command=self._on_stop_live_monitoring, + font=button_font, + bg=COLOR_DISABLED_BG, + fg=COLOR_DISABLED_FG, + activebackground=COLOR_DISABLED_BG, + activeforeground=COLOR_DISABLED_FG, + state=tk.DISABLED, + relief=tk.RAISED, + borderwidth=2, + padx=10, + pady=5 + ) + self.stop_live_button.pack(side=tk.LEFT, padx=15, pady=5) + + right_spacer = ttk.Frame(button_container) + right_spacer.pack(side=tk.LEFT, expand=True) + + # --- Altri Tab (invariati) --- download_tab_frame = ttk.Frame(self.function_notebook, padding=10) self.function_notebook.add(download_tab_frame, text="Historical Download") ttk.Label(download_tab_frame, text="Historical download controls...").pack() - # --- Playback Tab --- playback_tab_frame = ttk.Frame(self.function_notebook, padding=10) self.function_notebook.add(playback_tab_frame, text="Playback") ttk.Label(playback_tab_frame, text="Playback controls...").pack() self.function_notebook.bind("<>", self._on_tab_change) - # --- Event Handlers --- + # --- Event Handlers (invariati) --- def _on_start_live_monitoring(self): if self.controller: self.controller.start_live_monitoring() - def _on_stop_live_monitoring(self): if self.controller: self.controller.stop_live_monitoring() - def _on_profile_selected(self, event=None): selected_name = self.selected_profile_var.get() - if selected_name and self.controller: - self.controller.load_area_profile(selected_name) - + if selected_name and self.controller: self.controller.load_area_profile(selected_name) def _on_new_profile(self): self.selected_profile_var.set("") self.update_bbox_gui_fields({}) - def _on_save_profile(self): if self.controller: self.controller.save_current_area_as_profile() - def _on_delete_profile(self): profile_to_delete = self.selected_profile_var.get() if not profile_to_delete or profile_to_delete == DEFAULT_PROFILE_NAME: @@ -129,14 +200,40 @@ class FunctionNotebookPanel: return if messagebox.askyesno("Confirm Delete", f"Delete profile '{profile_to_delete}'?", parent=self.parent_frame): if self.controller: self.controller.delete_area_profile(profile_to_delete) - def _on_tab_change(self, event=None): - if not self.function_notebook: return - tab_text = self.function_notebook.tab(self.function_notebook.index("current"), "text") - if self.controller and hasattr(self.controller, "on_function_tab_changed"): - self.controller.on_function_tab_changed(tab_text) + if self.function_notebook: + tab_text = self.function_notebook.tab(self.function_notebook.index("current"), "text") + if self.controller: self.controller.on_function_tab_changed(tab_text) - # --- Public Methods --- + # --- Public Methods (modificata set_monitoring_button_states) --- + def set_monitoring_button_states(self, is_monitoring_active: bool): + """Sets the state and style of the Start/Stop buttons.""" + if is_monitoring_active: + # Monitoring ATTIVO + if self.start_live_button: + self.start_live_button.config( + state=tk.DISABLED, bg=COLOR_DISABLED_BG, fg=COLOR_DISABLED_FG, + activebackground=COLOR_DISABLED_BG, activeforeground=COLOR_DISABLED_FG + ) + if self.stop_live_button: + self.stop_live_button.config( + state=tk.NORMAL, bg=COLOR_STOP_BG, fg=COLOR_TEXT, + activebackground=COLOR_STOP_ACTIVE, activeforeground=COLOR_TEXT + ) + else: + # Monitoring FERMO + if self.start_live_button: + self.start_live_button.config( + state=tk.NORMAL, bg=COLOR_START_BG, fg=COLOR_TEXT, + activebackground=COLOR_START_ACTIVE, activeforeground=COLOR_TEXT + ) + if self.stop_live_button: + self.stop_live_button.config( + state=tk.DISABLED, bg=COLOR_DISABLED_BG, fg=COLOR_DISABLED_FG, + activebackground=COLOR_DISABLED_BG, activeforeground=COLOR_DISABLED_FG + ) + + # --- Altri metodi pubblici (invariati) --- def update_profile_list(self): if self.controller: profile_names = self.controller.get_profile_names() @@ -144,24 +241,21 @@ class FunctionNotebookPanel: self.set_selected_profile(self.selected_profile_var.get() or DEFAULT_PROFILE_NAME) def set_selected_profile(self, profile_name: str): - if profile_name in self.profile_combobox["values"]: + if self.profile_combobox["values"] and profile_name in self.profile_combobox["values"]: self.selected_profile_var.set(profile_name) elif self.profile_combobox["values"]: self.selected_profile_var.set(self.profile_combobox["values"][0]) - + def get_bounding_box_input(self): - # ... (metodo rimane invariato) try: bbox_candidate = { "lat_min": float(self.lat_min_var.get()), "lon_min": float(self.lon_min_var.get()), "lat_max": float(self.lat_max_var.get()), "lon_max": float(self.lon_max_var.get()), } return bbox_candidate if _is_valid_bbox_dict(bbox_candidate) else None - except (ValueError, TypeError): - return None + except (ValueError, TypeError): return None def update_bbox_gui_fields(self, bbox_dict: Dict[str, float]): - # ... (metodo rimane invariato) if bbox_dict and _is_valid_bbox_dict(bbox_dict): decimals = getattr(app_config, "COORDINATE_DECIMAL_PLACES", 5) self.lat_min_var.set(f"{bbox_dict['lat_min']:.{decimals}f}") @@ -169,27 +263,14 @@ class FunctionNotebookPanel: self.lat_max_var.set(f"{bbox_dict['lat_max']:.{decimals}f}") self.lon_max_var.set(f"{bbox_dict['lon_max']:.{decimals}f}") else: - self.lat_min_var.set("") - self.lon_min_var.set("") - self.lat_max_var.set("") - self.lon_max_var.set("") + self.lat_min_var.set(""), self.lon_min_var.set(""), self.lat_max_var.set(""), self.lon_max_var.set("") - def set_monitoring_button_states(self, is_monitoring_active: bool): - # ... (metodo rimane invariato) - if self.start_live_button and self.start_live_button.winfo_exists(): - self.start_live_button.config(state=tk.DISABLED if is_monitoring_active else tk.NORMAL) - if self.stop_live_button and self.stop_live_button.winfo_exists(): - self.stop_live_button.config(state=tk.NORMAL if is_monitoring_active else tk.DISABLED) - def set_controls_state(self, enabled: bool): state = tk.NORMAL if enabled else tk.DISABLED readonly_state = "readonly" if enabled else tk.DISABLED - self.profile_combobox.config(state=readonly_state) for entry in [self.lat_min_entry, self.lon_min_entry, self.lat_max_entry, self.lon_max_entry]: if entry.winfo_exists(): entry.config(state=state) - - # Abilita/Disabilita i bottoni dei profili for child in self.profile_combobox.master.winfo_children(): if isinstance(child, ttk.Button): child.config(state=state) \ No newline at end of file