import tkinter as tk from tkinter import messagebox import logging logger = logging.getLogger(__name__) class UIController: def __init__(self, controller_main, view): # controller_main is a reference to the main KeyPressController instance self.controller_main = controller_main self.view = view logger.info("UIController: Initialized.") def initial_ui_setup_after_view_is_ready(self): """ Performs UI-specific setup that relies on the view being fully initialized. Called from controller.py after view reference is available. """ if self.view is None: logger.error("UIController: initial_ui_setup_after_view_is_ready called but view is None!") return logger.info("UIController: Performing post-view-initialization UI setup.") # Any view-dependent setup that was previously in KeyPressController's init_setup # that directly interacts with self.view now lives here. # Link View's StringVar traces for key input change self.view.key_to_press_var.trace_add("write", lambda name, index, mode: self._on_key_input_change()) # Initial refresh of windows list for the UI self.refresh_windows_ui() # Initial check of start button state based on UI inputs self._check_start_button_state_ui() def _on_key_input_change(self): """Handles changes in the key input field, informs main controller.""" self.controller_main.set_key_input_from_ui(self.view.get_key_input()) self._check_start_button_state_ui() def refresh_windows_ui(self): """ Refreshes the list of available windows in the View and updates Controller. Calls model via controller_main to get window titles. """ current_selection = self.view.get_selected_window_title() window_titles = self.controller_main.get_available_window_titles() # Get from model via main controller display_window_titles = ["--- Select a Window ---"] + window_titles if "--- Global Input (No Specific Window) ---" not in display_window_titles: display_window_titles.insert(1, "--- Global Input (No Specific Window) ---") new_selection = current_selection if new_selection not in display_window_titles: new_selection = "--- Select a Window ---" elif current_selection == "--- Global Input (No Specific Window) ---": new_selection = "--- Global Input (No Specific Window) ---" self.view.update_window_list(display_window_titles, new_selection) # Inform the main controller about the updated window selection self.controller_main.set_window_selection_from_ui(new_selection) logger.info(f"UIController: Refreshed window list. Found {len(window_titles)} active windows.") self._check_start_button_state_ui() def on_window_selected_ui(self): """Handles combobox selection event from View, informs main controller.""" selected_title = self.view.get_selected_window_title() self.controller_main.set_window_selection_from_ui(selected_title) self._check_start_button_state_ui() def _check_start_button_state_ui(self): """ Determines if the start button should be enabled based on UI input validation. Updates validation labels in the View directly. """ key_input_present = bool(self.view.get_key_input()) self.view.set_key_validation_visibility(not key_input_present) selected_option = self.view.get_selected_window_title() is_real_window_selected = (selected_option != "--- Select a Window ---" and selected_option in self.controller_main.get_available_window_titles()) is_global_input_selected = (selected_option == "--- Global Input (No Specific Window) ---") valid_window_selected_for_start = is_real_window_selected or is_global_input_selected self.view.set_window_validation_visibility(not valid_window_selected_for_start) if key_input_present and valid_window_selected_for_start: # Only enable the button if both are valid self.view.start_button.config(state=tk.NORMAL) logger.debug("UIController: Start button enabled.") else: self.view.start_button.config(state=tk.DISABLED) logger.debug("UIController: Start button disabled (validation error).") def show_ui_error_message(self, message): """Displays a messagebox error to the user via View.""" self.view.show_input_error(message) def set_ui_running_state(self): """Updates UI elements to reflect running state.""" self.view.set_ui_state_running() def set_ui_idle_state(self): """Updates UI elements to reflect idle state.""" self.view.set_ui_state_idle() self._check_start_button_state_ui() # Re-check after returning to idle to ensure proper button state