feat(selectors): add enhancer and accessories selectors
- NEW: ui/enhancer_selector.py - Weapon/Armor enhancer browser - Filter by type (Damage, Economy, Range, etc.) - Filter by tier (1-5+) - Risk level indicator (Low/Medium/High break chance) - Warning about enhancer breakage - NEW: ui/accessories_selector.py - Rings, Clothing, Pets browser - Tabbed interface: Rings / Clothing / Pets - Rings: Limited items highlighted - Clothing: Buff display, cosmetic indicator - Pets: Effect display, level requirements
This commit is contained in:
parent
1c0d684c4c
commit
c490a84982
|
|
@ -0,0 +1,471 @@
|
|||
"""
|
||||
Rings, Clothing & Pet Selector for Lemontropia Suite
|
||||
Browse and search accessories 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, QTabWidget, QWidget
|
||||
)
|
||||
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, NexusRing, NexusClothing, NexusPet
|
||||
|
||||
|
||||
class AccessoriesLoaderThread(QThread):
|
||||
"""Background thread for loading accessories from API."""
|
||||
rings_loaded = pyqtSignal(list)
|
||||
clothing_loaded = pyqtSignal(list)
|
||||
pets_loaded = pyqtSignal(list)
|
||||
error_occurred = pyqtSignal(str)
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
api = get_nexus_api()
|
||||
rings = api.get_all_rings()
|
||||
clothing = api.get_all_clothing()
|
||||
pets = api.get_all_pets()
|
||||
self.rings_loaded.emit(rings)
|
||||
self.clothing_loaded.emit(clothing)
|
||||
self.pets_loaded.emit(pets)
|
||||
except Exception as e:
|
||||
self.error_occurred.emit(str(e))
|
||||
|
||||
|
||||
class AccessoriesSelectorDialog(QDialog):
|
||||
"""Dialog for selecting rings, clothing, and pets from Entropia Nexus API."""
|
||||
|
||||
ring_selected = pyqtSignal(NexusRing)
|
||||
clothing_selected = pyqtSignal(NexusClothing)
|
||||
pet_selected = pyqtSignal(NexusPet)
|
||||
|
||||
def __init__(self, parent=None, initial_tab: str = "rings"):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("Select Accessories - Entropia Nexus")
|
||||
self.setMinimumSize(900, 600)
|
||||
|
||||
self.all_rings: List[NexusRing] = []
|
||||
self.all_clothing: List[NexusClothing] = []
|
||||
self.all_pets: List[NexusPet] = []
|
||||
|
||||
self.selected_ring: Optional[NexusRing] = None
|
||||
self.selected_clothing: Optional[NexusClothing] = None
|
||||
self.selected_pet: Optional[NexusPet] = None
|
||||
|
||||
self._setup_ui()
|
||||
|
||||
# Set initial tab
|
||||
tab_map = {"rings": 0, "clothing": 1, "pets": 2}
|
||||
self.tabs.setCurrentIndex(tab_map.get(initial_tab, 0))
|
||||
|
||||
self._load_data()
|
||||
|
||||
def _setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
layout.setSpacing(10)
|
||||
|
||||
# Status
|
||||
self.status_label = QLabel("Loading accessories from Entropia Nexus...")
|
||||
layout.addWidget(self.status_label)
|
||||
|
||||
self.progress = QProgressBar()
|
||||
self.progress.setRange(0, 0)
|
||||
layout.addWidget(self.progress)
|
||||
|
||||
# Tabs
|
||||
self.tabs = QTabWidget()
|
||||
|
||||
# Rings tab
|
||||
self.tab_rings = self._create_rings_tab()
|
||||
self.tabs.addTab(self.tab_rings["widget"], "💍 Rings")
|
||||
|
||||
# Clothing tab
|
||||
self.tab_clothing = self._create_clothing_tab()
|
||||
self.tabs.addTab(self.tab_clothing["widget"], "👕 Clothing")
|
||||
|
||||
# Pets tab
|
||||
self.tab_pets = self._create_pets_tab()
|
||||
self.tabs.addTab(self.tab_pets["widget"], "🐾 Pets")
|
||||
|
||||
self.tabs.currentChanged.connect(self._on_tab_changed)
|
||||
layout.addWidget(self.tabs)
|
||||
|
||||
# Preview panel
|
||||
self.preview_group = QGroupBox("Item Preview")
|
||||
preview_layout = QFormLayout(self.preview_group)
|
||||
self.preview_name = QLabel("-")
|
||||
self.preview_type = QLabel("-")
|
||||
self.preview_effect = QLabel("-")
|
||||
self.preview_extra = QLabel("-")
|
||||
preview_layout.addRow("Name:", self.preview_name)
|
||||
preview_layout.addRow("Type:", self.preview_type)
|
||||
preview_layout.addRow("Effect:", self.preview_effect)
|
||||
preview_layout.addRow("", self.preview_extra)
|
||||
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 _create_rings_tab(self) -> dict:
|
||||
"""Create rings selection tab."""
|
||||
widget = QWidget()
|
||||
layout = QVBoxLayout(widget)
|
||||
|
||||
# Filters
|
||||
filter_layout = QHBoxLayout()
|
||||
filter_layout.addWidget(QLabel("Side:"))
|
||||
side_combo = QComboBox()
|
||||
side_combo.addItems(["Any", "Left", "Right"])
|
||||
filter_layout.addWidget(side_combo)
|
||||
|
||||
filter_layout.addWidget(QLabel("Limited:"))
|
||||
limited_combo = QComboBox()
|
||||
limited_combo.addItems(["Any", "Yes", "No"])
|
||||
filter_layout.addWidget(limited_combo)
|
||||
|
||||
layout.addLayout(filter_layout)
|
||||
|
||||
# Search
|
||||
search_layout = QHBoxLayout()
|
||||
search_layout.addWidget(QLabel("Search:"))
|
||||
search_input = QLineEdit()
|
||||
search_input.setPlaceholderText("Search rings...")
|
||||
search_layout.addWidget(search_input)
|
||||
|
||||
clear_btn = QPushButton("Clear")
|
||||
search_layout.addWidget(clear_btn)
|
||||
layout.addLayout(search_layout)
|
||||
|
||||
# Tree
|
||||
tree = QTreeWidget()
|
||||
tree.setHeaderLabels(["Name", "Effect Type", "Value", "Side", "Limited"])
|
||||
header = tree.header()
|
||||
header.setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)
|
||||
tree.itemSelectionChanged.connect(self._on_selection_changed)
|
||||
tree.itemDoubleClicked.connect(self._on_double_click)
|
||||
layout.addWidget(tree)
|
||||
|
||||
return {
|
||||
"widget": widget,
|
||||
"side": side_combo,
|
||||
"limited": limited_combo,
|
||||
"search": search_input,
|
||||
"clear": clear_btn,
|
||||
"tree": tree
|
||||
}
|
||||
|
||||
def _create_clothing_tab(self) -> dict:
|
||||
"""Create clothing selection tab."""
|
||||
widget = QWidget()
|
||||
layout = QVBoxLayout(widget)
|
||||
|
||||
# Filters
|
||||
filter_layout = QHBoxLayout()
|
||||
filter_layout.addWidget(QLabel("Slot:"))
|
||||
slot_combo = QComboBox()
|
||||
slot_combo.addItems(["Any", "Face", "Body", "Legs", "Feet", "Back"])
|
||||
filter_layout.addWidget(slot_combo)
|
||||
|
||||
filter_layout.addWidget(QLabel("Cosmetic:"))
|
||||
cosmetic_combo = QComboBox()
|
||||
cosmetic_combo.addItems(["Any", "Yes", "No"])
|
||||
filter_layout.addWidget(cosmetic_combo)
|
||||
|
||||
layout.addLayout(filter_layout)
|
||||
|
||||
# Search
|
||||
search_layout = QHBoxLayout()
|
||||
search_layout.addWidget(QLabel("Search:"))
|
||||
search_input = QLineEdit()
|
||||
search_input.setPlaceholderText("Search clothing...")
|
||||
search_layout.addWidget(search_input)
|
||||
|
||||
clear_btn = QPushButton("Clear")
|
||||
search_layout.addWidget(clear_btn)
|
||||
layout.addLayout(search_layout)
|
||||
|
||||
# Tree
|
||||
tree = QTreeWidget()
|
||||
tree.setHeaderLabels(["Name", "Slot", "Buffs", "Cosmetic"])
|
||||
header = tree.header()
|
||||
header.setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)
|
||||
tree.itemSelectionChanged.connect(self._on_selection_changed)
|
||||
tree.itemDoubleClicked.connect(self._on_double_click)
|
||||
layout.addWidget(tree)
|
||||
|
||||
return {
|
||||
"widget": widget,
|
||||
"slot": slot_combo,
|
||||
"cosmetic": cosmetic_combo,
|
||||
"search": search_input,
|
||||
"clear": clear_btn,
|
||||
"tree": tree
|
||||
}
|
||||
|
||||
def _create_pets_tab(self) -> dict:
|
||||
"""Create pets selection tab."""
|
||||
widget = QWidget()
|
||||
layout = QVBoxLayout(widget)
|
||||
|
||||
# Search
|
||||
search_layout = QHBoxLayout()
|
||||
search_layout.addWidget(QLabel("Search:"))
|
||||
search_input = QLineEdit()
|
||||
search_input.setPlaceholderText("Search pets...")
|
||||
search_layout.addWidget(search_input)
|
||||
|
||||
clear_btn = QPushButton("Clear")
|
||||
search_layout.addWidget(clear_btn)
|
||||
layout.addLayout(search_layout)
|
||||
|
||||
# Tree
|
||||
tree = QTreeWidget()
|
||||
tree.setHeaderLabels(["Name", "Effect Type", "Effect Value", "Level Req"])
|
||||
header = tree.header()
|
||||
header.setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)
|
||||
tree.itemSelectionChanged.connect(self._on_selection_changed)
|
||||
tree.itemDoubleClicked.connect(self._on_double_click)
|
||||
layout.addWidget(tree)
|
||||
|
||||
return {
|
||||
"widget": widget,
|
||||
"search": search_input,
|
||||
"clear": clear_btn,
|
||||
"tree": tree
|
||||
}
|
||||
|
||||
def _load_data(self):
|
||||
"""Load accessories in background thread."""
|
||||
self.loader = AccessoriesLoaderThread()
|
||||
self.loader.rings_loaded.connect(self._on_rings_loaded)
|
||||
self.loader.clothing_loaded.connect(self._on_clothing_loaded)
|
||||
self.loader.pets_loaded.connect(self._on_pets_loaded)
|
||||
self.loader.error_occurred.connect(self._on_load_error)
|
||||
self.loader.start()
|
||||
|
||||
def _on_rings_loaded(self, rings: List[NexusRing]):
|
||||
"""Handle loaded rings."""
|
||||
self.all_rings = rings
|
||||
self._populate_rings()
|
||||
self._update_status()
|
||||
|
||||
def _on_clothing_loaded(self, clothing: List[NexusClothing]):
|
||||
"""Handle loaded clothing."""
|
||||
self.all_clothing = clothing
|
||||
self._populate_clothing()
|
||||
self._update_status()
|
||||
|
||||
def _on_pets_loaded(self, pets: List[NexusPet]):
|
||||
"""Handle loaded pets."""
|
||||
self.all_pets = pets
|
||||
self._populate_pets()
|
||||
self._update_status()
|
||||
|
||||
def _on_load_error(self, error: str):
|
||||
"""Handle load error."""
|
||||
self.status_label.setText(f"Error loading accessories: {error}")
|
||||
self.progress.setRange(0, 100)
|
||||
self.progress.setValue(0)
|
||||
|
||||
def _update_status(self):
|
||||
"""Update status label."""
|
||||
total = len(self.all_rings) + len(self.all_clothing) + len(self.all_pets)
|
||||
if total > 0:
|
||||
self.status_label.setText(
|
||||
f"Loaded {len(self.all_rings)} rings, "
|
||||
f"{len(self.all_clothing)} clothing items, "
|
||||
f"{len(self.all_pets)} pets"
|
||||
)
|
||||
self.progress.setRange(0, 100)
|
||||
self.progress.setValue(100)
|
||||
|
||||
def _populate_rings(self):
|
||||
"""Populate rings tree."""
|
||||
tree = self.tab_rings["tree"]
|
||||
tree.clear()
|
||||
|
||||
for ring in self.all_rings:
|
||||
item = QTreeWidgetItem()
|
||||
item.setText(0, ring.name)
|
||||
item.setText(1, ring.effect_type)
|
||||
item.setText(2, str(ring.effect_value))
|
||||
item.setText(3, "Left/Right")
|
||||
item.setText(4, "Yes" if ring.is_limited else "No")
|
||||
|
||||
# Color limited items
|
||||
if ring.is_limited:
|
||||
item.setForeground(4, QColor("#ff9800"))
|
||||
|
||||
item.setData(0, Qt.ItemDataRole.UserRole, ring)
|
||||
tree.addTopLevelItem(item)
|
||||
|
||||
# Connect filters
|
||||
self.tab_rings["search"].textChanged.connect(self._filter_rings)
|
||||
self.tab_rings["clear"].clicked.connect(self.tab_rings["search"].clear)
|
||||
|
||||
def _populate_clothing(self):
|
||||
"""Populate clothing tree."""
|
||||
tree = self.tab_clothing["tree"]
|
||||
tree.clear()
|
||||
|
||||
for item_data in self.all_clothing:
|
||||
item = QTreeWidgetItem()
|
||||
item.setText(0, item_data.name)
|
||||
item.setText(1, item_data.slot)
|
||||
buffs = ", ".join([f"{k}:{v}" for k, v in item_data.buffs.items()])
|
||||
item.setText(2, buffs if buffs else "None")
|
||||
item.setText(3, "Yes" if item_data.is_cosmetic else "No")
|
||||
|
||||
# Color cosmetic items
|
||||
if not item_data.is_cosmetic:
|
||||
item.setForeground(3, QColor("#4caf50"))
|
||||
|
||||
item.setData(0, Qt.ItemDataRole.UserRole, item_data)
|
||||
tree.addTopLevelItem(item)
|
||||
|
||||
# Connect filters
|
||||
self.tab_clothing["search"].textChanged.connect(self._filter_clothing)
|
||||
self.tab_clothing["clear"].clicked.connect(self.tab_clothing["search"].clear)
|
||||
|
||||
def _populate_pets(self):
|
||||
"""Populate pets tree."""
|
||||
tree = self.tab_pets["tree"]
|
||||
tree.clear()
|
||||
|
||||
for pet in self.all_pets:
|
||||
item = QTreeWidgetItem()
|
||||
item.setText(0, pet.name)
|
||||
item.setText(1, pet.effect_type)
|
||||
item.setText(2, str(pet.effect_value))
|
||||
item.setText(3, str(pet.level_required) if pet.level_required > 0 else "-")
|
||||
|
||||
# Color by level requirement
|
||||
if pet.level_required > 50:
|
||||
item.setForeground(3, QColor("#f44336")) # Red
|
||||
elif pet.level_required > 20:
|
||||
item.setForeground(3, QColor("#ff9800")) # Orange
|
||||
|
||||
item.setData(0, Qt.ItemDataRole.UserRole, pet)
|
||||
tree.addTopLevelItem(item)
|
||||
|
||||
# Connect filters
|
||||
self.tab_pets["search"].textChanged.connect(self._filter_pets)
|
||||
self.tab_pets["clear"].clicked.connect(self.tab_pets["search"].clear)
|
||||
|
||||
def _filter_rings(self):
|
||||
"""Filter rings based on search and filters."""
|
||||
search = self.tab_rings["search"].text().lower()
|
||||
tree = self.tab_rings["tree"]
|
||||
|
||||
for i in range(tree.topLevelItemCount()):
|
||||
item = tree.topLevelItem(i)
|
||||
ring = item.data(0, Qt.ItemDataRole.UserRole)
|
||||
visible = search in ring.name.lower() or search in ring.effect_type.lower()
|
||||
item.setHidden(not visible)
|
||||
|
||||
def _filter_clothing(self):
|
||||
"""Filter clothing based on search and filters."""
|
||||
search = self.tab_clothing["search"].text().lower()
|
||||
tree = self.tab_clothing["tree"]
|
||||
|
||||
for i in range(tree.topLevelItemCount()):
|
||||
item = tree.topLevelItem(i)
|
||||
clothing = item.data(0, Qt.ItemDataRole.UserRole)
|
||||
visible = search in clothing.name.lower() or search in clothing.slot.lower()
|
||||
item.setHidden(not visible)
|
||||
|
||||
def _filter_pets(self):
|
||||
"""Filter pets based on search."""
|
||||
search = self.tab_pets["search"].text().lower()
|
||||
tree = self.tab_pets["tree"]
|
||||
|
||||
for i in range(tree.topLevelItemCount()):
|
||||
item = tree.topLevelItem(i)
|
||||
pet = item.data(0, Qt.ItemDataRole.UserRole)
|
||||
visible = search in pet.name.lower() or search in pet.effect_type.lower()
|
||||
item.setHidden(not visible)
|
||||
|
||||
def _on_tab_changed(self, index: int):
|
||||
"""Handle tab change."""
|
||||
self.selected_ring = None
|
||||
self.selected_clothing = None
|
||||
self.selected_pet = None
|
||||
self.ok_button.setEnabled(False)
|
||||
self.preview_name.setText("-")
|
||||
self.preview_type.setText("-")
|
||||
self.preview_effect.setText("-")
|
||||
self.preview_extra.setText("-")
|
||||
|
||||
def _on_selection_changed(self):
|
||||
"""Handle selection change."""
|
||||
index = self.tabs.currentIndex()
|
||||
|
||||
if index == 0: # Rings
|
||||
items = self.tab_rings["tree"].selectedItems()
|
||||
if items:
|
||||
self.selected_ring = items[0].data(0, Qt.ItemDataRole.UserRole)
|
||||
self._update_preview_ring(self.selected_ring)
|
||||
self.ok_button.setEnabled(True)
|
||||
elif index == 1: # Clothing
|
||||
items = self.tab_clothing["tree"].selectedItems()
|
||||
if items:
|
||||
self.selected_clothing = items[0].data(0, Qt.ItemDataRole.UserRole)
|
||||
self._update_preview_clothing(self.selected_clothing)
|
||||
self.ok_button.setEnabled(True)
|
||||
elif index == 2: # Pets
|
||||
items = self.tab_pets["tree"].selectedItems()
|
||||
if items:
|
||||
self.selected_pet = items[0].data(0, Qt.ItemDataRole.UserRole)
|
||||
self._update_preview_pet(self.selected_pet)
|
||||
self.ok_button.setEnabled(True)
|
||||
|
||||
def _update_preview_ring(self, ring: NexusRing):
|
||||
"""Update preview for ring."""
|
||||
self.preview_name.setText(ring.name)
|
||||
self.preview_type.setText("Ring (Left/Right)")
|
||||
self.preview_effect.setText(f"{ring.effect_type}: {ring.effect_value}")
|
||||
self.preview_extra.setText(f"Limited: {'Yes' if ring.is_limited else 'No'}")
|
||||
|
||||
def _update_preview_clothing(self, clothing: NexusClothing):
|
||||
"""Update preview for clothing."""
|
||||
self.preview_name.setText(clothing.name)
|
||||
self.preview_type.setText(f"Clothing ({clothing.slot})")
|
||||
buffs = ", ".join([f"{k}:{v}" for k, v in clothing.buffs.items()])
|
||||
self.preview_effect.setText(buffs if buffs else "No buffs")
|
||||
self.preview_extra.setText(f"Cosmetic: {'Yes' if clothing.is_cosmetic else 'No'}")
|
||||
|
||||
def _update_preview_pet(self, pet: NexusPet):
|
||||
"""Update preview for pet."""
|
||||
self.preview_name.setText(pet.name)
|
||||
self.preview_type.setText("Combat Pet")
|
||||
self.preview_effect.setText(f"{pet.effect_type}: {pet.effect_value}")
|
||||
self.preview_extra.setText(f"Level Required: {pet.level_required}" if pet.level_required > 0 else "No level requirement")
|
||||
|
||||
def _on_double_click(self, item, column):
|
||||
"""Handle double click."""
|
||||
self._on_accept()
|
||||
|
||||
def _on_accept(self):
|
||||
"""Handle OK button."""
|
||||
index = self.tabs.currentIndex()
|
||||
|
||||
if index == 0 and self.selected_ring:
|
||||
self.ring_selected.emit(self.selected_ring)
|
||||
self.accept()
|
||||
elif index == 1 and self.selected_clothing:
|
||||
self.clothing_selected.emit(self.selected_clothing)
|
||||
self.accept()
|
||||
elif index == 2 and self.selected_pet:
|
||||
self.pet_selected.emit(self.selected_pet)
|
||||
self.accept()
|
||||
|
|
@ -0,0 +1,313 @@
|
|||
"""
|
||||
Enhancer Selector for Lemontropia Suite
|
||||
Browse and search weapon/armor enhancers
|
||||
"""
|
||||
|
||||
from decimal import Decimal
|
||||
from PyQt6.QtWidgets import (
|
||||
QDialog, QVBoxLayout, QHBoxLayout, QLineEdit, QPushButton,
|
||||
QTreeWidget, QTreeWidgetItem, QHeaderView, QLabel, QDialogButtonBox,
|
||||
QProgressBar, QGroupBox, QFormLayout, QComboBox, QCheckBox
|
||||
)
|
||||
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, NexusEnhancer
|
||||
|
||||
|
||||
class EnhancerLoaderThread(QThread):
|
||||
"""Background thread for loading enhancers from API."""
|
||||
enhancers_loaded = pyqtSignal(list)
|
||||
error_occurred = pyqtSignal(str)
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
api = get_nexus_api()
|
||||
enhancers = api.get_all_enhancers()
|
||||
self.enhancers_loaded.emit(enhancers)
|
||||
except Exception as e:
|
||||
self.error_occurred.emit(str(e))
|
||||
|
||||
|
||||
class EnhancerSelectorDialog(QDialog):
|
||||
"""Dialog for selecting enhancers from Entropia Nexus API."""
|
||||
|
||||
enhancer_selected = pyqtSignal(NexusEnhancer)
|
||||
|
||||
def __init__(self, parent=None, enhancer_type: str = "", target_tier: int = 1):
|
||||
super().__init__(parent)
|
||||
self.preferred_type = enhancer_type.lower()
|
||||
self.target_tier = target_tier
|
||||
|
||||
type_names = {
|
||||
"damage": "Damage Enhancer",
|
||||
"economy": "Economy Enhancer",
|
||||
"range": "Range Enhancer",
|
||||
"accuracy": "Accuracy Enhancer",
|
||||
"skillmod": "Skill Mod Enhancer"
|
||||
}
|
||||
title_type = type_names.get(self.preferred_type, "Enhancer")
|
||||
|
||||
self.setWindowTitle(f"Select {title_type} - Entropia Nexus")
|
||||
self.setMinimumSize(900, 600)
|
||||
|
||||
self.all_enhancers: List[NexusEnhancer] = []
|
||||
self.selected_enhancer: Optional[NexusEnhancer] = None
|
||||
|
||||
self._setup_ui()
|
||||
self._load_data()
|
||||
|
||||
def _setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
layout.setSpacing(10)
|
||||
|
||||
# Warning about enhancer breakage
|
||||
warning = QLabel("⚠️ Warning: Enhancers have a chance to break on each use!")
|
||||
warning.setStyleSheet("color: #ff9800; font-weight: bold; padding: 5px;")
|
||||
layout.addWidget(warning)
|
||||
|
||||
# Status
|
||||
self.status_label = QLabel("Loading enhancers 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("Type:"))
|
||||
self.type_combo = QComboBox()
|
||||
self.type_combo.addItems([
|
||||
"All Types", "Damage", "Economy", "Range",
|
||||
"Accuracy", "Skill Mod", "Defense", "Durability"
|
||||
])
|
||||
if self.preferred_type:
|
||||
# Map type names
|
||||
type_map = {
|
||||
"damage": "Damage",
|
||||
"economy": "Economy",
|
||||
"range": "Range",
|
||||
"accuracy": "Accuracy",
|
||||
"skillmod": "Skill Mod"
|
||||
}
|
||||
preferred = type_map.get(self.preferred_type, "")
|
||||
index = self.type_combo.findText(preferred)
|
||||
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("Tier:"))
|
||||
self.tier_combo = QComboBox()
|
||||
self.tier_combo.addItems(["All Tiers", "Tier 1", "Tier 2", "Tier 3", "Tier 4", "Tier 5+"])
|
||||
if self.target_tier > 0 and self.target_tier <= 5:
|
||||
self.tier_combo.setCurrentIndex(self.target_tier)
|
||||
self.tier_combo.currentTextChanged.connect(self._apply_filters)
|
||||
filter_layout.addWidget(self.tier_combo)
|
||||
|
||||
# Show breakable only
|
||||
self.breakable_check = QCheckBox("Show breakable only")
|
||||
self.breakable_check.setChecked(False)
|
||||
self.breakable_check.stateChanged.connect(self._apply_filters)
|
||||
filter_layout.addWidget(self.breakable_check)
|
||||
|
||||
layout.addLayout(filter_layout)
|
||||
|
||||
# Search
|
||||
search_layout = QHBoxLayout()
|
||||
search_layout.addWidget(QLabel("Search:"))
|
||||
self.search_input = QLineEdit()
|
||||
self.search_input.setPlaceholderText("Search enhancers...")
|
||||
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", "Type", "Tier", "Effect", "Break Chance", "Risk Level"
|
||||
])
|
||||
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("Enhancer Preview")
|
||||
preview_layout = QFormLayout(self.preview_group)
|
||||
self.preview_name = QLabel("-")
|
||||
self.preview_type = QLabel("-")
|
||||
self.preview_tier = QLabel("-")
|
||||
self.preview_effect = QLabel("-")
|
||||
self.preview_break = QLabel("-")
|
||||
preview_layout.addRow("Name:", self.preview_name)
|
||||
preview_layout.addRow("Type:", self.preview_type)
|
||||
preview_layout.addRow("Tier:", self.preview_tier)
|
||||
preview_layout.addRow("Effect:", self.preview_effect)
|
||||
preview_layout.addRow("Break Chance:", self.preview_break)
|
||||
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 enhancers in background thread."""
|
||||
self.loader = EnhancerLoaderThread()
|
||||
self.loader.enhancers_loaded.connect(self._on_enhancers_loaded)
|
||||
self.loader.error_occurred.connect(self._on_load_error)
|
||||
self.loader.start()
|
||||
|
||||
def _on_enhancers_loaded(self, enhancers: List[NexusEnhancer]):
|
||||
"""Handle loaded enhancers."""
|
||||
self.all_enhancers = enhancers
|
||||
self.status_label.setText(f"Loaded {len(enhancers)} enhancers 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 enhancers: {error}")
|
||||
self.progress.setRange(0, 100)
|
||||
self.progress.setValue(0)
|
||||
|
||||
def _apply_filters(self):
|
||||
"""Apply all filters and search."""
|
||||
enhancers = self.all_enhancers.copy()
|
||||
|
||||
# Type filter
|
||||
type_filter = self.type_combo.currentText()
|
||||
if type_filter != "All Types":
|
||||
type_lower = type_filter.lower().replace(" ", "")
|
||||
enhancers = [e for e in enhancers if type_lower in e.enhancer_type.lower()]
|
||||
|
||||
# Tier filter
|
||||
tier_filter = self.tier_combo.currentText()
|
||||
if tier_filter != "All Tiers":
|
||||
if tier_filter == "Tier 5+":
|
||||
enhancers = [e for e in enhancers if e.tier >= 5]
|
||||
else:
|
||||
tier_num = int(tier_filter.replace("Tier ", ""))
|
||||
enhancers = [e for e in enhancers if e.tier == tier_num]
|
||||
|
||||
# Breakable filter
|
||||
if self.breakable_check.isChecked():
|
||||
enhancers = [e for e in enhancers if e.break_chance > 0]
|
||||
|
||||
# Search filter
|
||||
search_text = self.search_input.text()
|
||||
if search_text:
|
||||
query = search_text.lower()
|
||||
enhancers = [e for e in enhancers if query in e.name.lower()]
|
||||
|
||||
self._populate_results(enhancers)
|
||||
|
||||
# Update status
|
||||
if search_text:
|
||||
self.status_label.setText(f"Found {len(enhancers)} enhancers matching '{search_text}'")
|
||||
else:
|
||||
self.status_label.setText(f"Showing {len(enhancers)} of {len(self.all_enhancers)} enhancers")
|
||||
|
||||
def _populate_results(self, enhancers: List[NexusEnhancer]):
|
||||
"""Populate results tree."""
|
||||
self.results_tree.clear()
|
||||
|
||||
# Sort by tier (lowest first - safer) then effect value
|
||||
enhancers = sorted(enhancers, key=lambda e: (e.tier, -e.effect_value))
|
||||
|
||||
for enhancer in enhancers:
|
||||
item = QTreeWidgetItem()
|
||||
item.setText(0, enhancer.name)
|
||||
item.setText(1, enhancer.enhancer_type.title())
|
||||
item.setText(2, str(enhancer.tier))
|
||||
item.setText(3, f"+{enhancer.effect_value}%")
|
||||
item.setText(4, f"{enhancer.break_chance * 100:.1f}%")
|
||||
|
||||
# Risk level
|
||||
if enhancer.break_chance <= 0.01:
|
||||
risk = "Low"
|
||||
color = QColor("#4caf50") # Green
|
||||
elif enhancer.break_chance <= 0.05:
|
||||
risk = "Medium"
|
||||
color = QColor("#ff9800") # Orange
|
||||
else:
|
||||
risk = "High"
|
||||
color = QColor("#f44336") # Red
|
||||
|
||||
item.setText(5, risk)
|
||||
item.setForeground(5, color)
|
||||
|
||||
# Color code tier
|
||||
tier_colors = {
|
||||
1: QColor("#4caf50"), # Green
|
||||
2: QColor("#8bc34a"), # Light green
|
||||
3: QColor("#ff9800"), # Orange
|
||||
4: QColor("#ff5722"), # Deep orange
|
||||
5: QColor("#f44336"), # Red
|
||||
}
|
||||
if enhancer.tier in tier_colors:
|
||||
item.setForeground(2, tier_colors[enhancer.tier])
|
||||
|
||||
item.setData(0, Qt.ItemDataRole.UserRole, enhancer)
|
||||
self.results_tree.addTopLevelItem(item)
|
||||
|
||||
def _clear_search(self):
|
||||
"""Clear search and filters."""
|
||||
self.search_input.clear()
|
||||
self.type_combo.setCurrentIndex(0)
|
||||
self.tier_combo.setCurrentIndex(0)
|
||||
self.breakable_check.setChecked(False)
|
||||
self._apply_filters()
|
||||
|
||||
def _on_selection_changed(self):
|
||||
"""Handle selection change."""
|
||||
items = self.results_tree.selectedItems()
|
||||
if items:
|
||||
self.selected_enhancer = items[0].data(0, Qt.ItemDataRole.UserRole)
|
||||
self.ok_button.setEnabled(True)
|
||||
self._update_preview(self.selected_enhancer)
|
||||
else:
|
||||
self.selected_enhancer = None
|
||||
self.ok_button.setEnabled(False)
|
||||
|
||||
def _update_preview(self, enhancer: NexusEnhancer):
|
||||
"""Update preview panel."""
|
||||
self.preview_name.setText(enhancer.name)
|
||||
self.preview_type.setText(enhancer.enhancer_type.title())
|
||||
self.preview_tier.setText(str(enhancer.tier))
|
||||
self.preview_effect.setText(f"+{enhancer.effect_value}%")
|
||||
self.preview_break.setText(f"{enhancer.break_chance * 100:.1f}%")
|
||||
|
||||
# Color code break chance
|
||||
if enhancer.break_chance <= 0.01:
|
||||
self.preview_break.setStyleSheet("color: #4caf50;") # Green
|
||||
elif enhancer.break_chance <= 0.05:
|
||||
self.preview_break.setStyleSheet("color: #ff9800;") # Orange
|
||||
else:
|
||||
self.preview_break.setStyleSheet("color: #f44336;") # Red
|
||||
|
||||
def _on_double_click(self, item, column):
|
||||
"""Handle double click."""
|
||||
self._on_accept()
|
||||
|
||||
def _on_accept(self):
|
||||
"""Handle OK button."""
|
||||
if self.selected_enhancer:
|
||||
self.enhancer_selected.emit(self.selected_enhancer)
|
||||
self.accept()
|
||||
Loading…
Reference in New Issue