"""Paso 2: selección de plantilla de biblioteca curada.""" from __future__ import annotations from PySide6.QtCore import Qt from PySide6.QtWidgets import ( QHBoxLayout, QLabel, QLineEdit, QListWidget, QListWidgetItem, QVBoxLayout, QWidget, QWizardPage, ) from vmssailor.library import load_library from vmssailor.studio.theme import C_FOG, mono_font, ui_font class Step02Template(QWizardPage): def __init__(self, parent: QWidget | None = None) -> None: super().__init__(parent) self.setTitle("Paso 2 · Plantilla de buque") self.setSubTitle( "Elige una plantilla de la biblioteca curada. Las dimensiones del paso 3 " "se pre-rellenarán pero puedes ajustar después." ) outer = QHBoxLayout(self) outer.setSpacing(20) # Left: list of templates filtered by type self._list = QListWidget() self._list.setMinimumWidth(280) outer.addWidget(self._list, 1) # Right: details right = QVBoxLayout() outer.addLayout(right, 2) self._name_label = QLabel("(Selecciona una plantilla)") self._name_label.setObjectName("title") self._name_label.setFont(ui_font(13)) right.addWidget(self._name_label) self._meta_label = QLabel("") self._meta_label.setFont(mono_font(10)) self._meta_label.setStyleSheet(f"color: {C_FOG};") right.addWidget(self._meta_label) self._desc_label = QLabel("") self._desc_label.setWordWrap(True) right.addWidget(self._desc_label) right.addStretch(1) # Hidden vessel_name field for the next step self._vessel_name = QLineEdit() self._vessel_name.hide() from vmssailor.studio.wizard.wizard import F_TEMPLATE_ID, F_VESSEL_NAME self.registerField(F_TEMPLATE_ID, self, "selected_template_id", "templateChanged") self.registerField(F_VESSEL_NAME, self._vessel_name) self._templates: dict[str, dict] = {} self._selected_id: str | None = None self._load_templates() self._list.currentItemChanged.connect(self._on_selection_changed) # ----- Property API (for QWizard field) ------------------------------- from PySide6.QtCore import Property, Signal # type: ignore templateChanged = Signal() def get_selected_template_id(self) -> str: return self._selected_id or "" def set_selected_template_id(self, value: str) -> None: self._selected_id = value self.templateChanged.emit() selected_template_id = Property( str, fget=get_selected_template_id, fset=set_selected_template_id, notify=templateChanged ) # ----- Internals ------------------------------------------------------ def initializePage(self) -> None: from vmssailor.studio.wizard.wizard import F_VESSEL_TYPE type_str = self.field(F_VESSEL_TYPE) self._refresh_list(type_str) def _load_templates(self) -> None: try: result = load_library() for v in result.vessels: self._templates[v.id] = { "id": v.id, "name": v.name, "type": v.type.value, "length_overall_m": v.length_overall_m, "beam_max_m": v.beam_max_m, "draft_m": v.draft_m, "description": v.description, } except Exception: # Si la biblioteca falla, no rompemos el wizard. pass # Also add a "blank" template self._templates["__blank__"] = { "id": "__blank__", "name": "Plantilla en blanco", "type": "*", "length_overall_m": 24.0, "beam_max_m": 5.5, "draft_m": 1.8, "description": "Empezar desde cero, sin plantilla de buque. Defines todas las dimensiones manualmente.", } def _refresh_list(self, type_filter: str | None) -> None: self._list.clear() for tid, t in self._templates.items(): if type_filter and t["type"] not in (type_filter, "*"): continue label = ( f"{t['name']}\n" f" {t['length_overall_m']:.1f} × {t['beam_max_m']:.1f} m" if tid != "__blank__" else t["name"] ) item = QListWidgetItem(label) item.setData(Qt.UserRole, tid) self._list.addItem(item) if self._list.count() > 0: self._list.setCurrentRow(0) def _on_selection_changed(self, current: QListWidgetItem | None) -> None: if not current: return tid = current.data(Qt.UserRole) t = self._templates.get(tid) if not t: return self._selected_id = tid self._vessel_name.setText(t["name"]) self._name_label.setText(t["name"]) self._meta_label.setText( f"id: {t['id']} LOA {t['length_overall_m']:.1f} m · " f"manga {t['beam_max_m']:.1f} m · calado {t['draft_m']:.1f} m" ) self._desc_label.setText(t.get("description", "") or "(sin descripción)") self.templateChanged.emit() self.completeChanged.emit() def isComplete(self) -> bool: return self._selected_id is not None def get_template(self) -> dict | None: if self._selected_id: return self._templates.get(self._selected_id) return None