Lemontropia-Suite/ui/mindforce_selector.py

261 lines
9.5 KiB
Python

"""
Mindforce Implant Selector for Lemontropia Suite
Browse and select mindforce implants 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, NexusMindforceImplant
class MindforceImplantLoaderThread(QThread):
"""Background thread for loading mindforce implants from API."""
implants_loaded = pyqtSignal(list)
error_occurred = pyqtSignal(str)
def run(self):
try:
api = get_nexus_api()
implants = api.get_all_mindforce_implants()
self.implants_loaded.emit(implants)
except Exception as e:
self.error_occurred.emit(str(e))
class MindforceImplantSelectorDialog(QDialog):
"""Dialog for selecting mindforce implants from Entropia Nexus API."""
implant_selected = pyqtSignal(NexusMindforceImplant)
def __init__(self, parent=None, implant_type: str = ""):
super().__init__(parent)
self.preferred_type = implant_type.lower()
type_names = {
"healing": "Healing Chip",
"damage": "Damage Chip",
"utility": "Utility Chip"
}
title_type = type_names.get(self.preferred_type, "Mindforce Implant")
self.setWindowTitle(f"Select {title_type} - Entropia Nexus")
self.setMinimumSize(800, 500)
self.all_implants: List[NexusMindforceImplant] = []
self.selected_implant: Optional[NexusMindforceImplant] = None
self._setup_ui()
self._load_data()
def _setup_ui(self):
layout = QVBoxLayout(self)
layout.setSpacing(10)
# Status
self.status_label = QLabel("Loading mindforce implants 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", "Healing", "Damage", "Utility"])
if self.preferred_type:
type_map = {"healing": 1, "damage": 2, "utility": 3}
self.type_combo.setCurrentIndex(type_map.get(self.preferred_type, 0))
self.type_combo.currentTextChanged.connect(self._filter_implants)
filter_layout.addWidget(self.type_combo)
filter_layout.addWidget(QLabel("Search:"))
self.search_input = QLineEdit()
self.search_input.setPlaceholderText("Search implants...")
self.search_input.textChanged.connect(self._filter_implants)
filter_layout.addWidget(self.search_input)
clear_btn = QPushButton("Clear")
clear_btn.clicked.connect(self.search_input.clear)
filter_layout.addWidget(clear_btn)
layout.addLayout(filter_layout)
# Results tree
self.results_tree = QTreeWidget()
self.results_tree.setHeaderLabels([
"Name", "Type", "Chip Type", "Decay (PEC)", "Prof. Level", "Limited"
])
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("Implant Preview")
preview_layout = QFormLayout(self.preview_group)
self.preview_name = QLabel("-")
self.preview_type = QLabel("-")
self.preview_decay = QLabel("-")
preview_layout.addRow("Name:", self.preview_name)
preview_layout.addRow("Type:", self.preview_type)
preview_layout.addRow("Decay/Use:", 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 implants in background thread."""
self.loader = MindforceImplantLoaderThread()
self.loader.implants_loaded.connect(self._on_implants_loaded)
self.loader.error_occurred.connect(self._on_load_error)
self.loader.start()
def _on_implants_loaded(self, implants: List[NexusMindforceImplant]):
"""Handle loaded implants."""
self.all_implants = implants
self._filter_implants()
self.status_label.setText(f"Loaded {len(implants)} mindforce implants")
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 implants: {error}")
self.progress.setRange(0, 100)
self.progress.setValue(0)
def _populate_results(self, implants: List[NexusMindforceImplant]):
"""Populate results tree."""
self.results_tree.clear()
if not implants:
item = QTreeWidgetItem()
item.setText(0, "No implants available")
item.setForeground(0, QColor("#888888"))
self.results_tree.addTopLevelItem(item)
return
# Sort by decay (lower is better economy)
implants = sorted(implants, key=lambda i: i.decay)
for implant in implants:
item = QTreeWidgetItem()
item.setText(0, implant.name)
item.setText(1, implant.implant_type.title())
item.setText(2, implant.chip_type)
item.setText(3, f"{implant.decay:.2f}")
item.setText(4, str(implant.profession_level) if implant.profession_level > 0 else "-")
item.setText(5, "Yes" if implant.is_limited else "No")
# Color limited items
if implant.is_limited:
item.setForeground(5, QColor("#ff9800"))
# Color by type
if implant.implant_type == "healing":
item.setForeground(1, QColor("#4caf50"))
elif implant.implant_type == "damage":
item.setForeground(1, QColor("#f44336"))
item.setData(0, Qt.ItemDataRole.UserRole, implant)
self.results_tree.addTopLevelItem(item)
def _filter_implants(self):
"""Filter implants based on search and type."""
type_filter = self.type_combo.currentText().lower()
search = self.search_input.text().lower()
filtered = self.all_implants
# Filter by type
if type_filter != "all":
filtered = [i for i in filtered if i.implant_type == type_filter]
# Filter by search
if search:
filtered = [
i for i in filtered
if search in i.name.lower()
or search in i.chip_type.lower()
]
self._populate_results(filtered)
def _on_selection_changed(self):
"""Handle selection change."""
items = self.results_tree.selectedItems()
if items:
self.selected_implant = items[0].data(0, Qt.ItemDataRole.UserRole)
self._update_preview(self.selected_implant)
self.ok_button.setEnabled(True)
else:
self.selected_implant = None
self.ok_button.setEnabled(False)
def _update_preview(self, implant: NexusMindforceImplant):
"""Update preview panel."""
self.preview_name.setText(implant.name)
self.preview_type.setText(f"{implant.implant_type.title()} ({implant.chip_type})")
self.preview_decay.setText(f"{implant.decay:.4f} PEC per use")
# Color by type
if implant.implant_type == "healing":
self.preview_type.setStyleSheet("color: #4caf50;")
elif implant.implant_type == "damage":
self.preview_type.setStyleSheet("color: #f44336;")
else:
self.preview_type.setStyleSheet("color: #4a90d9;")
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_implant:
self.implant_selected.emit(self.selected_implant)
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 = MindforceImplantSelectorDialog()
# Connect signal for testing
dialog.implant_selected.connect(lambda i: print(f"Selected implant: {i.name}"))
if dialog.exec() == QDialog.DialogCode.Accepted:
print("Implant selected!")
sys.exit(0)