""" Armor Set Selector for Lemontropia Suite Browse and select full armor sets from Entropia Nexus API """ from decimal import Decimal from PyQt6.QtWidgets import ( QDialog, QVBoxLayout, QHBoxLayout, QLineEdit, QPushButton, QTreeWidget, QTreeWidgetItem, QHeaderView, QLabel, QDialogButtonBox, QProgressBar, QGroupBox, QFormLayout ) from PyQt6.QtCore import Qt, QThread, pyqtSignal from PyQt6.QtGui import QColor from typing import Optional, List from core.nexus_full_api import get_nexus_api, NexusArmorSet class ArmorSetLoaderThread(QThread): """Background thread for loading armor sets from API.""" armor_sets_loaded = pyqtSignal(list) error_occurred = pyqtSignal(str) def run(self): try: api = get_nexus_api() armor_sets = api.get_all_armor_sets() self.armor_sets_loaded.emit(armor_sets) except Exception as e: self.error_occurred.emit(str(e)) class ArmorSetSelectorDialog(QDialog): """Dialog for selecting full armor sets from Entropia Nexus API.""" armor_set_selected = pyqtSignal(NexusArmorSet) def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("Select Armor Set - Entropia Nexus") self.setMinimumSize(900, 600) self.all_armor_sets: List[NexusArmorSet] = [] self.selected_armor_set: Optional[NexusArmorSet] = None self._setup_ui() self._load_data() def _setup_ui(self): layout = QVBoxLayout(self) layout.setSpacing(10) # Status self.status_label = QLabel("Loading armor sets from Entropia Nexus...") layout.addWidget(self.status_label) self.progress = QProgressBar() self.progress.setRange(0, 0) layout.addWidget(self.progress) # Search search_layout = QHBoxLayout() search_layout.addWidget(QLabel("Search:")) self.search_input = QLineEdit() self.search_input.setPlaceholderText("Search armor sets (e.g., 'Ghost', 'Shogun')...") self.search_input.textChanged.connect(self._filter_armor_sets) search_layout.addWidget(self.search_input) clear_btn = QPushButton("Clear") clear_btn.clicked.connect(self.search_input.clear) search_layout.addWidget(clear_btn) layout.addLayout(search_layout) # Results tree self.results_tree = QTreeWidget() self.results_tree.setHeaderLabels([ "Set Name", "Pieces", "Total Protection", "Set Bonus" ]) header = self.results_tree.header() header.setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents) self.results_tree.itemSelectionChanged.connect(self._on_selection_changed) self.results_tree.itemDoubleClicked.connect(self._on_double_click) layout.addWidget(self.results_tree) # Preview panel self.preview_group = QGroupBox("Armor Set Preview") preview_layout = QFormLayout(self.preview_group) self.preview_name = QLabel("-") self.preview_pieces = QLabel("-") self.preview_protection = QLabel("-") self.preview_bonus = QLabel("-") preview_layout.addRow("Name:", self.preview_name) preview_layout.addRow("Pieces:", self.preview_pieces) preview_layout.addRow("Protection:", self.preview_protection) preview_layout.addRow("Set Bonus:", self.preview_bonus) layout.addWidget(self.preview_group) # Buttons buttons = QDialogButtonBox( QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel ) buttons.accepted.connect(self._on_accept) buttons.rejected.connect(self.reject) self.ok_button = buttons.button(QDialogButtonBox.StandardButton.Ok) self.ok_button.setEnabled(False) layout.addWidget(buttons) def _load_data(self): """Load armor sets in background thread.""" self.loader = ArmorSetLoaderThread() self.loader.armor_sets_loaded.connect(self._on_armor_sets_loaded) self.loader.error_occurred.connect(self._on_load_error) self.loader.start() def _on_armor_sets_loaded(self, armor_sets: List[NexusArmorSet]): """Handle loaded armor sets.""" self.all_armor_sets = armor_sets self._populate_results(armor_sets) self.status_label.setText(f"Showing {len(armor_sets)} armor sets") self.progress.setRange(0, 100) self.progress.setValue(100) def _on_load_error(self, error: str): """Handle load error.""" self.status_label.setText(f"Error loading armor sets: {error}") self.progress.setRange(0, 100) self.progress.setValue(0) def _populate_results(self, armor_sets: List[NexusArmorSet]): """Populate results tree.""" self.results_tree.clear() if not armor_sets: item = QTreeWidgetItem() item.setText(0, "No armor sets available") item.setForeground(0, QColor("#888888")) self.results_tree.addTopLevelItem(item) return # Sort by total protection armor_sets = sorted(armor_sets, key=lambda s: s.total_protection.get_total(), reverse=True) for armor_set in armor_sets: item = QTreeWidgetItem() item.setText(0, armor_set.name) item.setText(1, f"{len(armor_set.pieces)} pieces") # Format protection prot = armor_set.total_protection prot_str = f"Total: {prot.get_total():.1f}" if prot.impact > 0: prot_str += f" | Imp:{prot.impact:.0f}" if prot.cut > 0: prot_str += f" | Cut:{prot.cut:.0f}" if prot.stab > 0: prot_str += f" | Stab:{prot.stab:.0f}" item.setText(2, prot_str) # Set bonus bonus = armor_set.set_bonus or "None" item.setText(3, bonus) # Color by set bonus presence if armor_set.set_bonus: item.setForeground(3, QColor("#4caf50")) item.setData(0, Qt.ItemDataRole.UserRole, armor_set) self.results_tree.addTopLevelItem(item) def _filter_armor_sets(self): """Filter armor sets based on search.""" search = self.search_input.text().lower() if not search: self._populate_results(self.all_armor_sets) return filtered = [ s for s in self.all_armor_sets if search in s.name.lower() or any(search in piece.lower() for piece in s.pieces) ] self._populate_results(filtered) def _on_selection_changed(self): """Handle selection change.""" items = self.results_tree.selectedItems() if items: self.selected_armor_set = items[0].data(0, Qt.ItemDataRole.UserRole) self._update_preview(self.selected_armor_set) self.ok_button.setEnabled(True) else: self.selected_armor_set = None self.ok_button.setEnabled(False) def _update_preview(self, armor_set: NexusArmorSet): """Update preview panel.""" self.preview_name.setText(armor_set.name) self.preview_pieces.setText(", ".join(armor_set.pieces)) prot = armor_set.total_protection prot_str = f"Impact: {prot.impact:.1f}, Cut: {prot.cut:.1f}, Stab: {prot.stab:.1f}\n" prot_str += f"Burn: {prot.burn:.1f}, Cold: {prot.cold:.1f}, Acid: {prot.acid:.1f}, Elec: {prot.electric:.1f}\n" prot_str += f"Total: {prot.get_total():.1f}" self.preview_protection.setText(prot_str) self.preview_bonus.setText(armor_set.set_bonus or "None") if armor_set.set_bonus: self.preview_bonus.setStyleSheet("color: #4caf50;") else: self.preview_bonus.setStyleSheet("") def _on_double_click(self, item: QTreeWidgetItem, column: int): """Handle double click.""" if item.data(0, Qt.ItemDataRole.UserRole): self._on_accept() def _on_accept(self): """Handle OK button.""" if self.selected_armor_set: self.armor_set_selected.emit(self.selected_armor_set) self.accept() # Main entry for testing if __name__ == "__main__": import sys import logging from PyQt6.QtWidgets import QApplication logging.basicConfig(level=logging.INFO) app = QApplication(sys.argv) app.setStyle('Fusion') dialog = ArmorSetSelectorDialog() # Connect signal for testing dialog.armor_set_selected.connect(lambda s: print(f"Selected armor set: {s.name}")) if dialog.exec() == QDialog.DialogCode.Accepted: print("Armor set selected!") sys.exit(0)