Lemontropia-Suite/ui/armor_set_selector.py

244 lines
8.8 KiB
Python

"""
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)