aggiunte info ownship su tab simulazione

This commit is contained in:
VALLONGOL 2025-11-05 09:29:27 +01:00
parent 0de5beb93b
commit ff7000796a
2 changed files with 104 additions and 57 deletions

View File

@ -622,11 +622,15 @@ class MainView(tk.Tk):
if az_deg is not None: if az_deg is not None:
self.ppi_widget.update_antenna_azimuth(az_deg, timestamp=az_ts) self.ppi_widget.update_antenna_azimuth(az_deg, timestamp=az_ts)
# Update ownship orientation for the PPI display # Update ownship state for both PPI orientation and status display
ownship_state = self.simulation_hub.get_ownship_state() ownship_state = self.simulation_hub.get_ownship_state()
if ownship_state: if ownship_state:
ownship_heading = ownship_state.get("heading_deg", 0.0) ownship_heading = ownship_state.get("heading_deg", 0.0)
self.ppi_widget.update_ownship_state(ownship_heading) self.ppi_widget.update_ownship_state(ownship_heading)
self.simulation_controls.update_ownship_display(ownship_state)
else:
# Ensure display is cleared if no ownship data is present
self.simulation_controls.update_ownship_display({})
if sim_is_running_now: if sim_is_running_now:

View File

@ -1,76 +1,71 @@
# target_simulator/gui/simulation_controls.py
import tkinter as tk import tkinter as tk
from tkinter import ttk, messagebox from tkinter import ttk
from typing import Optional from typing import Dict, Any
from target_simulator.core.models import FPS_TO_KNOTS
class SimulationControls(ttk.LabelFrame): class SimulationControls(ttk.LabelFrame):
"""Encapsulates the Live Simulation Engine controls. """
Encapsulates the Live Simulation Engine controls and ownship status display.
This keeps the UI widgets (Start/Stop, Speed, Update Time, Reset, slider)
in a focused component. It uses the provided main_view reference for
callbacks and shared Tk variables to preserve existing behavior while
keeping the layout code out of `main_view.py`.
""" """
def __init__(self, parent, main_view): def __init__(self, parent, main_view):
super().__init__(parent, text="Live Simulation Engine") super().__init__(parent, text="Live Simulation Engine")
self.main_view = main_view self.main_view = main_view
# Use main_view's variables so external code referencing them keeps # --- Variables for UI Binding ---
# working unchanged.
self.time_multiplier_var = getattr(main_view, "time_multiplier_var", tk.StringVar(value="1x")) self.time_multiplier_var = getattr(main_view, "time_multiplier_var", tk.StringVar(value="1x"))
self.update_time = getattr(main_view, "update_time", tk.DoubleVar(value=1.0)) self.update_time = getattr(main_view, "update_time", tk.DoubleVar(value=1.0))
self.sim_slider_var = getattr(main_view, "sim_slider_var", tk.DoubleVar(value=0.0)) self.sim_slider_var = getattr(main_view, "sim_slider_var", tk.DoubleVar(value=0.0))
# Ownship display variables
self.lat_var = tk.StringVar(value="-")
self.lon_var = tk.StringVar(value="-")
self.alt_var = tk.StringVar(value="-")
self.hdg_var = tk.StringVar(value="-")
self.gnd_speed_var = tk.StringVar(value="-")
self.vert_speed_var = tk.StringVar(value="-")
# Layout grid setup # --- Widget Layout ---
self.grid_columnconfigure(0, weight=1) self.grid_columnconfigure(0, weight=1)
# Main controls frame # Main controls frame
controls_frame = ttk.Frame(self) controls_frame = ttk.Frame(self)
controls_frame.grid(row=0, column=0, sticky="ew", padx=5, pady=5) controls_frame.grid(row=0, column=0, sticky="ew", padx=5, pady=5)
controls_frame.grid_columnconfigure(3, weight=1)
# Configure columns inside the controls frame
for i in range(10):
controls_frame.grid_columnconfigure(i, weight=0)
controls_frame.grid_columnconfigure(3, weight=1) # Spacer
# Buttons
self.start_button = ttk.Button(controls_frame, text="Start Live", command=self._start) self.start_button = ttk.Button(controls_frame, text="Start Live", command=self._start)
self.start_button.grid(row=0, column=0, sticky="w") self.start_button.grid(row=0, column=0, sticky="w")
self.stop_button = ttk.Button(controls_frame, text="Stop Live", command=self._stop, state=tk.DISABLED) self.stop_button = ttk.Button(controls_frame, text="Stop Live", command=self._stop, state=tk.DISABLED)
self.stop_button.grid(row=0, column=1, sticky="w", padx=5) self.stop_button.grid(row=0, column=1, sticky="w", padx=5)
ttk.Frame(controls_frame).grid(row=0, column=3, sticky="ew") ttk.Frame(controls_frame).grid(row=0, column=2, sticky="ew", padx=10) # Spacer
ttk.Label(controls_frame, text="Speed:").grid(row=0, column=4, sticky="e", padx=(10, 2)) ttk.Label(controls_frame, text="Speed:").grid(row=0, column=4, sticky="e", padx=(10, 2))
self.multiplier_combo = ttk.Label(controls_frame, text="1x") self.multiplier_combo = ttk.Label(controls_frame, text="1x") # Placeholder, could be a combo
self.multiplier_combo.grid(row=0, column=5, sticky="w", padx=(0, 5)) self.multiplier_combo.grid(row=0, column=5, sticky="w")
ttk.Label(controls_frame, text="Update Time (s):").grid(row=0, column=6, sticky="e", padx=(10, 2)) ttk.Label(controls_frame, text="Update (s):").grid(row=0, column=6, sticky="e", padx=(10, 2))
self.update_time_entry = ttk.Entry(controls_frame, textvariable=self.update_time, width=5) self.update_time_entry = ttk.Entry(controls_frame, textvariable=self.update_time, width=5)
self.update_time_entry.grid(row=0, column=7, sticky="w", padx=(0, 5)) self.update_time_entry.grid(row=0, column=7, sticky="w")
self.reset_button = ttk.Button(controls_frame, text="Reset State", command=getattr(main_view, "_on_reset_simulation", lambda: None)) self.reset_button = ttk.Button(controls_frame, text="Reset Sim", command=getattr(main_view, "_on_reset_simulation", lambda: None))
self.reset_button.grid(row=0, column=8, sticky="e", padx=5) self.reset_button.grid(row=0, column=8, sticky="e", padx=10)
self.reset_radar_button = ttk.Button(controls_frame, text="Reset Radar", command=getattr(main_view, "_reset_radar_state", lambda: None)) self.reset_radar_button = ttk.Button(controls_frame, text="Reset Radar", command=getattr(main_view, "_reset_radar_state", lambda: None))
self.reset_radar_button.grid(row=0, column=9, sticky="e", padx=5) self.reset_radar_button.grid(row=0, column=9, sticky="e")
# Progress slider row # Progress slider row
progress_frame = ttk.Frame(self) progress_frame = ttk.Frame(self)
progress_frame.grid(row=1, column=0, columnspan=10, sticky="ew", padx=5, pady=(6, 2)) progress_frame.grid(row=1, column=0, sticky="ew", padx=5, pady=(6, 2))
progress_frame.grid_columnconfigure(0, weight=1) progress_frame.grid_columnconfigure(0, weight=1)
progress_frame.grid_columnconfigure(1, weight=0)
self.sim_slider = ttk.Scale( self.sim_slider = ttk.Scale(
progress_frame, progress_frame, orient=tk.HORIZONTAL, variable=self.sim_slider_var, from_=0.0, to=1.0
orient=tk.HORIZONTAL,
variable=self.sim_slider_var,
from_=0.0,
to=1.0,
command=lambda v: None,
) )
self.sim_slider.grid(row=0, column=0, sticky="ew", padx=(4, 8)) self.sim_slider.grid(row=0, column=0, sticky="ew", padx=(4, 8))
self.sim_slider.bind("<ButtonPress-1>", lambda e: setattr(main_view, "_slider_is_dragging", True)) self.sim_slider.bind("<ButtonPress-1>", lambda e: setattr(main_view, "_slider_is_dragging", True))
@ -83,43 +78,91 @@ class SimulationControls(ttk.LabelFrame):
) )
labels_frame = ttk.Frame(progress_frame) labels_frame = ttk.Frame(progress_frame)
labels_frame.grid(row=0, column=1, sticky="e", padx=(4, 4)) labels_frame.grid(row=0, column=1, sticky="e")
self.sim_elapsed_label = ttk.Label(labels_frame, text="0.0s", width=8, anchor=tk.E) self.sim_elapsed_label = ttk.Label(labels_frame, text="0.0s", width=8, anchor=tk.E)
self.sim_elapsed_label.grid(row=0, column=0) self.sim_elapsed_label.pack(side=tk.LEFT)
ttk.Label(labels_frame, text="/").grid(row=0, column=1, padx=(2, 2)) ttk.Label(labels_frame, text="/").pack(side=tk.LEFT, padx=2)
self.sim_total_label = ttk.Label(labels_frame, text="0.0s", width=8, anchor=tk.W) self.sim_total_label = ttk.Label(labels_frame, text="0.0s", width=8, anchor=tk.W)
self.sim_total_label.grid(row=0, column=2) self.sim_total_label.pack(side=tk.LEFT)
# --- Ownship State Display ---
ownship_frame = ttk.LabelFrame(self, text="Ownship State", padding=10)
ownship_frame.grid(row=2, column=0, sticky="ew", padx=5, pady=8)
ownship_frame.grid_columnconfigure(1, weight=1)
ownship_frame.grid_columnconfigure(3, weight=1)
ttk.Label(ownship_frame, text="Latitude:").grid(row=0, column=0, sticky="w")
ttk.Label(ownship_frame, textvariable=self.lat_var, anchor="w").grid(row=0, column=1, sticky="ew", padx=5)
ttk.Label(ownship_frame, text="Longitude:").grid(row=1, column=0, sticky="w")
ttk.Label(ownship_frame, textvariable=self.lon_var, anchor="w").grid(row=1, column=1, sticky="ew", padx=5)
ttk.Label(ownship_frame, text="Altitude:").grid(row=0, column=2, sticky="w", padx=(10, 0))
ttk.Label(ownship_frame, textvariable=self.alt_var, anchor="w").grid(row=0, column=3, sticky="ew", padx=5)
ttk.Label(ownship_frame, text="Heading:").grid(row=1, column=2, sticky="w", padx=(10, 0))
ttk.Label(ownship_frame, textvariable=self.hdg_var, anchor="w").grid(row=1, column=3, sticky="ew", padx=5)
ttk.Label(ownship_frame, text="Ground Speed:").grid(row=0, column=4, sticky="w", padx=(10, 0))
ttk.Label(ownship_frame, textvariable=self.gnd_speed_var, anchor="w").grid(row=0, column=5, sticky="ew", padx=5)
ttk.Label(ownship_frame, text="Vertical Speed:").grid(row=1, column=4, sticky="w", padx=(10, 0))
ttk.Label(ownship_frame, textvariable=self.vert_speed_var, anchor="w").grid(row=1, column=5, sticky="ew", padx=5)
# --- Non-modal notice area --- # --- Non-modal notice area ---
self.notice_var = tk.StringVar(value="") self.notice_var = tk.StringVar(value="")
self.notice_frame = ttk.Frame(self) self.notice_frame = ttk.Frame(self)
# This frame is placed at row=2, under the progress bar self.notice_frame.grid(row=3, column=0, sticky="ew", padx=5, pady=(5, 0))
self.notice_frame.grid(row=2, column=0, sticky="ew", padx=5, pady=(5, 0))
self.notice_frame.grid_remove() # Hidden by default self.notice_frame.grid_remove() # Hidden by default
self.notice_label = tk.Label( notice_label = tk.Label(
self.notice_frame, self.notice_frame, textvariable=self.notice_var, bg="#fff3cd",
textvariable=self.notice_var, fg="#6a4b00", anchor="w", relief=tk.SOLID, bd=1, padx=6, pady=2
bg="#fff3cd",
fg="#6a4b00",
anchor="w",
relief=tk.SOLID,
bd=1,
padx=6,
pady=2,
) )
self.notice_label.pack(side=tk.LEFT, fill=tk.X, expand=True) notice_label.pack(side=tk.LEFT, fill=tk.X, expand=True)
ttk.Button(self.notice_frame, text="Dismiss", command=self.hide_notice).pack(side=tk.RIGHT, padx=(6, 0))
self.dismiss_button = ttk.Button(self.notice_frame, text="Dismiss", command=self.hide_notice)
self.dismiss_button.pack(side=tk.RIGHT, padx=(6, 0)) def update_ownship_display(self, state: Dict[str, Any]):
"""Updates the labels in the Ownship State frame."""
if not state:
self.lat_var.set("-")
self.lon_var.set("-")
self.alt_var.set("-")
self.hdg_var.set("-")
self.gnd_speed_var.set("-")
self.vert_speed_var.set("-")
return
# Latitude / Longitude
lat = state.get('latitude', 0.0)
lon = state.get('longitude', 0.0)
self.lat_var.set(f"{abs(lat):.5f}° {'N' if lat >= 0 else 'S'}")
self.lon_var.set(f"{abs(lon):.5f}° {'E' if lon >= 0 else 'W'}")
# Altitude
alt_ft = state.get('altitude_ft', 0.0)
self.alt_var.set(f"{alt_ft:.1f} ft")
# Heading
hdg_deg = state.get('heading_deg', 0.0)
self.hdg_var.set(f"{hdg_deg:.2f}°")
# Ground Speed
vx_fps, vy_fps = state.get('velocity_xy_fps', (0.0, 0.0))
gnd_speed_kn = (vx_fps**2 + vy_fps**2)**0.5 * FPS_TO_KNOTS
self.gnd_speed_var.set(f"{gnd_speed_kn:.1f} kn")
# Vertical Speed
vz_fps = state.get('velocity_z_fps', 0.0) # Assuming 'vz' is part of state
self.vert_speed_var.set(f"{vz_fps:+.1f} ft/s")
def show_notice(self, message: str): def show_notice(self, message: str):
"""Displays the notification bar with a message."""
self.notice_var.set(message) self.notice_var.set(message)
self.notice_frame.grid() self.notice_frame.grid()
def hide_notice(self): def hide_notice(self):
"""Hides the notification bar."""
self.notice_var.set("") self.notice_var.set("")
self.notice_frame.grid_remove() self.notice_frame.grid_remove()