""" Lemontropia Suite - Loadout Selection Dialog v2.0 Simplified cost-focused selection. """ import json import logging from decimal import Decimal from pathlib import Path from PyQt6.QtWidgets import ( QDialog, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QListWidget, QListWidgetItem, QMessageBox, QWidget, QGridLayout ) from PyQt6.QtCore import Qt, pyqtSignal from ui.loadout_manager_simple import LoadoutConfig logger = logging.getLogger(__name__) class LoadoutSelectionDialog(QDialog): """Simplified dialog for selecting a loadout to start a session. Emits cost data that can be used directly by MainWindow for tracking. """ # Signal emits: { # 'id': 0, # 0 = file-based # 'name': 'Loadout Name', # 'source': 'file', # 'costs': { # 'cost_per_shot': Decimal, # 'cost_per_hit': Decimal, # 'cost_per_heal': Decimal, # }, # 'display': { # 'weapon_name': str, # 'armor_name': str, # 'healing_name': str, # } # } loadout_selected = pyqtSignal(dict) def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("Select Loadout for Session") self.setMinimumSize(500, 400) self.config_dir = Path.home() / ".lemontropia" / "loadouts" self.selected_loadout = None self._setup_ui() self._load_loadouts() def _setup_ui(self): """Setup simple UI.""" layout = QVBoxLayout(self) layout.setSpacing(10) # Header header = QLabel("Select a loadout to track costs during your session:") header.setStyleSheet("font-size: 12px; color: #888;") layout.addWidget(header) # Loadout list self.loadout_list = QListWidget() self.loadout_list.itemClicked.connect(self._on_select) self.loadout_list.itemDoubleClicked.connect(self._on_double_click) layout.addWidget(self.loadout_list) # Preview panel self.preview = QWidget() preview_layout = QGridLayout(self.preview) # Weapon preview_layout.addWidget(QLabel("⚔️ Weapon:"), 0, 0) self.preview_weapon = QLabel("-") preview_layout.addWidget(self.preview_weapon, 0, 1) preview_layout.addWidget(QLabel(" Cost/Shot:"), 1, 0) self.preview_cost_shot = QLabel("-") self.preview_cost_shot.setStyleSheet("color: #7FFF7F;") preview_layout.addWidget(self.preview_cost_shot, 1, 1) # Armor preview_layout.addWidget(QLabel("🛡️ Armor:"), 2, 0) self.preview_armor = QLabel("-") preview_layout.addWidget(self.preview_armor, 2, 1) preview_layout.addWidget(QLabel(" Cost/Hit:"), 3, 0) self.preview_cost_hit = QLabel("-") self.preview_cost_hit.setStyleSheet("color: #7FFF7F;") preview_layout.addWidget(self.preview_cost_hit, 3, 1) # Healing preview_layout.addWidget(QLabel("💚 Healing:"), 4, 0) self.preview_healing = QLabel("-") preview_layout.addWidget(self.preview_healing, 4, 1) preview_layout.addWidget(QLabel(" Cost/Heal:"), 5, 0) self.preview_cost_heal = QLabel("-") self.preview_cost_heal.setStyleSheet("color: #7FFF7F;") preview_layout.addWidget(self.preview_cost_heal, 5, 1) preview_layout.setColumnStretch(1, 1) layout.addWidget(self.preview) # Buttons button_layout = QHBoxLayout() button_layout.addStretch() self.skip_btn = QPushButton("Skip (No Cost Tracking)") self.skip_btn.clicked.connect(self._on_skip) self.skip_btn.setStyleSheet("color: #888;") button_layout.addWidget(self.skip_btn) self.ok_btn = QPushButton("Start Session ▶") self.ok_btn.clicked.connect(self._on_accept) self.ok_btn.setEnabled(False) self.ok_btn.setStyleSheet(""" QPushButton { background-color: #2E7D32; color: white; padding: 8px 16px; font-weight: bold; } QPushButton:disabled { background-color: #333; color: #666; } """) button_layout.addWidget(self.ok_btn) self.cancel_btn = QPushButton("Cancel") self.cancel_btn.clicked.connect(self.reject) button_layout.addWidget(self.cancel_btn) layout.addLayout(button_layout) def _load_loadouts(self): """Load all saved loadouts.""" self.loadout_list.clear() self.loadouts = [] if not self.config_dir.exists(): return try: for filepath in sorted(self.config_dir.glob("*.json")): try: with open(filepath, 'r') as f: data = json.load(f) config = LoadoutConfig.from_dict(data) # Build display text has_costs = ( config.weapon_cost_per_shot > 0 or config.armor_cost_per_hit > 0 or config.healing_cost_per_heal > 0 ) display = f"📋 {config.name}" if has_costs: display += f" (💰 {config.weapon_cost_per_shot:.3f}/shot)" item = QListWidgetItem(display) item.setData(Qt.ItemDataRole.UserRole, config) # Tooltip tooltip = ( f"Weapon: {config.weapon_name}\n" f"Armor: {config.armor_name}\n" f"Healing: {config.healing_name}\n" f"\n" f"Cost/Shot: {config.weapon_cost_per_shot:.4f} PED\n" f"Cost/Hit: {config.armor_cost_per_hit:.4f} PED\n" f"Cost/Heal: {config.healing_cost_per_heal:.4f} PED" ) item.setToolTip(tooltip) self.loadout_list.addItem(item) self.loadouts.append(config) except Exception as e: logger.error(f"Failed to load {filepath}: {e}") except Exception as e: logger.error(f"Failed to list loadouts: {e}") if not self.loadouts: item = QListWidgetItem("(No saved loadouts)") item.setFlags(Qt.ItemFlag.NoItemFlags) self.loadout_list.addItem(item) def _on_select(self, item: QListWidgetItem): """Update preview when loadout selected.""" config = item.data(Qt.ItemDataRole.UserRole) if not isinstance(config, LoadoutConfig): return self.selected_loadout = config # Update preview self.preview_weapon.setText(config.weapon_name if config.weapon_name != "None" else "Not set") self.preview_armor.setText(config.armor_name if config.armor_name != "None" else "Not set") self.preview_healing.setText(config.healing_name if config.healing_name != "None" else "Not set") self.preview_cost_shot.setText(f"{config.weapon_cost_per_shot:.4f} PED") self.preview_cost_hit.setText(f"{config.armor_cost_per_hit:.4f} PED") self.preview_cost_heal.setText(f"{config.healing_cost_per_heal:.4f} PED") self.ok_btn.setEnabled(True) def _on_double_click(self, item: QListWidgetItem): """Double-click to select immediately.""" self._on_select(item) self._on_accept() def _on_skip(self): """Start session without cost tracking.""" self.loadout_selected.emit({ 'id': 0, 'name': 'No Loadout', 'source': 'none', 'costs': { 'cost_per_shot': Decimal('0'), 'cost_per_hit': Decimal('0'), 'cost_per_heal': Decimal('0'), }, 'display': { 'weapon_name': 'None', 'armor_name': 'None', 'healing_name': 'None', } }) self.accept() def _on_accept(self): """Emit selected loadout and close.""" if not self.selected_loadout: QMessageBox.warning(self, "No Selection", "Please select a loadout") return config = self.selected_loadout self.loadout_selected.emit({ 'id': 0, # File-based 'name': config.name, 'source': 'file', 'costs': { 'cost_per_shot': config.weapon_cost_per_shot, 'cost_per_hit': config.armor_cost_per_hit, 'cost_per_heal': config.healing_cost_per_heal, }, 'display': { 'weapon_name': config.weapon_name, 'armor_name': config.armor_name, 'healing_name': config.healing_name, } }) self.accept()