Seregon/PkgToolBox

Toolbox for analyzing and editing pkg application files for psp,ps3, ps4 and ps5, includes the most useful functions you might need.

Python/57.3 KB/No license
GraphicUserInterface/dialogs/settings_dialog.py
PkgToolBox / GraphicUserInterface / dialogs / settings_dialog.py
1from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QTabWidget, QWidget, QGroupBox,
2 QGridLayout, QLabel, QComboBox, QSpinBox, QPushButton,
3 QCheckBox, QLineEdit, QHBoxLayout, QColorDialog, QFontDialog,
4 QFileDialog, QMessageBox, QApplication)
5from PyQt5.QtCore import Qt
6from PyQt5.QtGui import QFont, QColor, QFontDatabase
7import os
8import json
9 
10# Modifica l'import relativo in import assoluto
11from GraphicUserInterface.utils.style_manager import StyleManager
12 
13class SettingsDialog(QDialog):
14 def __init__(self, parent=None):
15 super().__init__(parent)
16 self.parent = parent
17 self.setup_ui()
18
19 def setup_ui(self):
20 """Setup the settings dialog UI"""
21 self.setWindowTitle("Settings")
22 self.setMinimumWidth(500)
23
24 layout = QVBoxLayout(self)
25
26 # Create tab widget
27 self.tab_widget = QTabWidget()
28
29 # Add tabs
30 self.tab_widget.addTab(self.create_appearance_tab(), "Appearance")
31 self.tab_widget.addTab(self.create_behavior_tab(), "Behavior")
32 self.tab_widget.addTab(self.create_paths_tab(), "Paths")
33
34 layout.addWidget(self.tab_widget)
35
36 # Add buttons
37 button_layout = QHBoxLayout()
38 save_button = QPushButton("Save")
39 cancel_button = QPushButton("Cancel")
40 reset_button = QPushButton("Reset to Default")
41
42 save_button.clicked.connect(self.save_settings)
43 cancel_button.clicked.connect(self.reject)
44 reset_button.clicked.connect(self.reset_settings)
45
46 button_layout.addWidget(save_button)
47 button_layout.addWidget(cancel_button)
48 button_layout.addWidget(reset_button)
49
50 layout.addLayout(button_layout)
51
52 # Load current settings
53 self.load_settings()
54 
55 def create_appearance_tab(self):
56 """Create and return the appearance tab"""
57 tab = QWidget()
58 layout = QVBoxLayout(tab)
59
60 # Theme group
61 theme_group = QGroupBox("Theme")
62 theme_layout = QGridLayout()
63
64 theme_layout.addWidget(QLabel("Theme:"), 0, 0)
65 self.theme_combo = QComboBox()
66 self.theme_combo.addItems(["Light", "Dark", "System", "Custom"])
67 self.theme_combo.currentTextChanged.connect(self.on_theme_changed)
68 theme_layout.addWidget(self.theme_combo, 0, 1)
69
70 theme_group.setLayout(theme_layout)
71 layout.addWidget(theme_group)
72
73 # Language group
74 language_group = QGroupBox("Language")
75 language_layout = QGridLayout()
76
77 language_layout.addWidget(QLabel("Language:"), 0, 0)
78 self.language_combo = QComboBox()
79 self.language_combo.addItems(["English", "Italian", "Spanish", "French", "German", "Japanese"])
80 self.language_combo.currentTextChanged.connect(self.on_language_changed)
81 language_layout.addWidget(self.language_combo, 0, 1)
82
83 language_group.setLayout(language_layout)
84 layout.addWidget(language_group)
85
86 # Font group
87 font_group = QGroupBox("Font")
88 font_layout = QGridLayout()
89
90 # Font family combo
91 font_layout.addWidget(QLabel("Font:"), 0, 0)
92 self.font_combo = QComboBox()
93 self.font_combo.addItems(QFontDatabase().families())
94 font_layout.addWidget(self.font_combo, 0, 1)
95
96 # Font size spinner
97 font_layout.addWidget(QLabel("Size:"), 1, 0)
98 self.font_size_spin = QSpinBox()
99 self.font_size_spin.setRange(8, 24)
100 self.font_size_spin.setValue(12)
101 font_layout.addWidget(self.font_size_spin, 1, 1)
102
103 # Font preview button
104 self.font_button = QPushButton("Preview Font")
105 self.font_button.clicked.connect(self.select_font)
106 font_layout.addWidget(self.font_button, 2, 0, 1, 2)
107
108 font_group.setLayout(font_layout)
109 layout.addWidget(font_group)
110
111 # Colors group
112 self.colors_group = QGroupBox("Colors")
113 colors_layout = QGridLayout()
114
115 # Color buttons with labels and preview
116 self.bg_color_button = QPushButton()
117 self.text_color_button = QPushButton()
118 self.accent_color_button = QPushButton()
119
120 colors_layout.addWidget(QLabel("Background:"), 0, 0)
121 colors_layout.addWidget(self.bg_color_button, 0, 1)
122 colors_layout.addWidget(QLabel("Text:"), 1, 0)
123 colors_layout.addWidget(self.text_color_button, 1, 1)
124 colors_layout.addWidget(QLabel("Accent:"), 2, 0)
125 colors_layout.addWidget(self.accent_color_button, 2, 1)
126
127 self.bg_color_button.clicked.connect(lambda: self.pick_color("background"))
128 self.text_color_button.clicked.connect(lambda: self.pick_color("text"))
129 self.accent_color_button.clicked.connect(lambda: self.pick_color("accent"))
130
131 # Disabilita i pulsanti dei colori se non è selezionato Custom
132 self.colors_group.setEnabled(self.theme_combo.currentText() == "Custom")
133
134 self.colors_group.setLayout(colors_layout)
135 layout.addWidget(self.colors_group)
136
137 return tab
138 
139 def create_behavior_tab(self):
140 """Create and return the behavior tab"""
141 tab = QWidget()
142 layout = QVBoxLayout(tab)
143
144 # File browser settings
145 browser_group = QGroupBox("File Browser")
146 browser_layout = QVBoxLayout()
147
148 self.auto_expand_check = QCheckBox("Auto-expand file tree")
149 self.show_hidden_check = QCheckBox("Show hidden files")
150 self.confirm_exit_check = QCheckBox("Confirm before exit")
151
152 browser_layout.addWidget(self.auto_expand_check)
153 browser_layout.addWidget(self.show_hidden_check)
154 browser_layout.addWidget(self.confirm_exit_check)
155
156 browser_group.setLayout(browser_layout)
157 layout.addWidget(browser_group)
158
159 layout.addStretch()
160 return tab
161 
162 def create_paths_tab(self):
163 """Create and return the paths tab"""
164 tab = QWidget()
165 layout = QVBoxLayout(tab)
166
167 paths_group = QGroupBox("Default Paths")
168 paths_layout = QGridLayout()
169
170 self.output_path_edit = QLineEdit()
171 self.temp_path_edit = QLineEdit()
172
173 output_browse = QPushButton("Browse")
174 temp_browse = QPushButton("Browse")
175
176 output_browse.clicked.connect(lambda: self.browse_directory(self.output_path_edit))
177 temp_browse.clicked.connect(lambda: self.browse_directory(self.temp_path_edit))
178
179 paths_layout.addWidget(QLabel("Output:"), 0, 0)
180 paths_layout.addWidget(self.output_path_edit, 0, 1)
181 paths_layout.addWidget(output_browse, 0, 2)
182 paths_layout.addWidget(QLabel("Temp:"), 1, 0)
183 paths_layout.addWidget(self.temp_path_edit, 1, 1)
184 paths_layout.addWidget(temp_browse, 1, 2)
185
186 paths_group.setLayout(paths_layout)
187 layout.addWidget(paths_group)
188
189 layout.addStretch()
190 return tab
191 
192 def select_font(self):
193 """Open font selection dialog"""
194 current_font = QApplication.font()
195 font, ok = QFontDialog.getFont(current_font, self)
196 if ok:
197 self.current_font = font
198 self.font_button.setText(f"{font.family()} - {font.pointSize()}pt")
199 QApplication.setFont(font)
200 
201 def pick_color(self, color_type):
202 """Open color picker dialog and immediately apply nested settings"""
203 color = QColorDialog.getColor()
204 if not color.isValid():
205 return
206 color_hex = color.name()
207 
208 # Update the clicked button preview/text
209 button_style = f"""
210 QPushButton {{
211 background-color: {color_hex};
212 color: {"#ffffff" if color.lightness() < 128 else "#000000"};
213 min-width: 100px;
214 padding: 5px;
215 border: 1px solid #bdc3c7;
216 border-radius: 4px;
217 }}
218 """
219 
220 if color_type == "background":
221 self.bg_color_button.setStyleSheet(button_style)
222 self.bg_color_button.setText(color_hex)
223 elif color_type == "text":
224 self.text_color_button.setStyleSheet(button_style)
225 self.text_color_button.setText(color_hex)
226 elif color_type == "accent":
227 self.accent_color_button.setStyleSheet(button_style)
228 self.accent_color_button.setText(color_hex)
229 
230 # Build full nested settings snapshot and apply theme
231 if self.parent:
232 settings = {
233 "appearance": {
234 "theme": self.theme_combo.currentText(),
235 "night_mode": self.theme_combo.currentText() == "Dark",
236 "font_family": getattr(self, 'current_font', QFont("Arial", 12)).family(),
237 "font_size": getattr(self, 'current_font', QFont("Arial", 12)).pointSize(),
238 "colors": {
239 "background": self.bg_color_button.text() if self.bg_color_button.text().startswith('#') else "#ffffff",
240 "text": self.text_color_button.text() if self.text_color_button.text().startswith('#') else "#000000",
241 "accent": self.accent_color_button.text() if self.accent_color_button.text().startswith('#') else "#3498db",
242 },
243 }
244 }
245 StyleManager.apply_theme(self.parent, settings)
246 self.parent.repaint()
247 QApplication.processEvents()
248 
249 def browse_directory(self, line_edit):
250 """Browse for directory"""
251 directory = QFileDialog.getExistingDirectory(self, "Select Directory")
252 if directory:
253 line_edit.setText(directory)
254 
255 def save_settings(self):
256 """Save settings in StyleManager format and apply them"""
257 try:
258 settings = {
259 "appearance": {
260 "theme": self.theme_combo.currentText(),
261 "night_mode": self.theme_combo.currentText() == "Dark",
262 "font_family": self.current_font.family() if hasattr(self, 'current_font') else "Arial",
263 "font_size": self.current_font.pointSize() if hasattr(self, 'current_font') else 12,
264 "colors": {
265 "background": self.bg_color_button.text() if self.bg_color_button.text().startswith('#') else "#ffffff",
266 "text": self.text_color_button.text() if self.text_color_button.text().startswith('#') else "#000000",
267 "accent": self.accent_color_button.text() if self.accent_color_button.text().startswith('#') else "#3498db",
268 },
269 },
270 "behavior": {
271 "auto_expand": self.auto_expand_check.isChecked(),
272 "show_hidden": self.show_hidden_check.isChecked(),
273 "confirm_exit": self.confirm_exit_check.isChecked(),
274 },
275 "paths": {
276 "output": self.output_path_edit.text(),
277 "temp": self.temp_path_edit.text(),
278 },
279 "language": self.language_combo.currentText(),
280 }
281 
282 StyleManager.save_settings(settings)
283 
284 if self.parent:
285 # Apply theme and font immediately
286 StyleManager.apply_theme(self.parent, settings)
287 font = QFont(settings["appearance"]["font_family"], settings["appearance"]["font_size"])
288 QApplication.setFont(font)
289 
290 self.accept()
291 
292 except Exception as e:
293 QMessageBox.critical(self, "Error", f"Failed to save settings: {str(e)}")
294 
295 def load_settings(self):
296 """Load settings using StyleManager (nested format) and populate UI"""
297 try:
298 settings = StyleManager.load_settings()
299 
300 appearance = settings.get("appearance", {})
301 colors = appearance.get("colors", {})
302 
303 # Theme
304 self.theme_combo.setCurrentText(appearance.get("theme", "Light"))
305 self.colors_group.setEnabled(self.theme_combo.currentText() == "Custom")
306 
307 # Language (optional)
308 lang = settings.get("language", "English")
309 if self.language_combo.findText(lang) != -1:
310 self.language_combo.setCurrentText(lang)
311 
312 # Font
313 font = QFont(appearance.get("font_family", "Arial"), appearance.get("font_size", 12))
314 self.current_font = font
315 self.font_button.setText(f"{font.family()} - {font.pointSize()}pt")
316 
317 # Colors
318 self.update_color_button(self.bg_color_button, colors.get("background", "#ffffff"))
319 self.update_color_button(self.text_color_button, colors.get("text", "#000000"))
320 self.update_color_button(self.accent_color_button, colors.get("accent", "#3498db"))
321 
322 # Behavior
323 behavior = settings.get("behavior", {})
324 self.auto_expand_check.setChecked(behavior.get("auto_expand", True))
325 self.show_hidden_check.setChecked(behavior.get("show_hidden", False))
326 self.confirm_exit_check.setChecked(behavior.get("confirm_exit", True))
327 
328 # Paths
329 paths = settings.get("paths", {})
330 self.output_path_edit.setText(paths.get("output", ""))
331 self.temp_path_edit.setText(paths.get("temp", ""))
332 
333 except Exception as e:
334 QMessageBox.warning(self, "Warning", f"Failed to load settings: {str(e)}")
335 # Soft defaults without forcing save
336 self.reset_settings()
337 
338 def reset_settings(self):
339 """Reset settings to default"""
340 reply = QMessageBox.question(self, "Confirm Reset",
341 "Are you sure you want to reset all settings to default?",
342 QMessageBox.Yes | QMessageBox.No)
343
344 if reply == QMessageBox.Yes:
345 # Reset to defaults
346 self.theme_combo.setCurrentText("Light")
347
348 font = QFont("Arial", 12)
349 self.current_font = font
350 self.font_button.setText("Arial - 12pt")
351
352 self.bg_color_button.setStyleSheet("")
353 self.text_color_button.setStyleSheet("")
354 self.accent_color_button.setStyleSheet("")
355
356 self.auto_expand_check.setChecked(True)
357 self.show_hidden_check.setChecked(False)
358 self.confirm_exit_check.setChecked(True)
359
360 self.output_path_edit.clear()
361 self.temp_path_edit.clear()
362
363 # Save and apply default settings
364 self.save_settings()
365 
366 def apply_settings(self, settings):
367 """Apply settings to parent window"""
368 if self.parent:
369 try:
370 # Applica il tema
371 theme = settings.get("theme", "Light")
372
373 # Gestisci i colori personalizzati
374 if theme == "Custom":
375 colors = {
376 'bg_color': self.bg_color_button.text(),
377 'text_color': self.text_color_button.text(),
378 'accent_color': self.accent_color_button.text()
379 }
380 settings.update(colors)
381
382 # Applica il font
383 font = QFont(settings["font_family"], settings["font_size"])
384 QApplication.setFont(font)
385
386 # Applica il tema
387 StyleManager.apply_theme(self.parent, settings)
388
389 # Aggiorna le impostazioni del file browser
390 if hasattr(self.parent, 'file_browser'):
391 if settings.get("auto_expand", True):
392 self.parent.file_browser.file_tree.expandAll()
393 else:
394 self.parent.file_browser.file_tree.collapseAll()
395
396 # Forza l'aggiornamento visuale
397 self.parent.repaint()
398 QApplication.processEvents()
399
400 except Exception as e:
401 QMessageBox.critical(self, "Error", f"Failed to apply settings: {str(e)}")
402 
403 def on_theme_changed(self, theme):
404 """Handle theme change"""
405 self.colors_group.setEnabled(theme == "Custom")
406 if theme != "Custom":
407 # Imposta i colori predefiniti per il tema selezionato
408 if theme == "Light":
409 self.set_theme_colors("#ffffff", "#000000", "#3498db")
410 elif theme == "Dark":
411 self.set_theme_colors("#1e1e1e", "#ffffff", "#3498db")
412 elif theme == "System":
413 # Usa i colori di sistema
414 from PyQt5.QtGui import QPalette
415 palette = QApplication.palette()
416 self.set_theme_colors(
417 palette.color(QPalette.Window).name(),
418 palette.color(QPalette.WindowText).name(),
419 palette.color(QPalette.Highlight).name()
420 )
421 
422 def set_theme_colors(self, bg, text, accent):
423 """Set theme colors"""
424 self.update_color_button(self.bg_color_button, bg)
425 self.update_color_button(self.text_color_button, text)
426 self.update_color_button(self.accent_color_button, accent)
427 
428 def update_color_button(self, button, color):
429 """Update color button appearance"""
430 button.setStyleSheet(f"""
431 QPushButton {{
432 background-color: {color};
433 color: {"#ffffff" if QColor(color).lightness() < 128 else "#000000"};
434 min-width: 100px;
435 padding: 5px;
436 border: 1px solid #bdc3c7;
437 border-radius: 4px;
438 }}
439 """)
440 button.setText(color)
441 
442 def on_language_changed(self, language):
443 """Handle language change"""
444 lang_codes = {
445 "English": "en",
446 "Italian": "it",
447 "Spanish": "es",
448 "French": "fr",
449 "German": "de",
450 "Japanese": "ja"
451 }
452
453 if language in lang_codes:
454 self.parent.translator.change_language(lang_codes[language])
455 self.parent.retranslate_ui()