diff --git a/ui/accessories_selector.py b/ui/accessories_selector.py new file mode 100644 index 0000000..427b0d6 --- /dev/null +++ b/ui/accessories_selector.py @@ -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() diff --git a/ui/enhancer_selector.py b/ui/enhancer_selector.py new file mode 100644 index 0000000..0624ffc --- /dev/null +++ b/ui/enhancer_selector.py @@ -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()