263 lines
10 KiB
Python
263 lines
10 KiB
Python
"""
|
|
Plate Selector for Lemontropia Suite
|
|
Browse and search armor plates 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, QComboBox
|
|
)
|
|
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, NexusPlate
|
|
|
|
|
|
class PlateLoaderThread(QThread):
|
|
"""Background thread for loading plates from API."""
|
|
plates_loaded = pyqtSignal(list)
|
|
error_occurred = pyqtSignal(str)
|
|
|
|
def run(self):
|
|
try:
|
|
api = get_nexus_api()
|
|
plates = api.get_all_plates()
|
|
self.plates_loaded.emit(plates)
|
|
except Exception as e:
|
|
self.error_occurred.emit(str(e))
|
|
|
|
|
|
class PlateSelectorDialog(QDialog):
|
|
"""Dialog for selecting armor plates from Entropia Nexus API."""
|
|
|
|
plate_selected = pyqtSignal(NexusPlate)
|
|
|
|
def __init__(self, parent=None, damage_type: str = ""):
|
|
super().__init__(parent)
|
|
self.setWindowTitle("Select Armor Plate - Entropia Nexus")
|
|
self.setMinimumSize(900, 600)
|
|
|
|
self.all_plates: List[NexusPlate] = []
|
|
self.selected_plate: Optional[NexusPlate] = None
|
|
self.preferred_damage_type = damage_type # For filtering
|
|
|
|
self._setup_ui()
|
|
self._load_data()
|
|
|
|
def _setup_ui(self):
|
|
layout = QVBoxLayout(self)
|
|
layout.setSpacing(10)
|
|
|
|
# Status
|
|
self.status_label = QLabel("Loading plates from Entropia Nexus...")
|
|
layout.addWidget(self.status_label)
|
|
|
|
self.progress = QProgressBar()
|
|
self.progress.setRange(0, 0)
|
|
layout.addWidget(self.progress)
|
|
|
|
# Filters
|
|
filter_layout = QHBoxLayout()
|
|
|
|
filter_layout.addWidget(QLabel("Protection Type:"))
|
|
self.type_combo = QComboBox()
|
|
self.type_combo.addItems(["All Types", "Impact", "Cut", "Stab", "Burn", "Cold", "Acid", "Electric"])
|
|
if self.preferred_damage_type:
|
|
index = self.type_combo.findText(self.preferred_damage_type.capitalize())
|
|
if index >= 0:
|
|
self.type_combo.setCurrentIndex(index)
|
|
self.type_combo.currentTextChanged.connect(self._apply_filters)
|
|
filter_layout.addWidget(self.type_combo)
|
|
|
|
filter_layout.addWidget(QLabel("Min Protection:"))
|
|
self.min_prot_combo = QComboBox()
|
|
self.min_prot_combo.addItems(["Any", "1+", "3+", "5+", "7+", "10+"])
|
|
self.min_prot_combo.currentTextChanged.connect(self._apply_filters)
|
|
filter_layout.addWidget(self.min_prot_combo)
|
|
|
|
layout.addLayout(filter_layout)
|
|
|
|
# Search
|
|
search_layout = QHBoxLayout()
|
|
search_layout.addWidget(QLabel("Search:"))
|
|
self.search_input = QLineEdit()
|
|
self.search_input.setPlaceholderText("Type to search plates (e.g., '5B', 'Impact')...")
|
|
self.search_input.textChanged.connect(self._apply_filters)
|
|
search_layout.addWidget(self.search_input)
|
|
|
|
self.clear_btn = QPushButton("Clear")
|
|
self.clear_btn.clicked.connect(self._clear_search)
|
|
search_layout.addWidget(self.clear_btn)
|
|
layout.addLayout(search_layout)
|
|
|
|
# Results tree
|
|
self.results_tree = QTreeWidget()
|
|
self.results_tree.setHeaderLabels([
|
|
"Name", "Impact", "Cut", "Stab", "Burn", "Cold", "Acid", "Electric", "Total", "Decay"
|
|
])
|
|
header = self.results_tree.header()
|
|
header.setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)
|
|
header.setStretchLastSection(False)
|
|
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("Plate Preview")
|
|
preview_layout = QFormLayout(self.preview_group)
|
|
self.preview_name = QLabel("-")
|
|
self.preview_protection = QLabel("-")
|
|
self.preview_decay = QLabel("-")
|
|
preview_layout.addRow("Name:", self.preview_name)
|
|
preview_layout.addRow("Protection:", self.preview_protection)
|
|
preview_layout.addRow("Decay:", self.preview_decay)
|
|
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 plates in background thread."""
|
|
self.loader = PlateLoaderThread()
|
|
self.loader.plates_loaded.connect(self._on_plates_loaded)
|
|
self.loader.error_occurred.connect(self._on_load_error)
|
|
self.loader.start()
|
|
|
|
def _on_plates_loaded(self, plates: List[NexusPlate]):
|
|
"""Handle loaded plates."""
|
|
self.all_plates = plates
|
|
self.status_label.setText(f"Loaded {len(plates)} plates from Entropia Nexus")
|
|
self.progress.setRange(0, 100)
|
|
self.progress.setValue(100)
|
|
self._apply_filters()
|
|
|
|
def _on_load_error(self, error: str):
|
|
"""Handle load error."""
|
|
self.status_label.setText(f"Error loading plates: {error}")
|
|
self.progress.setRange(0, 100)
|
|
self.progress.setValue(0)
|
|
|
|
def _apply_filters(self):
|
|
"""Apply all filters and search."""
|
|
plates = self.all_plates.copy()
|
|
|
|
# Type filter
|
|
type_filter = self.type_combo.currentText()
|
|
if type_filter != "All Types":
|
|
type_lower = type_filter.lower()
|
|
plates = [p for p in plates if getattr(p, f"protection_{type_lower}", Decimal("0")) > 0]
|
|
|
|
# Min protection filter
|
|
min_prot = self.min_prot_combo.currentText()
|
|
if min_prot != "Any":
|
|
min_val = int(min_prot.replace("+", ""))
|
|
plates = [p for p in plates if (
|
|
p.protection_impact + p.protection_cut + p.protection_stab +
|
|
p.protection_burn + p.protection_cold + p.protection_acid + p.protection_electric
|
|
) >= min_val]
|
|
|
|
# Search filter
|
|
search_text = self.search_input.text()
|
|
if search_text:
|
|
query = search_text.lower()
|
|
plates = [p for p in plates if query in p.name.lower()]
|
|
|
|
self._populate_results(plates)
|
|
|
|
# Update status
|
|
if search_text:
|
|
self.status_label.setText(f"Found {len(plates)} plates matching '{search_text}'")
|
|
else:
|
|
self.status_label.setText(f"Showing {len(plates)} of {len(self.all_plates)} plates")
|
|
|
|
def _populate_results(self, plates: List[NexusPlate]):
|
|
"""Populate results tree."""
|
|
self.results_tree.clear()
|
|
|
|
# Sort by total protection (highest first)
|
|
plates = sorted(plates, key=lambda p: (
|
|
p.protection_impact + p.protection_cut + p.protection_stab +
|
|
p.protection_burn + p.protection_cold + p.protection_acid + p.protection_electric
|
|
), reverse=True)
|
|
|
|
for plate in plates:
|
|
item = QTreeWidgetItem()
|
|
item.setText(0, plate.name)
|
|
item.setText(1, str(plate.protection_impact))
|
|
item.setText(2, str(plate.protection_cut))
|
|
item.setText(3, str(plate.protection_stab))
|
|
item.setText(4, str(plate.protection_burn))
|
|
item.setText(5, str(plate.protection_cold))
|
|
item.setText(6, str(plate.protection_acid))
|
|
item.setText(7, str(plate.protection_electric))
|
|
|
|
total = plate.protection_impact + plate.protection_cut + plate.protection_stab + plate.protection_burn + plate.protection_cold + plate.protection_acid + plate.protection_electric
|
|
item.setText(8, str(total))
|
|
item.setText(9, f"{plate.decay:.2f}")
|
|
|
|
# Highlight plates matching preferred damage type
|
|
if self.preferred_damage_type:
|
|
type_lower = self.preferred_damage_type.lower()
|
|
if getattr(plate, f"protection_{type_lower}", Decimal("0")) > 0:
|
|
item.setBackground(0, QColor("#2d4a3e")) # Dark green
|
|
|
|
item.setData(0, Qt.ItemDataRole.UserRole, plate)
|
|
self.results_tree.addTopLevelItem(item)
|
|
|
|
def _clear_search(self):
|
|
"""Clear search and filters."""
|
|
self.search_input.clear()
|
|
self.type_combo.setCurrentIndex(0)
|
|
self.min_prot_combo.setCurrentIndex(0)
|
|
self._apply_filters()
|
|
|
|
def _on_selection_changed(self):
|
|
"""Handle selection change."""
|
|
items = self.results_tree.selectedItems()
|
|
if items:
|
|
self.selected_plate = items[0].data(0, Qt.ItemDataRole.UserRole)
|
|
self.ok_button.setEnabled(True)
|
|
self._update_preview(self.selected_plate)
|
|
else:
|
|
self.selected_plate = None
|
|
self.ok_button.setEnabled(False)
|
|
|
|
def _update_preview(self, plate: NexusPlate):
|
|
"""Update preview panel."""
|
|
self.preview_name.setText(plate.name)
|
|
|
|
prot_parts = []
|
|
if plate.protection_impact > 0:
|
|
prot_parts.append(f"Imp:{plate.protection_impact}")
|
|
if plate.protection_cut > 0:
|
|
prot_parts.append(f"Cut:{plate.protection_cut}")
|
|
if plate.protection_stab > 0:
|
|
prot_parts.append(f"Stab:{plate.protection_stab}")
|
|
if plate.protection_burn > 0:
|
|
prot_parts.append(f"Burn:{plate.protection_burn}")
|
|
if plate.protection_cold > 0:
|
|
prot_parts.append(f"Cold:{plate.protection_cold}")
|
|
|
|
self.preview_protection.setText(", ".join(prot_parts) if prot_parts else "None")
|
|
self.preview_decay.setText(f"{plate.decay:.2f} PEC")
|
|
|
|
def _on_double_click(self, item, column):
|
|
"""Handle double click."""
|
|
self._on_accept()
|
|
|
|
def _on_accept(self):
|
|
"""Handle OK button."""
|
|
if self.selected_plate:
|
|
self.plate_selected.emit(self.selected_plate)
|
|
self.accept()
|