fix: standalone extractor - clean UI and icon support

UI Cleanup:
- Removed gamepad from header
- Removed emojis from footer
- Cleaned up group box titles (no emojis in section headers)
- Tighter spacing in all boxes for better fit
- Shorter path displays with tooltips for full paths
- Reduced padding and margins throughout

Layout Improvements:
- Cache Source: Shows shortened path with tooltip for full path
- Output Location: Cleaner display with consistent styling
- All boxes now fit content without overflow
- Reduced minimum window size slightly

Icon Support:
- Added header icon placeholder (48x48)
- _load_icon() method loads icon.ico or icon.png
- Icon appears in window title bar and header
- Falls back gracefully if no icon file present

To add your icon:
Place icon.ico or icon.png in same folder as the script, or in assets/ folder
This commit is contained in:
LemonNexus 2026-02-11 18:47:35 +00:00
parent 77f210f594
commit 3943a5cdf5
1 changed files with 121 additions and 92 deletions

View File

@ -301,6 +301,7 @@ class IconExtractorWindow(QMainWindow):
self.settings = QSettings("ImpulsiveFPS", "EUIconExtractor") self.settings = QSettings("ImpulsiveFPS", "EUIconExtractor")
self._setup_ui() self._setup_ui()
self._load_icon()
self._load_settings() self._load_settings()
self._detect_subfolders() self._detect_subfolders()
@ -312,10 +313,23 @@ class IconExtractorWindow(QMainWindow):
layout.setContentsMargins(15, 15, 15, 15) layout.setContentsMargins(15, 15, 15, 15)
layout.setSpacing(10) layout.setSpacing(10)
# Header # Header with icon
header = QLabel("🎮 Entropia Universe Icon Extractor") header_layout = QHBoxLayout()
header.setStyleSheet("font-size: 24px; font-weight: bold; color: #4caf50; padding-bottom: 5px;") header_layout.setSpacing(15)
layout.addWidget(header)
# Icon label (will be set if icon exists)
self.header_icon = QLabel()
self.header_icon.setFixedSize(48, 48)
self.header_icon.setStyleSheet("background: transparent;")
header_layout.addWidget(self.header_icon)
# Title
header = QLabel("Entropia Universe Icon Extractor")
header.setStyleSheet("font-size: 22px; font-weight: bold; color: #4caf50;")
header_layout.addWidget(header, 1)
header_layout.addStretch()
layout.addLayout(header_layout)
# Description - two lines with clickable link # Description - two lines with clickable link
desc_widget = QWidget() desc_widget = QWidget()
@ -355,45 +369,47 @@ class IconExtractorWindow(QMainWindow):
left_layout.setSpacing(10) left_layout.setSpacing(10)
# Cache folder # Cache folder
cache_group = QGroupBox("📂 Cache Source") cache_group = QGroupBox("Cache Source")
cache_group.setStyleSheet("QGroupBox { font-size: 13px; font-weight: bold; }") cache_group.setStyleSheet("QGroupBox { font-size: 13px; font-weight: bold; }")
cache_layout = QVBoxLayout(cache_group) cache_layout = QVBoxLayout(cache_group)
cache_layout.setContentsMargins(12, 18, 12, 12) cache_layout.setContentsMargins(10, 15, 10, 10)
cache_layout.setSpacing(10) cache_layout.setSpacing(8)
# Base path (hardcoded) # Base path (hardcoded) - show just the end part
path_display = str(self.base_cache_path).replace("/", "\\") path_display = "...\\Entropia Universe\\public_users_data\\cache\\icon"
self.cache_path_full = str(self.base_cache_path).replace("/", "\\")
self.cache_label = QLabel(path_display) self.cache_label = QLabel(path_display)
self.cache_label.setStyleSheet( self.cache_label.setStyleSheet(
"font-family: Consolas; font-size: 11px; color: #aaa; " "font-family: Consolas; font-size: 11px; color: #aaa; "
"padding: 8px; background: #252525; border-radius: 4px;" "padding: 6px 8px; background: #252525; border-radius: 3px;"
) )
self.cache_label.setWordWrap(True) self.cache_label.setToolTip(self.cache_path_full)
cache_layout.addWidget(self.cache_label) cache_layout.addWidget(self.cache_label)
# Subfolder selector # Subfolder selector in one row
subfolder_layout = QHBoxLayout() subfolder_layout = QHBoxLayout()
subfolder_layout.setSpacing(10) subfolder_layout.setSpacing(8)
subfolder_label = QLabel("📁 Version:")
subfolder_label = QLabel("Version:")
subfolder_label.setStyleSheet("font-size: 12px;") subfolder_label.setStyleSheet("font-size: 12px;")
subfolder_layout.addWidget(subfolder_label) subfolder_layout.addWidget(subfolder_label)
self.subfolder_combo = QComboBox() self.subfolder_combo = QComboBox()
self.subfolder_combo.setMinimumWidth(200) self.subfolder_combo.setMinimumWidth(180)
self.subfolder_combo.setStyleSheet("font-size: 12px; padding: 4px;") self.subfolder_combo.setStyleSheet("font-size: 12px; padding: 3px;")
self.subfolder_combo.currentIndexChanged.connect(self._on_subfolder_changed) self.subfolder_combo.currentIndexChanged.connect(self._on_subfolder_changed)
subfolder_layout.addWidget(self.subfolder_combo, 1) subfolder_layout.addWidget(self.subfolder_combo, 1)
refresh_btn = QPushButton("🔄 Refresh") refresh_btn = QPushButton("Refresh")
refresh_btn.setMaximumWidth(80) refresh_btn.setMaximumWidth(70)
refresh_btn.setStyleSheet("font-size: 11px; padding: 5px;") refresh_btn.setStyleSheet("font-size: 11px; padding: 4px;")
refresh_btn.clicked.connect(self._detect_subfolders) refresh_btn.clicked.connect(self._detect_subfolders)
subfolder_layout.addWidget(refresh_btn) subfolder_layout.addWidget(refresh_btn)
cache_layout.addLayout(subfolder_layout) cache_layout.addLayout(subfolder_layout)
# All subfolders checkbox # All subfolders checkbox
self.all_subfolders_check = QCheckBox("☑️ Include ALL version folders") self.all_subfolders_check = QCheckBox("Include ALL version folders")
self.all_subfolders_check.setStyleSheet("font-size: 12px;") self.all_subfolders_check.setStyleSheet("font-size: 12px;")
self.all_subfolders_check.setToolTip("Merge icons from all game versions") self.all_subfolders_check.setToolTip("Merge icons from all game versions")
self.all_subfolders_check.stateChanged.connect(self._on_all_subfolders_changed) self.all_subfolders_check.stateChanged.connect(self._on_all_subfolders_changed)
@ -402,76 +418,75 @@ class IconExtractorWindow(QMainWindow):
left_layout.addWidget(cache_group) left_layout.addWidget(cache_group)
# Output folder # Output folder
output_group = QGroupBox("💾 Output Location") output_group = QGroupBox("Output Location")
output_group.setStyleSheet("QGroupBox { font-size: 13px; font-weight: bold; }") output_group.setStyleSheet("QGroupBox { font-size: 13px; font-weight: bold; }")
output_layout = QVBoxLayout(output_group) output_layout = QVBoxLayout(output_group)
output_layout.setContentsMargins(12, 18, 12, 12) output_layout.setContentsMargins(10, 15, 10, 10)
output_layout.setSpacing(10) output_layout.setSpacing(8)
output_info = QLabel("📁 Icons saved to your Documents folder (same location as chat.log)") output_info = QLabel("Saved to Documents folder (same location as chat.log)")
output_info.setStyleSheet("color: #aaaaaa; font-size: 12px;") output_info.setStyleSheet("color: #aaaaaa; font-size: 12px;")
output_info.setWordWrap(True)
output_layout.addWidget(output_info) output_layout.addWidget(output_info)
rel_path = "Documents/Entropia Universe/Icons/" rel_path = "Documents\\Entropia Universe\\Icons\\"
self.output_label = QLabel(f"📂 {rel_path}") self.output_label = QLabel(rel_path)
self.output_label.setStyleSheet( self.output_label.setStyleSheet(
"font-family: Consolas; font-size: 11px; color: #aaa; " "font-family: Consolas; font-size: 11px; color: #aaa; "
"padding: 8px; background: #252525; border-radius: 4px;" "padding: 6px 8px; background: #252525; border-radius: 3px;"
) )
output_layout.addWidget(self.output_label) output_layout.addWidget(self.output_label)
change_btn = QPushButton("📂 Change Output Folder...") change_btn = QPushButton("Change Output Folder...")
change_btn.setStyleSheet("font-size: 11px; padding: 6px;") change_btn.setStyleSheet("font-size: 11px; padding: 5px;")
change_btn.clicked.connect(self._browse_output) change_btn.clicked.connect(self._browse_output)
output_layout.addWidget(change_btn) output_layout.addWidget(change_btn)
left_layout.addWidget(output_group) left_layout.addWidget(output_group)
# Settings (simplified - just 320x320) # Settings (simplified - just 320x320)
settings_group = QGroupBox("⚙️ Export Settings") settings_group = QGroupBox("Export Settings")
settings_group.setStyleSheet("QGroupBox { font-size: 13px; font-weight: bold; }") settings_group.setStyleSheet("QGroupBox { font-size: 13px; font-weight: bold; }")
settings_layout = QVBoxLayout(settings_group) settings_layout = QVBoxLayout(settings_group)
settings_layout.setContentsMargins(12, 18, 12, 12) settings_layout.setContentsMargins(10, 15, 10, 10)
settings_info = QLabel( settings_info = QLabel(
"🖼️ Format: PNG with transparency\n" "Format: PNG with transparency\n"
"📐 Canvas: 320x320 pixels (centered)\n" "Canvas: 320x320 pixels (centered)\n"
"📏 Size: Original icon size (no upscaling)" "Size: Original icon size (no upscaling)"
) )
settings_info.setStyleSheet("color: #aaaaaa; font-size: 12px; line-height: 1.5;") settings_info.setStyleSheet("color: #aaaaaa; font-size: 12px; line-height: 1.4;")
settings_layout.addWidget(settings_info) settings_layout.addWidget(settings_info)
left_layout.addWidget(settings_group) left_layout.addWidget(settings_group)
# Nexus link # Nexus link
nexus_group = QGroupBox("🌐 EntropiaNexus.com") nexus_group = QGroupBox("EntropiaNexus.com")
nexus_group.setStyleSheet("QGroupBox { font-size: 13px; font-weight: bold; color: #4caf50; }") nexus_group.setStyleSheet("QGroupBox { font-size: 13px; font-weight: bold; color: #4caf50; }")
nexus_layout = QVBoxLayout(nexus_group) nexus_layout = QVBoxLayout(nexus_group)
nexus_layout.setContentsMargins(12, 18, 12, 12) nexus_layout.setContentsMargins(10, 15, 10, 10)
nexus_info = QLabel("📤 Submit icons to help complete the item database") nexus_info = QLabel("Submit icons to help complete the item database")
nexus_info.setStyleSheet("color: #cccccc; font-size: 12px;") nexus_info.setStyleSheet("color: #cccccc; font-size: 12px;")
nexus_layout.addWidget(nexus_info) nexus_layout.addWidget(nexus_info)
nexus_btn = QPushButton("🌐 Open EntropiaNexus.com") nexus_btn = QPushButton("Open EntropiaNexus.com")
nexus_btn.setMinimumHeight(32) nexus_btn.setMinimumHeight(28)
nexus_btn.setStyleSheet("font-size: 11px; padding: 6px;") nexus_btn.setStyleSheet("font-size: 11px; padding: 5px;")
nexus_btn.clicked.connect(lambda: self._open_url(WEBSITE)) nexus_btn.clicked.connect(lambda: self._open_url(WEBSITE))
nexus_layout.addWidget(nexus_btn) nexus_layout.addWidget(nexus_btn)
left_layout.addWidget(nexus_group) left_layout.addWidget(nexus_group)
# Convert button # Convert button
self.convert_btn = QPushButton("▶️ Start Extracting Icons") self.convert_btn = QPushButton("Start Extracting Icons")
self.convert_btn.setMinimumHeight(55) self.convert_btn.setMinimumHeight(50)
self.convert_btn.setStyleSheet(""" self.convert_btn.setStyleSheet("""
QPushButton { QPushButton {
background-color: #1565c0; background-color: #1565c0;
font-weight: bold; font-weight: bold;
font-size: 14px; font-size: 14px;
border-radius: 6px; border-radius: 5px;
padding: 12px; padding: 10px;
color: white; color: white;
} }
QPushButton:hover { background-color: #1976d2; } QPushButton:hover { background-color: #1976d2; }
@ -487,7 +502,7 @@ class IconExtractorWindow(QMainWindow):
self.progress_bar.setVisible(False) self.progress_bar.setVisible(False)
left_layout.addWidget(self.progress_bar) left_layout.addWidget(self.progress_bar)
self.status_label = QLabel("Ready") self.status_label = QLabel("Ready")
self.status_label.setStyleSheet("color: #888; font-size: 12px; padding: 5px;") self.status_label.setStyleSheet("color: #888; font-size: 12px; padding: 5px;")
self.status_label.setAlignment(Qt.AlignmentFlag.AlignCenter) self.status_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
left_layout.addWidget(self.status_label) left_layout.addWidget(self.status_label)
@ -501,47 +516,47 @@ class IconExtractorWindow(QMainWindow):
right_layout = QVBoxLayout(right_panel) right_layout = QVBoxLayout(right_panel)
right_layout.setContentsMargins(0, 0, 0, 0) right_layout.setContentsMargins(0, 0, 0, 0)
files_group = QGroupBox("📄 Available Icons") files_group = QGroupBox("Available Icons")
files_group.setStyleSheet("QGroupBox { font-size: 13px; font-weight: bold; }") files_group.setStyleSheet("QGroupBox { font-size: 13px; font-weight: bold; }")
files_layout = QVBoxLayout(files_group) files_layout = QVBoxLayout(files_group)
files_layout.setContentsMargins(12, 18, 12, 12) files_layout.setContentsMargins(10, 15, 10, 10)
files_layout.setSpacing(10) files_layout.setSpacing(8)
files_info = QLabel("💡 Double-click an icon to preview. Select icons to extract (or leave blank for all).") files_info = QLabel("Double-click an icon to preview. Select icons to extract (or leave blank for all).")
files_info.setStyleSheet("color: #aaaaaa; font-size: 12px;") files_info.setStyleSheet("color: #aaaaaa; font-size: 12px;")
files_layout.addWidget(files_info) files_layout.addWidget(files_info)
self.files_count_label = QLabel("No files found") self.files_count_label = QLabel("No files found")
self.files_count_label.setStyleSheet("font-weight: bold; font-size: 12px; padding: 5px 0;") self.files_count_label.setStyleSheet("font-weight: bold; font-size: 12px; padding: 3px 0;")
files_layout.addWidget(self.files_count_label) files_layout.addWidget(self.files_count_label)
self.files_list = QListWidget() self.files_list = QListWidget()
self.files_list.setSelectionMode(QListWidget.SelectionMode.ExtendedSelection) self.files_list.setSelectionMode(QListWidget.SelectionMode.ExtendedSelection)
self.files_list.setStyleSheet("font-size: 12px; padding: 3px;") self.files_list.setStyleSheet("font-size: 12px; padding: 2px;")
self.files_list.doubleClicked.connect(self._on_file_double_clicked) self.files_list.doubleClicked.connect(self._on_file_double_clicked)
files_layout.addWidget(self.files_list, 1) files_layout.addWidget(self.files_list, 1)
# Selection buttons # Selection buttons
sel_layout = QHBoxLayout() sel_layout = QHBoxLayout()
sel_layout.setSpacing(10) sel_layout.setSpacing(8)
select_all_btn = QPushButton("☑️ Select All") select_all_btn = QPushButton("Select All")
select_all_btn.setMaximumWidth(110) select_all_btn.setMaximumWidth(90)
select_all_btn.setStyleSheet("font-size: 11px; padding: 5px;") select_all_btn.setStyleSheet("font-size: 11px; padding: 4px;")
select_all_btn.clicked.connect(self.files_list.selectAll) select_all_btn.clicked.connect(self.files_list.selectAll)
sel_layout.addWidget(select_all_btn) sel_layout.addWidget(select_all_btn)
select_none_btn = QPushButton("Select None") select_none_btn = QPushButton("Select None")
select_none_btn.setMaximumWidth(110) select_none_btn.setMaximumWidth(90)
select_none_btn.setStyleSheet("font-size: 11px; padding: 5px;") select_none_btn.setStyleSheet("font-size: 11px; padding: 4px;")
select_none_btn.clicked.connect(self.files_list.clearSelection) select_none_btn.clicked.connect(self.files_list.clearSelection)
sel_layout.addWidget(select_none_btn) sel_layout.addWidget(select_none_btn)
sel_layout.addStretch() sel_layout.addStretch()
open_folder_btn = QPushButton("📂 Open Output Folder") open_folder_btn = QPushButton("Open Output Folder")
open_folder_btn.setMaximumWidth(140) open_folder_btn.setMaximumWidth(120)
open_folder_btn.setStyleSheet("font-size: 11px; padding: 5px;") open_folder_btn.setStyleSheet("font-size: 11px; padding: 4px;")
open_folder_btn.clicked.connect(self._open_output_folder) open_folder_btn.clicked.connect(self._open_output_folder)
sel_layout.addWidget(open_folder_btn) sel_layout.addWidget(open_folder_btn)
@ -554,7 +569,7 @@ class IconExtractorWindow(QMainWindow):
layout.addWidget(splitter, 1) layout.addWidget(splitter, 1)
# Important Information (moved to bottom) # Important Information (moved to bottom)
notice_group = QGroupBox("⚠️ Important Information") notice_group = QGroupBox("Important Information")
notice_group.setStyleSheet(""" notice_group.setStyleSheet("""
QGroupBox { QGroupBox {
font-size: 13px; font-size: 13px;
@ -563,19 +578,20 @@ class IconExtractorWindow(QMainWindow):
} }
""") """)
notice_layout = QVBoxLayout(notice_group) notice_layout = QVBoxLayout(notice_group)
notice_layout.setContentsMargins(12, 18, 12, 12) notice_layout.setContentsMargins(10, 15, 10, 10)
notice_text = QTextEdit() notice_text = QTextEdit()
notice_text.setReadOnly(True) notice_text.setReadOnly(True)
notice_text.setMaximumHeight(70)
notice_text.setStyleSheet(""" notice_text.setStyleSheet("""
QTextEdit { QTextEdit {
background-color: #2d2818; background-color: #2d2818;
color: #ffc107; color: #ffc107;
border: 1px solid #5d4e37; border: 1px solid #5d4e37;
border-radius: 4px; border-radius: 3px;
font-size: 13px; font-size: 12px;
padding: 10px; padding: 8px;
line-height: 1.5; line-height: 1.4;
} }
""") """)
notice_text.setText( notice_text.setText(
@ -586,25 +602,25 @@ class IconExtractorWindow(QMainWindow):
notice_layout.addWidget(notice_text) notice_layout.addWidget(notice_text)
layout.addWidget(notice_group) layout.addWidget(notice_group)
# Footer with clickable links # Footer with clickable links (no emojis)
footer_widget = QWidget() footer_widget = QWidget()
footer_layout = QVBoxLayout(footer_widget) footer_layout = QVBoxLayout(footer_widget)
footer_layout.setContentsMargins(10, 10, 10, 10) footer_layout.setContentsMargins(10, 10, 10, 10)
footer_layout.setSpacing(5) footer_layout.setSpacing(5)
# First line - developer info # First line - developer info (no emojis)
footer_line1 = QLabel(f"👨‍💻 Developed by {DEVELOPER} | 💬 Discord: {DISCORD} | 📎 GitHub: (coming soon)") footer_line1 = QLabel(f"Developed by {DEVELOPER} | Discord: {DISCORD} | GitHub: (coming soon)")
footer_line1.setStyleSheet("color: #888; font-size: 11px;") footer_line1.setStyleSheet("color: #888; font-size: 11px;")
footer_line1.setAlignment(Qt.AlignmentFlag.AlignCenter) footer_line1.setAlignment(Qt.AlignmentFlag.AlignCenter)
footer_layout.addWidget(footer_line1) footer_layout.addWidget(footer_line1)
# Second line - disclaimer with links # Second line - disclaimer with links (no emojis)
disclaimer_widget = QWidget() disclaimer_widget = QWidget()
disclaimer_layout = QHBoxLayout(disclaimer_widget) disclaimer_layout = QHBoxLayout(disclaimer_widget)
disclaimer_layout.setContentsMargins(0, 0, 0, 0) disclaimer_layout.setContentsMargins(0, 0, 0, 0)
disclaimer_layout.setSpacing(0) disclaimer_layout.setSpacing(0)
label1 = QLabel("📜 Entropia Universe Icon Extractor is a fan-made resource and is not affiliated with ") label1 = QLabel("Entropia Universe Icon Extractor is a fan-made resource and is not affiliated with ")
label1.setStyleSheet("color: #666; font-size: 10px;") label1.setStyleSheet("color: #666; font-size: 10px;")
label1.setOpenExternalLinks(True) label1.setOpenExternalLinks(True)
@ -612,9 +628,6 @@ class IconExtractorWindow(QMainWindow):
mindark_link.setStyleSheet("color: #666; font-size: 10px;") mindark_link.setStyleSheet("color: #666; font-size: 10px;")
mindark_link.setOpenExternalLinks(True) mindark_link.setOpenExternalLinks(True)
label2 = QLabel("")
label2.setStyleSheet("color: #666; font-size: 10px;")
eu_link = QLabel('<a href="https://www.entropiauniverse.com/" style="color: #888;">Entropia Universe</a>') eu_link = QLabel('<a href="https://www.entropiauniverse.com/" style="color: #888;">Entropia Universe</a>')
eu_link.setStyleSheet("color: #666; font-size: 10px;") eu_link.setStyleSheet("color: #666; font-size: 10px;")
eu_link.setOpenExternalLinks(True) eu_link.setOpenExternalLinks(True)
@ -649,12 +662,37 @@ class IconExtractorWindow(QMainWindow):
import webbrowser import webbrowser
webbrowser.open(url) webbrowser.open(url)
def _load_icon(self):
"""Load and set the application icon."""
# Try to load icon from various locations
icon_paths = [
Path(__file__).parent / "assets" / "icon.ico",
Path(__file__).parent / "assets" / "icon.png",
Path(__file__).parent / "icon.ico",
Path(__file__).parent / "icon.png",
]
for icon_path in icon_paths:
if icon_path.exists():
pixmap = QPixmap(str(icon_path))
if not pixmap.isNull():
# Set window icon
self.setWindowIcon(QIcon(pixmap))
# Set header icon (scaled to 48x48)
header_pixmap = pixmap.scaled(48, 48, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)
self.header_icon.setPixmap(header_pixmap)
return True
# Hide header icon if no icon found
self.header_icon.hide()
return False
def _load_settings(self): def _load_settings(self):
"""Load saved settings.""" """Load saved settings."""
# Output folder # Output folder
saved_output = self.settings.value("output_dir", str(self.converter.output_dir)) saved_output = self.settings.value("output_dir", str(self.converter.output_dir))
self.converter.output_dir = Path(saved_output) self.converter.output_dir = Path(saved_output)
self.output_label.setText("Documents/Entropia Universe/Icons/") self.output_label.setText("Documents\\Entropia Universe\\Icons\\")
def _save_settings(self): def _save_settings(self):
"""Save current settings.""" """Save current settings."""
@ -862,19 +900,10 @@ class IconExtractorWindow(QMainWindow):
def set_app_icon(app: QApplication): def set_app_icon(app: QApplication):
"""Set application icon.""" """Set application icon (window icon is set per-window in _load_icon)."""
# Try to load icon from various locations # Icon is loaded per-window in IconExtractorWindow._load_icon()
icon_paths = [ # This function is kept for compatibility but doesn't need to do anything
Path(__file__).parent / "assets" / "icon.ico", pass
Path(__file__).parent / "assets" / "icon.png",
Path(__file__).parent / "icon.ico",
Path(__file__).parent / "icon.png",
]
for icon_path in icon_paths:
if icon_path.exists():
app.setWindowIcon(QIcon(str(icon_path)))
return
def main(): def main():