Lemontropia-Suite/ui/icon_price_dialogs.py

361 lines
12 KiB
Python

"""
Lemontropia Suite - Icon Browser UI
GUI for browsing and exporting item icons.
"""
from pathlib import Path
from PyQt6.QtWidgets import (
QDialog, QVBoxLayout, QHBoxLayout, QLabel, QPushButton,
QListWidget, QListWidgetItem, QFileDialog, QMessageBox,
QLineEdit, QComboBox, QProgressBar
)
from PyQt6.QtCore import Qt, QThread, pyqtSignal
from PyQt6.QtGui import QPixmap, QIcon
from modules.icon_manager import IconManager
class IconDownloadWorker(QThread):
"""Background worker for downloading icons."""
progress = pyqtSignal(int)
finished_item = pyqtSignal(str, bool)
finished_all = pyqtSignal()
def __init__(self, icon_manager: IconManager, item_names: list, size: str):
super().__init__()
self.icon_manager = icon_manager
self.item_names = item_names
self.size = size
def run(self):
for i, item_name in enumerate(self.item_names):
path = self.icon_manager.get_icon(item_name, self.size)
self.progress.emit(int((i + 1) / len(self.item_names) * 100))
self.finished_item.emit(item_name, path is not None)
self.finished_all.emit()
class IconBrowserDialog(QDialog):
"""
Dialog for browsing, previewing, and exporting item icons.
"""
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("Icon Browser")
self.setMinimumSize(600, 500)
self.icon_manager = IconManager()
self.current_preview = None
self._setup_ui()
self._load_cached_icons()
def _setup_ui(self):
layout = QVBoxLayout(self)
# Search bar
search_layout = QHBoxLayout()
search_layout.addWidget(QLabel("Search:"))
self.search_edit = QLineEdit()
self.search_edit.setPlaceholderText("Enter item name...")
self.search_edit.returnPressed.connect(self._on_search)
search_layout.addWidget(self.search_edit)
self.size_combo = QComboBox()
self.size_combo.addItems(['small (32x32)', 'medium (64x64)', 'large (128x128)'])
search_layout.addWidget(self.size_combo)
self.search_btn = QPushButton("Download")
self.search_btn.clicked.connect(self._on_search)
search_layout.addWidget(self.search_btn)
layout.addLayout(search_layout)
# Progress bar (hidden initially)
self.progress = QProgressBar()
self.progress.setVisible(False)
layout.addWidget(self.progress)
# Main content
content = QHBoxLayout()
# Icon list
self.icon_list = QListWidget()
self.icon_list.itemClicked.connect(self._on_item_selected)
content.addWidget(self.icon_list, 1)
# Preview panel
preview_panel = QVBoxLayout()
self.preview_label = QLabel("No icon selected")
self.preview_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.preview_label.setMinimumSize(200, 200)
self.preview_label.setStyleSheet("background-color: #1a1a1a; border: 1px solid #333;")
preview_panel.addWidget(self.preview_label)
self.item_name_label = QLabel("")
self.item_name_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
preview_panel.addWidget(self.item_name_label)
# Export buttons
export_layout = QVBoxLayout()
self.export_single_btn = QPushButton("Export This Icon")
self.export_single_btn.clicked.connect(self._export_single)
self.export_single_btn.setEnabled(False)
export_layout.addWidget(self.export_single_btn)
self.export_all_btn = QPushButton("Export All Icons")
self.export_all_btn.clicked.connect(self._export_all)
export_layout.addWidget(self.export_all_btn)
self.clear_cache_btn = QPushButton("Clear Cache")
self.clear_cache_btn.clicked.connect(self._clear_cache)
export_layout.addWidget(self.clear_cache_btn)
preview_panel.addLayout(export_layout)
preview_panel.addStretch()
content.addLayout(preview_panel, 1)
layout.addLayout(content, 1)
# Status bar
self.status_label = QLabel("Ready")
layout.addWidget(self.status_label)
# Close button
btn_layout = QHBoxLayout()
btn_layout.addStretch()
close_btn = QPushButton("Close")
close_btn.clicked.connect(self.accept)
btn_layout.addWidget(close_btn)
layout.addLayout(btn_layout)
def _load_cached_icons(self):
"""Load list of cached icons."""
self.icon_list.clear()
cache_dir = self.icon_manager.wiki.cache_dir
if cache_dir.exists():
for icon_file in sorted(cache_dir.glob("*.png")):
item_name = icon_file.stem.split('_')[0] # Remove size suffix
item = QListWidgetItem(item_name)
item.setData(Qt.ItemDataRole.UserRole, str(icon_file))
self.icon_list.addItem(item)
stats = self.icon_manager.get_cache_stats()
self.status_label.setText(f"Cached icons: {stats['cached_icons']}")
def _on_search(self):
"""Search and download icon."""
item_name = self.search_edit.text().strip()
if not item_name:
return
size_text = self.size_combo.currentText()
size = size_text.split(' ')[0] # 'small', 'medium', 'large'
self.status_label.setText(f"Downloading: {item_name}...")
# Download in background
path = self.icon_manager.get_icon(item_name, size)
if path:
self.status_label.setText(f"Downloaded: {item_name}")
self._load_cached_icons() # Refresh list
# Select the new item
for i in range(self.icon_list.count()):
if item_name.lower() in self.icon_list.item(i).text().lower():
self.icon_list.setCurrentRow(i)
self._on_item_selected(self.icon_list.item(i))
break
else:
QMessageBox.warning(self, "Not Found",
f"Icon not found for: {item_name}\n\n"
"The item may not exist on EntropiaWiki.")
self.status_label.setText("Icon not found")
def _on_item_selected(self, item: QListWidgetItem):
"""Preview selected icon."""
icon_path = item.data(Qt.ItemDataRole.UserRole)
item_name = item.text()
if icon_path and Path(icon_path).exists():
pixmap = QPixmap(icon_path)
# Scale to fit preview while maintaining aspect ratio
scaled = pixmap.scaled(
180, 180,
Qt.AspectRatioMode.KeepAspectRatio,
Qt.TransformationMode.SmoothTransformation
)
self.preview_label.setPixmap(scaled)
self.current_preview = icon_path
self.item_name_label.setText(item_name)
self.export_single_btn.setEnabled(True)
def _export_single(self):
"""Export currently selected icon."""
if not self.current_preview:
return
item_name = self.item_name_label.text()
filepath, _ = QFileDialog.getSaveFileName(
self, "Export Icon", f"{item_name}.png", "PNG Images (*.png)"")
if filepath:
import shutil
shutil.copy2(self.current_preview, filepath)
QMessageBox.information(self, "Exported", f"Icon exported to:\n{filepath}")
def _export_all(self):
"""Export all cached icons."""
export_dir = QFileDialog.getExistingDirectory(self, "Select Export Directory")
if export_dir:
results = self.icon_manager.batch_export_icons(
[self.icon_list.item(i).text() for i in range(self.icon_list.count())],
Path(export_dir)
)
success_count = sum(1 for _, success in results if success)
QMessageBox.information(self, "Export Complete",
f"Exported {success_count}/{len(results)} icons")
def _clear_cache(self):
"""Clear icon cache."""
reply = QMessageBox.question(self, "Clear Cache",
"Delete all cached icons?\nThey will be re-downloaded when needed.",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
if reply == QMessageBox.StandardButton.Yes:
self.icon_manager.clear_cache()
self._load_cached_icons()
self.preview_label.setText("No icon selected")
self.item_name_label.setText("")
self.export_single_btn.setEnabled(False)
class PriceTrackerDialog(QDialog):
"""
Dialog for managing item prices and markups.
"""
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("Price Tracker")
self.setMinimumSize(500, 400)
from modules.market_prices import ManualPriceTracker
self.price_tracker = ManualPriceTracker()
self._setup_ui()
self._load_prices()
def _setup_ui(self):
layout = QVBoxLayout(self)
# Price list
layout.addWidget(QLabel("Tracked Item Prices:"))
self.price_list = QListWidget()
self.price_list.itemClicked.connect(self._on_item_selected)
layout.addWidget(self.price_list)
# Add/Edit panel
form = QHBoxLayout()
form.addWidget(QLabel("Item:"))
self.item_edit = QLineEdit()
form.addWidget(self.item_edit)
form.addWidget(QLabel("MU %:"))
self.mu_edit = QLineEdit()
self.mu_edit.setMaximumWidth(60)
form.addWidget(self.mu_edit)
form.addWidget(QLabel("TT:"))
self.tt_edit = QLineEdit()
self.tt_edit.setMaximumWidth(80)
form.addWidget(self.tt_edit)
self.add_btn = QPushButton("Add/Update")
self.add_btn.clicked.connect(self._add_price)
form.addWidget(self.add_btn)
layout.addLayout(form)
# Buttons
btn_layout = QHBoxLayout()
btn_layout.addStretch()
delete_btn = QPushButton("Delete Selected")
delete_btn.clicked.connect(self._delete_selected)
btn_layout.addWidget(delete_btn)
close_btn = QPushButton("Close")
close_btn.clicked.connect(self.accept)
btn_layout.addWidget(close_btn)
layout.addLayout(btn_layout)
def _load_prices(self):
"""Load prices into list."""
self.price_list.clear()
for item_name, price in self.price_tracker.prices.items():
display = f"{item_name} - {price.markup}% (MU: {price.mu_value:.2f} PED)"
item = QListWidgetItem(display)
item.setData(Qt.ItemDataRole.UserRole, item_name)
self.price_list.addItem(item)
def _on_item_selected(self, item: QListWidgetItem):
"""Fill form with selected item."""
item_name = item.data(Qt.ItemDataRole.UserRole)
price = self.price_tracker.get_price(item_name)
if price:
self.item_edit.setText(item_name)
self.mu_edit.setText(str(price.markup))
self.tt_edit.setText(str(price.tt_value))
def _add_price(self):
"""Add or update price."""
item_name = self.item_edit.text().strip()
try:
markup = float(self.mu_edit.text())
tt = float(self.tt_edit.text())
except ValueError:
QMessageBox.warning(self, "Error", "Invalid numbers")
return
from decimal import Decimal
self.price_tracker.set_price(item_name, Decimal(str(markup)), Decimal(str(tt)))
self._load_prices()
# Clear form
self.item_edit.clear()
self.mu_edit.clear()
self.tt_edit.clear()
def _delete_selected(self):
"""Delete selected price."""
item = self.price_list.currentItem()
if item:
item_name = item.data(Qt.ItemDataRole.UserRole)
if item_name in self.price_tracker.prices:
del self.price_tracker.prices[item_name]
self.price_tracker._save_prices()
self._load_prices()
# Export dialogs
__all__ = ['IconBrowserDialog', 'PriceTrackerDialog']