# Módulo: vista/panel_lateral.py import tkinter as tk from tkinter import ttk from tkinter import messagebox # --- Módulos de Lógica Existente --- # Asumiendo que estos módulos existen en la estructura lógica del proyecto from logica.controlador import accion_placeholder from logica.T1.backup import accion_backup_t1 from logica.T1.runVScode import abrir_vscode from logica.T1.openBrowser import navegar_a_url from logica.T2.scraping import hacer_scraping # --- Módulos de Vistas --- # Importamos la clase RadioPanel, que contiene los controles de música (Play/Pause y Volumen). from vista.central_panel.view_radio import RadioPanel from vista.config import * class PanelLateral(ttk.Frame): """ Panel lateral izquierdo de la aplicación. Contiene la barra de entrada, botones de lógica (Extracción, Navegación, Backup) y los controles de música esenciales. """ # Usamos la constante definida en vista/config.py ANCHO_CARACTERES_FIJO = ANCHO_CARACTERES_PANEL_LATERAL def __init__(self, parent, root, panel_central, *args, **kwargs): super().__init__(parent, *args, **kwargs) self.root = root self.panel_central = panel_central self.controles_musica = None self.entrada_superior = None self.configurar_estilos_locales(root) # Configuración de Layout Principal self.grid_rowconfigure(99, weight=1) # Permite que la Fila 99 se expanda self.grid_columnconfigure(0, weight=1) # Creación de Secciones self.crear_barra_de_entrada() # Fila 0 self.crear_seccion_acciones() # Fila 1 self.crear_seccion_aplicaciones() # Fila 2 self.crear_seccion_batch() # Fila 3 # Separador y Espacio Expandible ttk.Separator(self, orient='horizontal').grid(row=4, column=0, sticky="ew", pady=(10, 0)) tk.Frame(self, height=1).grid(row=99, column=0, sticky="nsew") self.crear_controles_musica() # Fila 100 # ------------------------------------------------------------- # 🖼️ ESTRUCTURA Y WIDGETS # ------------------------------------------------------------- def crear_barra_de_entrada(self): """Crea la entrada superior para URL/Scraping.""" frame_entrada = ttk.Frame(self, style='TFrame', padding="10 5 10 0") frame_entrada.grid(row=0, column=0, sticky="ew") self.entrada_superior = ttk.Entry(frame_entrada, width=self.ANCHO_CARACTERES_FIJO, style='Yellow.TEntry') self.entrada_superior.pack(fill="x", ipady=3) self.entrada_superior.bind('', self.manejar_navegacion) def crear_seccion_acciones(self): """Crea los botones de Extracción/Navegación.""" acciones_extraccion = [ ("Extraer Datos (Wikipedia)", self.manejar_extraccion_datos), ("Ir a la URL usando el navegador", self.manejar_navegacion), ("Buscar API Google", lambda: accion_placeholder("Buscar API Google")) ] self._crear_bloque_botones(self, titulo="Extracción/Navegación", acciones=acciones_extraccion, grid_row=1) def crear_seccion_aplicaciones(self): """Crea los botones de apertura de aplicaciones.""" app2_comando = self.manejar_inicio_carrera_t2 acciones_aplicaciones = [ ("Visual Code", abrir_vscode), ("App2 (Carrera 🏁)", app2_comando), ("App3", lambda: accion_placeholder("App3")) ] self._crear_bloque_botones(self, titulo="Aplicaciones", acciones=acciones_aplicaciones, grid_row=2) def crear_seccion_batch(self): """Crea el botón de Copias de seguridad.""" acciones_batch = [ ("Copias de seguridad", self.manejar_backup) ] self._crear_bloque_botones(self, titulo="Procesos batch", acciones=acciones_batch, grid_row=3) def crear_controles_musica(self): """Crea el área para alojar los controles de música/radio.""" frame_musica = ttk.Frame(self, style='TFrame', padding="15 10") frame_musica.grid(row=100, column=0, sticky="ew") frame_musica.grid_columnconfigure(0, weight=1) # Instancia la clase RadioPanel, que ahora contiene solo Play/Pause y Volumen self.controles_musica = RadioPanel(frame_musica, self.root) self.controles_musica.grid(row=0, column=0, sticky="nsew") frame_musica.grid_rowconfigure(0, weight=1) # ------------------------------------------------------------- # ⏯️ MÉTODOS DE LÓGICA / CONTROL # ------------------------------------------------------------- def manejar_extraccion_datos(self): """ Obtiene el término de búsqueda, realiza el scraping, y carga el resultado en el módulo Navegador del Panel Central. """ termino_busqueda = self.entrada_superior.get().strip() if not termino_busqueda: messagebox.showwarning("⚠️ Entrada Vacía", "Por favor, introduce un término de búsqueda para extraer datos.") return success, message, contenido = hacer_scraping(termino_busqueda) if success: messagebox.showinfo("✅ Extracción Exitosa", message) if self.panel_central: self.panel_central.cargar_contenido_web(f"Scraping: {termino_busqueda}", contenido) else: messagebox.showerror("Error", "No se puede visualizar el resultado: Panel Central no disponible.") else: messagebox.showerror("❌ Error de Extracción", message) def manejar_inicio_carrera_t2(self): """ Llama al método 'manejar_inicio_carrera' del Panel Central. """ if self.panel_central: print("Botón App2 presionado. Iniciando Carrera de Camellos en Panel Central...") self.panel_central.manejar_inicio_carrera() else: messagebox.showerror("Error", "El Panel Central no está inicializado.") def manejar_navegacion(self, event=None): """ Obtiene el texto de la entrada superior y llama a la función de navegación (abrir navegador externo). """ url = self.entrada_superior.get() if navegar_a_url(url): self.entrada_superior.delete(0, tk.END) def manejar_backup(self): """Llama a la lógica de backup de T1 e informa al usuario del resultado.""" print("Iniciando proceso de Copia de Seguridad...") success, message = accion_backup_t1() if success: messagebox.showinfo("✅ Backup Completado", message) else: messagebox.showerror("❌ Error en el Backup", message) # ------------------------------------------------------------- # ⚙️ MÉTODOS HELPER # ------------------------------------------------------------- def configurar_estilos_locales(self, parent): """Configura estilos para los widgets del panel lateral, usando constantes importadas.""" style = ttk.Style(parent) style.configure('Yellow.TEntry', fieldbackground='#fff8e1', foreground=COLOR_TEXTO, padding=[5, 5], relief='solid', borderwidth=1) style.configure('Green.TButton', background=COLOR_EXITO, foreground=COLOR_BLANCO, font=FUENTE_NEGOCIOS, relief='flat', padding=[10, 5]) style.map('Green.TButton', background=[('active', '#388E3C'), ('pressed', '#1B5E20')]) style.configure('Action.TButton', background=COLOR_ACCION, foreground=COLOR_BLANCO, font=FUENTE_NEGOCIOS, relief='flat', padding=[10, 5]) style.map('Action.TButton', background=[('active', COLOR_ACCION_HOVER), ('pressed', COLOR_ACCION_PRESSED)]) style.configure('SmallAction.TButton', background=COLOR_ACCION, foreground=COLOR_BLANCO, font=(FUENTE_FAMILIA, 9, 'bold'), relief='flat', padding=[5, 3]) style.map('SmallAction.TButton', background=[('active', COLOR_ACCION_HOVER), ('pressed', COLOR_ACCION_PRESSED)]) def _crear_bloque_botones(self, parent_frame, titulo, acciones, grid_row): """Función helper para crear secciones de etiquetas y botones usando GRID.""" frame_seccion = ttk.Frame(parent_frame, style='TFrame', padding="10 0 10 5") frame_seccion.grid(row=grid_row, column=0, sticky="ew") if titulo: frame_titulo = ttk.Frame(frame_seccion, style='TFrame') frame_titulo.pack(fill="x", pady=(10, 0)) ttk.Label(frame_titulo, text=titulo, font=FUENTE_NEGOCIOS).pack(anchor="w", padx=5) for texto_boton, comando in acciones: ttk.Button(frame_seccion, text=texto_boton, command=comando, style='Green.TButton').pack(fill="x", pady=5)