# --- START OF FILE ui.py --- # ui.py """ THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. Defines the user interface components for the Control Panel application, including the main control panel area, status bar, map parameters, info display with Google Maps/Earth links, and helper functions for window creation. The main ControlPanel frame is designed to be placed within a container managed by the main application. The metadata display components are now created and managed directly by the main application (ControlPanelApp). """ # Standard library imports import logging from typing import TYPE_CHECKING, Dict, Tuple, Optional # Third-party imports import tkinter as tk from tkinter import ttk # Local application imports from controlpanel import config # Type hinting for App reference if TYPE_CHECKING: # Assuming ControlPanelApp is defined in ControlPanel.py from controlpanel.app_main import ControlPanelApp class ControlPanel(ttk.Frame): # This is the main panel holding user controls """ Main control panel frame containing SAR, MFD, Map parameter widgets, information displays, statistics labels, and interaction buttons. This frame is typically placed in the main application window's container. """ def __init__(self, parent: tk.Widget, app: "ControlPanelApp", *args, **kwargs): """Initializes the ControlPanel frame.""" log_prefix = "[UI Setup]" logging.debug(f"{log_prefix} Initializing ControlPanel frame...") super().__init__(parent, *args, **kwargs) self.app: "ControlPanelApp" = app # --- StringVars for UI elements --- self.sar_center_coords_var = tk.StringVar(value="Lat=N/A, Lon=N/A") self.sar_orientation_var = tk.StringVar(value="N/A") self.sar_size_km_var = tk.StringVar(value="N/A") self.mouse_coords_var = tk.StringVar(value="Lat=N/A, Lon=N/A") self.map_mouse_coords_var = tk.StringVar(value="Lat=N/A, Lon=N/A") self.sar_lat_shift_var = tk.StringVar( value=f"{self.app.state.sar_lat_shift_deg:.6f}" ) self.sar_lon_shift_var = tk.StringVar( value=f"{self.app.state.sar_lon_shift_deg:.6f}" ) self.dropped_stats_var = tk.StringVar(value="Drop (Q): S=0, M=0, Tk=0, Mo=0") self.incomplete_stats_var = tk.StringVar(value="Incmpl (RX): S=0, M=0") self.show_meta_var = tk.BooleanVar(value=self.app.state.display_sar_metadata) self.sar_center_elevation_var = tk.StringVar(value="Elev: N/A") self.sar_mouse_elevation_var = tk.StringVar(value="Elev: N/A") self.map_mouse_elevation_var = tk.StringVar(value="Elev: N/A") # --- References to UI widgets --- self.mfd_color_labels: Dict[str, tk.Label] = {} # --- Initialize UI structure --- self.init_ui() logging.debug(f"{log_prefix} ControlPanel frame initialization complete.") # --- UI Construction Method --- def init_ui(self): """Initializes and arranges the user interface widgets within this frame.""" log_prefix = "[UI Setup]" logging.debug(f"{log_prefix} Starting init_ui widget creation...") # --- 1. SAR Parameters Frame --- # ... (Questa sezione rimane invariata) ... self.sar_params_frame = ttk.Labelframe(self, text="SAR Parameters", padding=5) self.sar_params_frame.pack(side=tk.TOP, fill=tk.X, padx=5, pady=(5, 2)) sar_row = 0 self.test_image_var = tk.IntVar(value=1 if config.ENABLE_TEST_MODE else 0) self.test_image_check = ttk.Checkbutton( self.sar_params_frame, text="Test Image", variable=self.test_image_var, command=self.app.update_image_mode, ) self.test_image_check.grid(row=sar_row, column=0, columnspan=2, sticky=tk.W, padx=5, pady=2) self.record_sar_var = tk.BooleanVar(value=config.DEFAULT_SAR_RECORDING_ENABLED) self.record_sar_check = ttk.Checkbutton( self.sar_params_frame, text="Record SAR", variable=self.record_sar_var, command=self.app.toggle_sar_recording, ) self.record_sar_check.grid(row=sar_row, column=2, columnspan=2, sticky=tk.W, padx=5, pady=2) sar_row += 1 self.sar_size_label = ttk.Label(self.sar_params_frame, text="Size:") self.sar_size_label.grid(row=sar_row, column=0, sticky=tk.W, padx=(5, 2), pady=1) self.sar_size_combo = ttk.Combobox( self.sar_params_frame, values=config.SAR_SIZE_FACTORS, state="readonly", width=6, ) try: factor = 1 if self.app.state.sar_display_width > 0: factor = max(1, config.SAR_WIDTH // self.app.state.sar_display_width) sz_str = f"1:{factor}" if sz_str in config.SAR_SIZE_FACTORS: self.sar_size_combo.set(sz_str) else: self.sar_size_combo.set(config.DEFAULT_SAR_SIZE) except Exception: self.sar_size_combo.set(config.DEFAULT_SAR_SIZE) self.sar_size_combo.grid(row=sar_row, column=1, sticky=tk.EW, padx=(0, 10), pady=1) self.sar_size_combo.bind("<>", self.app.update_sar_size) self.palette_label = ttk.Label(self.sar_params_frame, text="Palette:") self.palette_label.grid(row=sar_row, column=2, sticky=tk.W, padx=(0, 2), pady=1) self.palette_combo = ttk.Combobox( self.sar_params_frame, values=config.COLOR_PALETTES, state="readonly", width=8, ) self.palette_combo.set(self.app.state.sar_palette) self.palette_combo.grid(row=sar_row, column=3, sticky=tk.EW, padx=(0, 5), pady=1) self.palette_combo.bind("<>", self.app.update_sar_palette) sar_row += 1 self.contrast_label = ttk.Label(self.sar_params_frame, text="Contrast:") self.contrast_label.grid(row=sar_row, column=0, sticky=tk.W, padx=(5, 2), pady=1) self.contrast_scale = ttk.Scale( self.sar_params_frame, orient=tk.HORIZONTAL, from_=0.1, to=3.0, value=self.app.state.sar_contrast, command=self.app.update_contrast, ) self.contrast_scale.grid(row=sar_row, column=1, sticky=tk.EW, padx=(0, 10), pady=1) self.brightness_label = ttk.Label(self.sar_params_frame, text="Brightness:") self.brightness_label.grid(row=sar_row, column=2, sticky=tk.W, padx=(0, 2), pady=1) self.brightness_scale = ttk.Scale( self.sar_params_frame, orient=tk.HORIZONTAL, from_=-100, to=100, value=self.app.state.sar_brightness, command=self.app.update_brightness, ) self.brightness_scale.grid(row=sar_row, column=3, sticky=tk.EW, padx=(0, 5), pady=1) sar_row += 1 self.show_meta_check = ttk.Checkbutton( self.sar_params_frame, text="Show SAR Metadata", variable=self.show_meta_var, command=self.app.toggle_sar_metadata_display, ) self.show_meta_check.grid(row=sar_row, column=0, columnspan=4, sticky=tk.W, padx=5, pady=(5, 2)) self.sar_params_frame.columnconfigure(1, weight=1) self.sar_params_frame.columnconfigure(3, weight=1) # --- 2. MFD Parameters Frame --- # ... (Questa sezione rimane invariata) ... self.mfd_params_frame = ttk.Labelframe(self, text="MFD Parameters", padding=5) self.mfd_params_frame.pack(side=tk.TOP, fill=tk.X, padx=5, pady=2) mfd_categories_ordered = ["Occlusion", "Cat A", "Cat B", "Cat C", "Cat C1", "Cat C2", "Cat C3"] num_categories = len(mfd_categories_ordered) for index, name in enumerate(mfd_categories_ordered): row = index // 2 col_offset = 0 if (index % 2 == 0) else 4 cat_label = ttk.Label(self.mfd_params_frame, text=f"{name}:") cat_label.grid(row=row, column=0 + col_offset, sticky=tk.W, padx=(5,1), pady=1) intensity_var = tk.IntVar(value=config.DEFAULT_MFD_INTENSITY) try: intensity_var.set(self.app.state.mfd_params["categories"][name]["intensity"]) except Exception: pass intensity_scale = ttk.Scale( self.mfd_params_frame, orient=tk.HORIZONTAL, length=100, from_=0, to=255, variable=intensity_var, command=lambda v, n=name, var=intensity_var: self.app.update_mfd_category_intensity(n, var.get()), ) intensity_scale.grid(row=row, column=1 + col_offset, sticky=tk.EW, padx=1, pady=1) color_button = ttk.Button( self.mfd_params_frame, text="Color", width=5, command=lambda n=name: self.app.choose_mfd_category_color(n), ) color_button.grid(row=row, column=2 + col_offset, sticky=tk.W, padx=1, pady=1) color_label = tk.Label(self.mfd_params_frame, text="", width=3, relief=tk.SUNKEN, borderwidth=1) try: bgr = self.app.state.mfd_params["categories"][name]["color"] hex_color = f"#{bgr[2]:02x}{bgr[1]:02x}{bgr[0]:02x}" color_label.config(background=hex_color) except Exception: color_label.config(background="grey") color_label.grid(row=row, column=3 + col_offset, sticky=tk.W, padx=(1,5), pady=1) self.mfd_color_labels[name] = color_label last_cat_row = (num_categories -1) // 2 raw_map_col_offset = 4 if (num_categories % 2 != 0) else 0 raw_map_row = last_cat_row if (num_categories % 2 != 0) else last_cat_row + 1 raw_map_label = ttk.Label(self.mfd_params_frame, text="Raw Map:") raw_map_label.grid(row=raw_map_row, column=0 + raw_map_col_offset, sticky=tk.W, padx=(5,1), pady=1) raw_map_intensity_var = tk.IntVar(value=config.DEFAULT_MFD_RAW_MAP_INTENSITY) try: raw_map_intensity_var.set(self.app.state.mfd_params["raw_map_intensity"]) except Exception: pass self.mfd_raw_map_intensity_var = raw_map_intensity_var raw_map_scale = ttk.Scale( self.mfd_params_frame, orient=tk.HORIZONTAL, length=100, from_=0, to=255, variable=raw_map_intensity_var, command=lambda v: self.app.update_mfd_raw_map_intensity(raw_map_intensity_var.get()), ) raw_map_scale.grid(row=raw_map_row, column=1 + raw_map_col_offset, columnspan=3, sticky=tk.EW, padx=(1,5), pady=1) self.mfd_params_frame.columnconfigure(1, weight=1) self.mfd_params_frame.columnconfigure(5, weight=1) # --- 3. Map Parameters Frame --- # ... (Questa sezione rimane invariata) ... self.map_params_frame = ttk.Labelframe(self, text="Map Parameters", padding=5) self.map_params_frame.pack(side=tk.TOP, fill=tk.X, padx=5, pady=2) map_row = 0 self.map_size_label = ttk.Label(self.map_params_frame, text="Map Display Size:") self.map_size_label.grid(row=map_row, column=0, sticky=tk.W, padx=(5,2), pady=1) self.map_size_combo = ttk.Combobox( self.map_params_frame, values=config.MAP_SIZE_FACTORS, state="readonly", width=6, ) self.map_size_combo.set(config.DEFAULT_MAP_SIZE) self.map_size_combo.grid(row=map_row, column=1, sticky=tk.EW, padx=(2,10), pady=1) self.map_size_combo.bind("<>", self.app.update_map_size) self.save_map_button = ttk.Button( self.map_params_frame, text="Save Map View", command=self.app.save_current_map_view, ) self.save_map_button.grid(row=map_row, column=2, columnspan=4, sticky=tk.E, padx=5, pady=1) map_row += 1 self.sar_overlay_var = tk.BooleanVar(value=self.app.state.map_sar_overlay_enabled) self.sar_overlay_check = ttk.Checkbutton( self.map_params_frame, text="Show SAR Overlay on Map", variable=self.sar_overlay_var, command=self.app.toggle_sar_overlay, ) self.sar_overlay_check.grid(row=map_row, column=0, columnspan=2, sticky=tk.W, padx=5, pady=2) map_row += 1 self.alpha_label = ttk.Label(self.map_params_frame, text="SAR Overlay Alpha:") self.alpha_label.grid(row=map_row, column=0, sticky=tk.W, padx=(5,2), pady=1) self.sar_overlay_alpha_var = tk.DoubleVar(value=self.app.state.map_sar_overlay_alpha) self.alpha_scale = ttk.Scale( self.map_params_frame, orient=tk.HORIZONTAL, from_=0.0, to=1.0, variable=self.sar_overlay_alpha_var, ) self.alpha_scale.bind("", self.app.on_alpha_slider_release) self.alpha_scale.grid(row=map_row, column=1, columnspan=5, sticky=tk.EW, padx=(0,5), pady=1) map_row += 1 shift_label = ttk.Label(self.map_params_frame, text="SAR Shift (deg):") shift_label.grid(row=map_row, column=0, sticky=tk.W, padx=(5,2), pady=1) lat_label = ttk.Label(self.map_params_frame, text="Lat:") lat_label.grid(row=map_row, column=1, sticky=tk.W, padx=(0,0), pady=1) self.lat_shift_entry = ttk.Entry( self.map_params_frame, textvariable=self.sar_lat_shift_var, width=10 ) self.lat_shift_entry.grid(row=map_row, column=2, sticky=tk.W, padx=(0,5), pady=1) lon_label = ttk.Label(self.map_params_frame, text="Lon:") lon_label.grid(row=map_row, column=3, sticky=tk.W, padx=(5,0), pady=1) self.lon_shift_entry = ttk.Entry( self.map_params_frame, textvariable=self.sar_lon_shift_var, width=10 ) self.lon_shift_entry.grid(row=map_row, column=4, sticky=tk.W, padx=(0,5), pady=1) self.apply_shift_button = ttk.Button( self.map_params_frame, text="Apply Shift", command=self.app.apply_sar_overlay_shift, ) self.apply_shift_button.grid(row=map_row, column=5, sticky=tk.E, padx=(5,5), pady=1) self.map_params_frame.columnconfigure(2, weight=1) self.map_params_frame.columnconfigure(4, weight=1) # --- 4. Info Display Frame (MODIFIED) --- self.info_display_frame = ttk.Labelframe(self, text="Info Display", padding=5) self.info_display_frame.pack(side=tk.TOP, fill=tk.X, padx=5, pady=2) info_row = 0 button_width = 3 entry_width_coords = 30 # Adjusted width for coords + elevation entry_width_orient = 10 entry_width_size = 18 entry_width_stats_drop = 28 entry_width_stats_incmpl = 15 entry_width_elevation = 15 # Width for elevation labels # --- Row 0: SAR Center Coords & Elevation --- ref_label = ttk.Label(self.info_display_frame, text="SAR Center:") ref_label.grid(row=info_row, column=0, sticky=tk.W, padx=(5, 2), pady=1) self.sar_center_entry = ttk.Entry( self.info_display_frame, textvariable=self.sar_center_coords_var, state="readonly", width=entry_width_coords ) self.sar_center_entry.grid(row=info_row, column=1, columnspan=2, sticky=tk.EW, padx=(0, 2), pady=1) # --- >>> NEW: SAR Center Elevation Label <<< --- self.sar_center_elev_label = ttk.Label( self.info_display_frame, textvariable=self.sar_center_elevation_var, width=entry_width_elevation, anchor=tk.W, relief=tk.SUNKEN, borderwidth=1 ) self.sar_center_elev_label.grid(row=info_row, column=3, sticky=tk.EW, padx=(2,2), pady=1) # --- >>> END NEW <<< --- self.ref_gmaps_button = ttk.Button( self.info_display_frame, text="Go", width=button_width, command=lambda: self.app.go_to_google_maps("sar_center") ) self.ref_gmaps_button.grid(row=info_row, column=4, sticky=tk.E, padx=(0, 1), pady=1) self.ref_gearth_button = ttk.Button( self.info_display_frame, text="GE", width=button_width, command=lambda: self.app.go_to_google_earth("sar_center") ) self.ref_gearth_button.grid(row=info_row, column=5, sticky=tk.E, padx=(0, 5), pady=1) info_row += 1 # --- Row 1: Image Orient & Image Size --- orient_label = ttk.Label(self.info_display_frame, text="Image Orient:") orient_label.grid(row=info_row, column=0, sticky=tk.W, padx=5, pady=1) self.sar_orientation_entry = ttk.Entry( self.info_display_frame, textvariable=self.sar_orientation_var, state="readonly", width=entry_width_orient ) self.sar_orientation_entry.grid(row=info_row, column=1, sticky=tk.EW, padx=(0, 5), pady=1) size_label = ttk.Label(self.info_display_frame, text="Image Size:") size_label.grid(row=info_row, column=2, sticky=tk.W, padx=(5, 2), pady=1) # Adjusted column self.sar_size_entry = ttk.Entry( self.info_display_frame, textvariable=self.sar_size_km_var, state="readonly", width=entry_width_size ) # Span across remaining columns for Go/GE alignment self.sar_size_entry.grid(row=info_row, column=3, columnspan=3, sticky=tk.EW, padx=(0, 5), pady=1) info_row += 1 # --- Row 2: SAR Mouse Coords & Elevation --- sar_mouse_label = ttk.Label(self.info_display_frame, text="SAR Mouse:") sar_mouse_label.grid(row=info_row, column=0, sticky=tk.W, padx=5, pady=1) self.mouse_latlon_entry = ttk.Entry( self.info_display_frame, textvariable=self.mouse_coords_var, state="readonly", width=entry_width_coords ) self.mouse_latlon_entry.grid(row=info_row, column=1, columnspan=2, sticky=tk.EW, padx=(0, 2), pady=1) # --- >>> NEW: SAR Mouse Elevation Label <<< --- self.sar_mouse_elev_label = ttk.Label( self.info_display_frame, textvariable=self.sar_mouse_elevation_var, width=entry_width_elevation, anchor=tk.W, relief=tk.SUNKEN, borderwidth=1 ) self.sar_mouse_elev_label.grid(row=info_row, column=3, sticky=tk.EW, padx=(2,2), pady=1) # --- >>> END NEW <<< --- self.sar_mouse_gmaps_button = ttk.Button( self.info_display_frame, text="Go", width=button_width, command=lambda: self.app.go_to_google_maps("sar_mouse") ) self.sar_mouse_gmaps_button.grid(row=info_row, column=4, sticky=tk.E, padx=(0, 1), pady=1) self.sar_mouse_gearth_button = ttk.Button( self.info_display_frame, text="GE", width=button_width, command=lambda: self.app.go_to_google_earth("sar_mouse") ) self.sar_mouse_gearth_button.grid(row=info_row, column=5, sticky=tk.E, padx=(0, 5), pady=1) info_row += 1 # --- Row 3: Map Mouse Coords & Elevation --- map_mouse_label = ttk.Label(self.info_display_frame, text="Map Mouse:") map_mouse_label.grid(row=info_row, column=0, sticky=tk.W, padx=5, pady=1) self.map_mouse_latlon_entry = ttk.Entry( self.info_display_frame, textvariable=self.map_mouse_coords_var, state="readonly", width=entry_width_coords ) self.map_mouse_latlon_entry.grid(row=info_row, column=1, columnspan=2, sticky=tk.EW, padx=(0, 2), pady=1) # --- >>> NEW: Map Mouse Elevation Label <<< --- self.map_mouse_elev_label = ttk.Label( self.info_display_frame, textvariable=self.map_mouse_elevation_var, width=entry_width_elevation, anchor=tk.W, relief=tk.SUNKEN, borderwidth=1 ) self.map_mouse_elev_label.grid(row=info_row, column=3, sticky=tk.EW, padx=(2,2), pady=1) # --- >>> END NEW <<< --- self.map_mouse_gmaps_button = ttk.Button( self.info_display_frame, text="Go", width=button_width, command=lambda: self.app.go_to_google_maps("map_mouse") ) self.map_mouse_gmaps_button.grid(row=info_row, column=4, sticky=tk.E, padx=(0, 1), pady=1) self.map_mouse_gearth_button = ttk.Button( self.info_display_frame, text="GE", width=button_width, command=lambda: self.app.go_to_google_earth("map_mouse") ) self.map_mouse_gearth_button.grid(row=info_row, column=5, sticky=tk.E, padx=(0, 5), pady=1) info_row += 1 # --- Row 4: Drop & Incomplete Stats --- dropped_label_text = ttk.Label(self.info_display_frame, text="Stats Drop:") dropped_label_text.grid(row=info_row, column=0, sticky=tk.W, padx=5, pady=1) self.dropped_entry = ttk.Entry( self.info_display_frame, textvariable=self.dropped_stats_var, state="readonly", width=entry_width_stats_drop ) self.dropped_entry.grid(row=info_row, column=1, columnspan=2, sticky=tk.EW, padx=(0, 5), pady=1) # Span 2 cols incomplete_label_text = ttk.Label(self.info_display_frame, text="Incomplete:") incomplete_label_text.grid(row=info_row, column=3, sticky=tk.W, padx=(5, 2), pady=1) # Start at col 3 self.incomplete_entry = ttk.Entry( self.info_display_frame, textvariable=self.incomplete_stats_var, state="readonly", width=entry_width_stats_incmpl ) self.incomplete_entry.grid(row=info_row, column=4, columnspan=2, sticky=tk.EW, padx=(0, 5), pady=1) # Span 2 cols info_row += 1 # --- Row 5: "GE All" Button --- self.ge_all_button = ttk.Button( self.info_display_frame, text="GE All", command=self.app.go_to_all_gearth ) self.ge_all_button.grid( row=info_row, column=0, columnspan=6, sticky=tk.EW, padx=5, pady=(5, 5) ) # Configure column weights for Info Display frame self.info_display_frame.columnconfigure(1, weight=1) # Coords entry self.info_display_frame.columnconfigure(2, weight=1) # Coords entry (continued for span) / Size Label self.info_display_frame.columnconfigure(3, weight=0) # Elevation Label / Size Entry / Incomplete Label self.info_display_frame.columnconfigure(4, weight=0) # Go Button / Size Entry / Incomplete Entry self.info_display_frame.columnconfigure(5, weight=0) # GE Button / Size Entry / Incomplete Entry logging.debug(f"{log_prefix} Info Display frame created with elevation labels.") logging.debug(f"{log_prefix} init_ui widget creation complete.") # --- UI Update Methods --- # ... (metodi set_sar_center_coords, set_mouse_coordinates, ecc. rimangono invariati) ... def set_sar_center_coords(self, latitude_str: str, longitude_str: str): text = f"Lat={latitude_str}, Lon={longitude_str}" try: self.sar_center_coords_var.set(text) except Exception as e: logging.warning(f"[UI Update] Error setting SAR center coords: {e}") def set_mouse_coordinates(self, latitude_str: str, longitude_str: str): text = f"Lat={latitude_str}, Lon={longitude_str}" try: self.mouse_coords_var.set(text) except Exception as e: logging.warning(f"[UI Update] Error setting SAR mouse coords: {e}") def set_map_mouse_coordinates(self, latitude_str: str, longitude_str: str): text = f"Lat={latitude_str}, Lon={longitude_str}" try: self.map_mouse_coords_var.set(text) except Exception as e: logging.warning(f"[UI Update] Error setting Map mouse coords: {e}") def set_sar_orientation(self, orientation_deg_str: str): try: self.sar_orientation_var.set(orientation_deg_str) except Exception as e: logging.warning(f"[UI Update] Error setting SAR orientation: {e}") def set_sar_size_km(self, size_text: str): try: self.sar_size_km_var.set(size_text) except Exception as e: logging.warning(f"[UI Update] Error setting SAR size: {e}") def set_statistics_display(self, dropped_text: str, incomplete_text: str): try: self.dropped_stats_var.set(dropped_text) self.incomplete_stats_var.set(incomplete_text) except Exception as e: logging.warning(f"[UI Update] Error setting stats display: {e}") def update_mfd_color_display(self, category_name: str, color_bgr_tuple: Tuple[int, int, int]): if category_name in self.mfd_color_labels: lbl = self.mfd_color_labels[category_name] hex_color = f"#{color_bgr_tuple[2]:02x}{color_bgr_tuple[1]:02x}{color_bgr_tuple[0]:02x}" try: if lbl.winfo_exists(): lbl.config(background=hex_color) except Exception as e: logging.exception(f"[UI Update] Error updating MFD color for {category_name}: {e}") def set_sar_center_elevation(self, elevation_text: str): """Updates the SAR Center elevation display label.""" try: # The text is now pre-formatted by app_main.py self.sar_center_elevation_var.set(elevation_text) except Exception as e: logging.warning(f"[UI Update] Error setting SAR center elevation: {e}") def set_sar_mouse_elevation(self, elevation_text: str): """Updates the SAR Mouse elevation display label.""" try: # The text is now pre-formatted by app_main.py self.sar_mouse_elevation_var.set(elevation_text) except Exception as e: logging.warning(f"[UI Update] Error setting SAR mouse elevation: {e}") def set_map_mouse_elevation(self, elevation_text: str): """Updates the Map Mouse elevation display label.""" try: # The text is now pre-formatted by app_main.py self.map_mouse_elevation_var.set(elevation_text) except Exception as e: logging.warning(f"[UI Update] Error setting Map mouse elevation: {e}") # --- StatusBar Class --- class StatusBar(ttk.Label): """Represents the status bar at the bottom of the main window.""" def __init__(self, parent: tk.Widget, *args, **kwargs): log_prefix = "[UI Setup]" logging.debug(f"{log_prefix} Initializing StatusBar...") super().__init__( parent, text=config.INITIAL_STATUS_MESSAGE, relief=tk.SUNKEN, anchor=tk.W, # Anchor text to the West (left) padding=(5, 2), # Add some internal padding *args, **kwargs, ) # Packed by the main application layout manager def set_status_text(self, text: str): """Sets the text displayed in the status bar.""" try: # Update text only if the widget still exists if self.winfo_exists(): self.config(text=text) except Exception: # Ignore errors during status update, especially during shutdown pass # --- Window Creation Helper --- def create_main_window( title: str, min_width: int, min_height: int, x_pos: int, y_pos: int ) -> tk.Tk: """Creates and configures the main Tkinter root window.""" log_prefix = "[UI Setup]" try: # Create the root window root = tk.Tk() # Set window title root.title(title) # Set minimum size constraint root.minsize(min_width, min_height) # Set initial position (may be overridden by OS window manager) # This is less critical now as the app constructor sets the final position root.geometry(f"+{x_pos}+{y_pos}") logging.debug( f"{log_prefix} Main Tkinter root window created (initial requested pos: {x_pos},{y_pos})." ) return root except Exception as e: logging.critical( f"{log_prefix} Failed to create main Tkinter window:", exc_info=True ) # Re-raise the exception to halt execution if window creation fails raise # --- END OF FILE ui.py ---