gui.panels.slide_navigator
1from PySide6.QtWidgets import QTreeWidget, QTreeWidgetItem 2from PySide6.QtCore import Signal, Qt 3from PySide6.QtGui import QColor, QBrush, QFont 4 5from gui.theme import c, signal as theme_signal 6 7 8_TIPO_COLOR: dict[str, str] = { 9 **{t: '#60a5fa' for t in ( 10 'java', 'python', 'javascript', 'html', 'xml', 11 'jsp', 'css', 'json', 'yaml', 'codigo', 12 )}, 13 'texto': '#fb7185', 14 'bullets': '#818cf8', 15 'dos_columnas': '#2dd4bf', 16 'cita': '#f9a8d4', 17 **{t: '#4ade80' for t in ( 18 'comparar', 'comparar_python', 'comparar_js', 19 'comparar_xml', 'comparar_html', 'comparar_json', 'comparar_css', 'comparar_jsp', 20 )}, 21 'tabla': '#fb923c', 22 'aviso': '#fbbf24', 23 **{t: '#c084fc' for t in ('terminal', 'salida', 'code')}, 24 'diagrama': '#22d3ee', 25 **{t: '#f472b6' for t in ('imagen', 'imagen_texto')}, 26} 27 28# Valores especiales de section_idx para los nodos fijos 29NODE_PORTADA = -10 30NODE_OBJETIVOS = -9 31NODE_CONCLUSION = -8 32NODE_REFERENCIAS = -7 33 34 35def _slide_label(slide: dict, n: int) -> str: 36 tipo = slide.get('tipo', '?') 37 if tipo == 'aviso': 38 nivel = slide.get('nivel', '') 39 return f'aviso: {nivel} ({n})' 40 return f'{tipo} ({n})' 41 42 43class SlideNavigator(QTreeWidget): 44 """Árbol semántico del YAML activo. 45 46 Emite slide_selected(section_idx, slide_idx) al hacer click: 47 - section_idx >= 0, slide_idx >= 0 → slide concreto (0 = primer slide de la sección) 48 - section_idx == NODE_* → nodo fijo (portada, objetivos…) 49 """ 50 slide_selected = Signal(int, int) 51 52 def __init__(self, parent=None): 53 super().__init__(parent) 54 self.setHeaderHidden(True) 55 self.setAnimated(True) 56 self.setIndentation(16) 57 self.setMinimumWidth(160) 58 self.itemClicked.connect(self._on_item_clicked) 59 theme_signal().changed.connect(self._on_theme_changed) 60 self._last_data: dict = {} 61 62 # ── API pública ─────────────────────────────────────────────────────────── 63 64 def _on_theme_changed(self) -> None: 65 if self._last_data: 66 self.rebuild(self._last_data) 67 68 def rebuild(self, data: dict) -> None: 69 self._last_data = data 70 """Reconstruye el árbol desde el dict YAML parseado.""" 71 self.clear() 72 73 self._add_fixed('Portada', NODE_PORTADA, 0) 74 self._add_fixed('Objetivos', NODE_OBJETIVOS, 0) 75 76 indice_list = data.get('indice', []) 77 78 for sec_idx, sec in enumerate(data.get('secciones', [])): 79 if 'titulo' in sec: 80 titulo = sec['titulo'] 81 elif 'indice' in sec and indice_list: 82 idx = sec['indice'] - 1 83 titulo = indice_list[idx] if 0 <= idx < len(indice_list) else f'Sección {sec_idx + 1}' 84 else: 85 titulo = f'Sección {sec_idx + 1}' 86 87 sec_item = QTreeWidgetItem(self) 88 sec_item.setText(0, f'Sec {sec_idx + 1}: {titulo}') 89 sec_item.setData(0, Qt.ItemDataRole.UserRole, (sec_idx, 0)) 90 sec_item.setForeground(0, QBrush(QColor(c('text')))) 91 bold = QFont() 92 bold.setBold(True) 93 sec_item.setFont(0, bold) 94 95 for slide_idx, slide in enumerate(sec.get('slides', [])): 96 tipo = slide.get('tipo', '?') 97 s_item = QTreeWidgetItem(sec_item) 98 s_item.setText(0, f' {_slide_label(slide, slide_idx + 1)}') 99 s_item.setData(0, Qt.ItemDataRole.UserRole, (sec_idx, slide_idx)) 100 s_item.setForeground(0, QBrush(QColor(_TIPO_COLOR.get(tipo, '#94a3b8')))) 101 102 sec_item.setExpanded(True) 103 104 self._add_fixed('Conclusión', NODE_CONCLUSION, 0) 105 self._add_fixed('Referencias', NODE_REFERENCIAS, 0) 106 107 # ── Slots privados ──────────────────────────────────────────────────────── 108 109 def _add_fixed(self, label: str, sec_idx: int, slide_idx: int) -> QTreeWidgetItem: 110 item = QTreeWidgetItem(self) 111 item.setText(0, label) 112 item.setData(0, Qt.ItemDataRole.UserRole, (sec_idx, slide_idx)) 113 item.setForeground(0, QBrush(QColor(c('text_dim')))) 114 return item 115 116 def _on_item_clicked(self, item: QTreeWidgetItem, _column: int) -> None: 117 data = item.data(0, Qt.ItemDataRole.UserRole) 118 if data is not None: 119 self.slide_selected.emit(data[0], data[1])
NODE_PORTADA =
-10
NODE_OBJETIVOS =
-9
NODE_CONCLUSION =
-8
NODE_REFERENCIAS =
-7