667 lines
33 KiB
Python
667 lines
33 KiB
Python
# gui/config_editor_dialog.py
|
|
|
|
import json
|
|
from PySide6.QtWidgets import ( # Changed from PyQt5
|
|
QDialog, QVBoxLayout, QHBoxLayout, QTabWidget, QWidget,
|
|
QLineEdit, QSpinBox, QDoubleSpinBox, QComboBox, QCheckBox,
|
|
QPushButton, QFileDialog, QLabel, QTableWidget, # Removed QColorDialog
|
|
QTableWidgetItem, QDialogButtonBox, QMessageBox, QListWidget,
|
|
QListWidgetItem, QFormLayout, QGroupBox
|
|
)
|
|
from PySide6.QtGui import QColor # Changed from PyQt5
|
|
from PySide6.QtCore import Qt # Changed from PyQt5
|
|
from PySide6.QtWidgets import QColorDialog # Import QColorDialog separately for PySide6
|
|
|
|
# Assuming configuration.py is in the parent directory or accessible
|
|
# Adjust import path if necessary
|
|
try:
|
|
from configuration import load_base_config, save_base_config
|
|
except ImportError:
|
|
# Fallback import for testing or different project structure
|
|
from ..configuration import load_base_config, save_base_config
|
|
|
|
|
|
class ConfigEditorDialog(QDialog):
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent)
|
|
self.setWindowTitle("Configuration Editor")
|
|
self.setGeometry(100, 100, 800, 600)
|
|
|
|
self.settings = {}
|
|
self.widgets = {} # Dictionary to hold references to created widgets
|
|
|
|
self.main_layout = QVBoxLayout(self)
|
|
self.tab_widget = QTabWidget()
|
|
self.main_layout.addWidget(self.tab_widget)
|
|
|
|
self.button_box = QDialogButtonBox(QDialogButtonBox.Save | QDialogButtonBox.Cancel)
|
|
self.button_box.accepted.connect(self.save_settings)
|
|
self.button_box.rejected.connect(self.reject)
|
|
self.main_layout.addWidget(self.button_box)
|
|
|
|
self.load_settings() # Load settings FIRST
|
|
self.create_tabs() # THEN create widgets based on settings
|
|
# self.populate_widgets() # Removed as population is now in load_settings
|
|
|
|
def load_settings(self):
|
|
"""Loads settings from the configuration file and populates widgets."""
|
|
try:
|
|
self.settings = load_base_config()
|
|
print("Configuration loaded successfully.") # Debug print
|
|
|
|
# Populate widgets after loading settings and creating tabs
|
|
self.populate_widgets_from_settings()
|
|
|
|
except Exception as e:
|
|
QMessageBox.critical(self, "Loading Error", f"Failed to load configuration: {e}")
|
|
self.settings = {} # Use empty settings on failure
|
|
# Optionally disable save button or widgets if loading fails
|
|
self.button_box.button(QDialogButtonBox.Save).setEnabled(False)
|
|
|
|
def create_tabs(self):
|
|
"""Creates tabs based on the redesigned UI plan."""
|
|
if not self.settings:
|
|
return
|
|
|
|
# --- Create Tabs ---
|
|
self.tabs = {
|
|
"general": QWidget(),
|
|
"output_naming": QWidget(),
|
|
"image_processing": QWidget(),
|
|
"definitions": QWidget(),
|
|
"map_merging": QWidget(),
|
|
"postprocess_scripts": QWidget()
|
|
}
|
|
self.tab_widget.addTab(self.tabs["general"], "General")
|
|
self.tab_widget.addTab(self.tabs["output_naming"], "Output & Naming")
|
|
self.tab_widget.addTab(self.tabs["image_processing"], "Image Processing")
|
|
self.tab_widget.addTab(self.tabs["definitions"], "Definitions")
|
|
self.tab_widget.addTab(self.tabs["map_merging"], "Map Merging")
|
|
self.tab_widget.addTab(self.tabs["postprocess_scripts"], "Postprocess Scripts")
|
|
|
|
|
|
# --- Setup Layouts for Tabs ---
|
|
self.tab_layouts = {name: QVBoxLayout(tab) for name, tab in self.tabs.items()}
|
|
|
|
# --- Populate Tabs ---
|
|
self.populate_general_tab(self.tab_layouts["general"])
|
|
self.populate_output_naming_tab(self.tab_layouts["output_naming"])
|
|
self.populate_image_processing_tab(self.tab_layouts["image_processing"])
|
|
self.populate_definitions_tab(self.tab_layouts["definitions"])
|
|
self.populate_map_merging_tab(self.tab_layouts["map_merging"])
|
|
self.populate_postprocess_scripts_tab(self.tab_layouts["postprocess_scripts"])
|
|
|
|
def create_widget_for_setting(self, parent_layout, key, value, setting_key_prefix=""):
|
|
"""Creates an appropriate widget for a single setting key-value pair."""
|
|
full_key = f"{setting_key_prefix}{key}" if setting_key_prefix else key
|
|
label_text = key.replace('_', ' ').title()
|
|
label = QLabel(label_text + ":")
|
|
widget = None
|
|
layout_to_add = None # Use this for widgets needing extra controls (like browse button)
|
|
|
|
if isinstance(value, str):
|
|
if 'PATH' in key.upper() or 'DIR' in key.upper() or key == "BLENDER_EXECUTABLE_PATH":
|
|
widget = QLineEdit(value)
|
|
button = QPushButton("Browse...")
|
|
# Determine if it's a file or directory browse
|
|
is_dir = 'DIR' in key.upper()
|
|
button.clicked.connect(lambda checked, w=widget, k=full_key, is_dir=is_dir: self.browse_path(w, k, is_dir))
|
|
h_layout = QHBoxLayout()
|
|
h_layout.addWidget(widget)
|
|
h_layout.addWidget(button)
|
|
layout_to_add = h_layout
|
|
elif 'COLOR' in key.upper() or 'COLOUR' in key.upper():
|
|
widget = QLineEdit(value)
|
|
button = QPushButton("Pick Color...")
|
|
button.clicked.connect(lambda checked, w=widget: self.pick_color(w))
|
|
h_layout = QHBoxLayout()
|
|
h_layout.addWidget(widget)
|
|
h_layout.addWidget(button)
|
|
layout_to_add = h_layout
|
|
else:
|
|
widget = QLineEdit(value)
|
|
elif isinstance(value, int):
|
|
widget = QSpinBox()
|
|
widget.setRange(-2147483648, 2147483647)
|
|
widget.setValue(value)
|
|
elif isinstance(value, float):
|
|
widget = QDoubleSpinBox()
|
|
widget.setRange(-1.7976931348623157e+308, 1.7976931348623157e+308)
|
|
widget.setValue(value)
|
|
elif isinstance(value, bool):
|
|
widget = QCheckBox()
|
|
widget.setChecked(value)
|
|
elif isinstance(value, list) and key != "MAP_MERGE_RULES": # Handle simple lists (excluding complex ones)
|
|
# Assuming list of strings or simple types
|
|
widget = QLineEdit(", ".join(map(str, value)))
|
|
# Complex dicts/lists like ASSET_TYPE_DEFINITIONS, MAP_MERGE_RULES etc. are handled in dedicated methods
|
|
|
|
if widget or layout_to_add:
|
|
if layout_to_add:
|
|
parent_layout.addRow(label, layout_to_add)
|
|
else:
|
|
parent_layout.addRow(label, widget)
|
|
|
|
# Store reference using the full key only if a widget was created
|
|
if widget:
|
|
self.widgets[full_key] = widget
|
|
else:
|
|
# Optionally handle unsupported types or log a warning
|
|
# print(f"Skipping widget creation for key '{full_key}' with unsupported type: {type(value)}")
|
|
pass
|
|
|
|
def populate_definitions_tab(self, layout):
|
|
"""Populates the Definitions tab."""
|
|
# Reuse existing methods for Asset and File Type Definitions
|
|
if "ASSET_TYPE_DEFINITIONS" in self.settings:
|
|
group = QGroupBox("Asset Type Definitions")
|
|
group_layout = QVBoxLayout(group)
|
|
self.create_asset_definitions_widget(group_layout, self.settings["ASSET_TYPE_DEFINITIONS"])
|
|
layout.addWidget(group)
|
|
|
|
if "FILE_TYPE_DEFINITIONS" in self.settings:
|
|
group = QGroupBox("File Type Definitions")
|
|
group_layout = QVBoxLayout(group)
|
|
self.create_file_type_definitions_widget(group_layout, self.settings["FILE_TYPE_DEFINITIONS"])
|
|
layout.addWidget(group)
|
|
|
|
# Add STANDARD_MAP_TYPES and RESPECT_VARIANT_MAP_TYPES here
|
|
form_layout = QFormLayout()
|
|
if "STANDARD_MAP_TYPES" in self.settings:
|
|
self.create_widget_for_setting(form_layout, "STANDARD_MAP_TYPES", self.settings["STANDARD_MAP_TYPES"])
|
|
if "RESPECT_VARIANT_MAP_TYPES" in self.settings:
|
|
self.create_widget_for_setting(form_layout, "RESPECT_VARIANT_MAP_TYPES", self.settings["RESPECT_VARIANT_MAP_TYPES"])
|
|
|
|
layout.addLayout(form_layout)
|
|
layout.addStretch()
|
|
|
|
|
|
def populate_general_tab(self, layout):
|
|
"""Populates the General tab."""
|
|
form_layout = QFormLayout()
|
|
# Settings from app_settings.json that fit 'General'
|
|
keys_to_include = [
|
|
"DEFAULT_ASSET_CATEGORY"
|
|
]
|
|
for key in keys_to_include:
|
|
if key in self.settings:
|
|
self.create_widget_for_setting(form_layout, key, self.settings[key])
|
|
layout.addLayout(form_layout)
|
|
layout.addStretch()
|
|
|
|
def populate_output_naming_tab(self, layout):
|
|
"""Populates the Output & Naming tab."""
|
|
form_layout = QFormLayout()
|
|
# Settings from app_settings.json that fit 'Output & Naming'
|
|
keys_to_include = [
|
|
"OUTPUT_BASE_DIR", "EXTRA_FILES_SUBDIR", "METADATA_FILENAME",
|
|
"TARGET_FILENAME_PATTERN", "TEMP_DIR_PREFIX"
|
|
]
|
|
for key in keys_to_include:
|
|
if key in self.settings:
|
|
self.create_widget_for_setting(form_layout, key, self.settings[key])
|
|
layout.addLayout(form_layout)
|
|
layout.addStretch()
|
|
|
|
def populate_image_processing_tab(self, layout):
|
|
"""Populates the Image Processing tab."""
|
|
form_layout = QFormLayout()
|
|
# Simple settings from app_settings.json that fit 'Image Processing'
|
|
simple_keys = [
|
|
"PNG_COMPRESSION_LEVEL", "JPG_QUALITY", "RESOLUTION_THRESHOLD_FOR_JPG",
|
|
"ASPECT_RATIO_DECIMALS", "CALCULATE_STATS_RESOLUTION",
|
|
"OUTPUT_FORMAT_16BIT_PRIMARY", "OUTPUT_FORMAT_16BIT_FALLBACK",
|
|
"OUTPUT_FORMAT_8BIT"
|
|
]
|
|
for key in simple_keys:
|
|
if key in self.settings:
|
|
self.create_widget_for_setting(form_layout, key, self.settings[key])
|
|
layout.addLayout(form_layout)
|
|
|
|
# Complex widgets for Image Processing
|
|
if "IMAGE_RESOLUTIONS" in self.settings:
|
|
group = QGroupBox("Image Resolutions")
|
|
group_layout = QVBoxLayout(group)
|
|
# IMAGE_RESOLUTIONS is a dict in app_settings, need to adapt create_image_resolutions_widget
|
|
# For now, display as a simple text field or defer
|
|
# Deferring complex dict/list handling for now, except for Definitions and Map Merging
|
|
# self.create_image_resolutions_widget(group_layout, self.settings["IMAGE_RESOLUTIONS"])
|
|
# Placeholder for IMAGE_RESOLUTIONS
|
|
layout.addWidget(QLabel("Image Resolutions (complex structure - deferred)"))
|
|
# Add a simple widget for now to show the data
|
|
if "IMAGE_RESOLUTIONS" in self.settings:
|
|
self.create_widget_for_setting(form_layout, "IMAGE_RESOLUTIONS", str(self.settings["IMAGE_RESOLUTIONS"]))
|
|
|
|
|
|
if "MAP_BIT_DEPTH_RULES" in self.settings:
|
|
group = QGroupBox("Map Bit Depth Rules")
|
|
group_layout = QVBoxLayout(group)
|
|
# MAP_BIT_DEPTH_RULES is a dict in app_settings, need to adapt create_map_bit_depth_rules_widget
|
|
# For now, display as a simple text field or defer
|
|
# Deferring complex dict/list handling for now, except for Definitions and Map Merging
|
|
# self.create_map_bit_depth_rules_widget(group_layout, self.settings["MAP_BIT_DEPTH_RULES"])
|
|
# Placeholder for MAP_BIT_DEPTH_RULES
|
|
layout.addWidget(QLabel("Map Bit Depth Rules (complex structure - deferred)"))
|
|
# Add a simple widget for now to show the data
|
|
if "MAP_BIT_DEPTH_RULES" in self.settings:
|
|
self.create_widget_for_setting(form_layout, "MAP_BIT_DEPTH_RULES", str(self.settings["MAP_BIT_DEPTH_RULES"]))
|
|
|
|
|
|
layout.addStretch()
|
|
|
|
def populate_map_merging_tab(self, layout):
|
|
"""Populates the Map Merging tab."""
|
|
# Implement Map Merging UI (ListWidget + Details Form)
|
|
if "MAP_MERGE_RULES" in self.settings:
|
|
self.create_map_merge_rules_widget(layout, self.settings["MAP_MERGE_RULES"])
|
|
layout.addStretch()
|
|
|
|
def populate_postprocess_scripts_tab(self, layout):
|
|
"""Populates the Postprocess Scripts tab."""
|
|
form_layout = QFormLayout()
|
|
# No explicit settings for postprocess scripts in app_settings.json currently
|
|
layout.addWidget(QLabel("No postprocess script settings found."))
|
|
layout.addLayout(form_layout)
|
|
layout.addStretch()
|
|
|
|
# Remove the old create_widgets_for_section method as it's replaced
|
|
# def create_widgets_for_section(self, layout, section_data, section_key):
|
|
# ... (old implementation removed) ...
|
|
|
|
|
|
def create_asset_definitions_widget(self, layout, definitions_data):
|
|
"""Creates a widget for editing asset type definitions."""
|
|
table = QTableWidget()
|
|
table.setColumnCount(3) # Asset Type, Description, Color
|
|
table.setHorizontalHeaderLabels(["Asset Type", "Description", "Color"])
|
|
table.setRowCount(len(definitions_data))
|
|
|
|
row = 0
|
|
for asset_type, details in definitions_data.items():
|
|
table.setItem(row, 0, QTableWidgetItem(asset_type))
|
|
table.setItem(row, 1, QTableWidgetItem(details.get("description", "")))
|
|
|
|
color_widget = QLineEdit(details.get("color", ""))
|
|
color_button = QPushButton("Pick Color...")
|
|
color_button.clicked.connect(lambda checked, w=color_widget: self.pick_color(w))
|
|
h_layout = QHBoxLayout()
|
|
h_layout.addWidget(color_widget)
|
|
h_layout.addWidget(color_button)
|
|
|
|
cell_widget = QWidget()
|
|
cell_widget.setLayout(h_layout)
|
|
table.setCellWidget(row, 2, cell_widget)
|
|
|
|
row += 1
|
|
|
|
table.horizontalHeader().setStretchLastSection(True)
|
|
layout.addWidget(table)
|
|
self.widgets["DEFINITION_SETTINGS.ASSET_TYPE_DEFINITIONS"] = table # Store table reference
|
|
|
|
def create_file_type_definitions_widget(self, layout, definitions_data):
|
|
"""Creates a widget for editing file type definitions."""
|
|
table = QTableWidget()
|
|
table.setColumnCount(3) # File Type, Description, Color
|
|
table.setHorizontalHeaderLabels(["File Type", "Description", "Color"])
|
|
table.setRowCount(len(definitions_data))
|
|
|
|
row = 0
|
|
for file_type, details in definitions_data.items():
|
|
table.setItem(row, 0, QTableWidgetItem(file_type))
|
|
table.setItem(row, 1, QTableWidgetItem(details.get("description", "")))
|
|
|
|
color_widget = QLineEdit(details.get("color", ""))
|
|
color_button = QPushButton("Pick Color...")
|
|
color_button.clicked.connect(lambda checked, w=color_widget: self.pick_color(w))
|
|
h_layout = QHBoxLayout()
|
|
h_layout.addWidget(color_widget)
|
|
h_layout.addWidget(color_button)
|
|
|
|
cell_widget = QWidget()
|
|
cell_widget.setLayout(h_layout)
|
|
table.setCellWidget(row, 2, cell_widget)
|
|
|
|
row += 1
|
|
|
|
table.horizontalHeader().setStretchLastSection(True)
|
|
layout.addWidget(table)
|
|
self.widgets["DEFINITION_SETTINGS.FILE_TYPE_DEFINITIONS"] = table # Store table reference
|
|
|
|
def create_image_resolutions_widget(self, layout, resolutions_data):
|
|
"""Creates a widget for editing image resolutions."""
|
|
table = QTableWidget()
|
|
table.setColumnCount(2) # Width, Height
|
|
table.setHorizontalHeaderLabels(["Width", "Height"])
|
|
table.setRowCount(len(resolutions_data))
|
|
|
|
for row, resolution in enumerate(resolutions_data):
|
|
table.setItem(row, 0, QTableWidgetItem(str(resolution[0])))
|
|
table.setItem(row, 1, QTableWidgetItem(str(resolution[1])))
|
|
|
|
table.horizontalHeader().setStretchLastSection(True)
|
|
layout.addWidget(table)
|
|
self.widgets["IMAGE_PROCESSING_SETTINGS.IMAGE_RESOLUTIONS"] = table # Store table reference
|
|
|
|
def create_map_bit_depth_rules_widget(self, layout, rules_data: dict):
|
|
"""Creates a widget for editing map bit depth rules (Map Type -> Rule)."""
|
|
table = QTableWidget()
|
|
table.setColumnCount(2) # Map Type, Rule
|
|
table.setHorizontalHeaderLabels(["Map Type", "Rule (respect/force_8bit)"])
|
|
table.setRowCount(len(rules_data))
|
|
|
|
# Iterate through dictionary items (key-value pairs)
|
|
for row, (map_type, rule_string) in enumerate(rules_data.items()):
|
|
table.setItem(row, 0, QTableWidgetItem(map_type))
|
|
# Optionally use a ComboBox for the rule selection later
|
|
table.setItem(row, 1, QTableWidgetItem(str(rule_string)))
|
|
|
|
table.horizontalHeader().setStretchLastSection(True)
|
|
layout.addWidget(table)
|
|
# Store reference using a more specific key if needed, or handle in save_settings
|
|
self.widgets["MAP_BIT_DEPTH_RULES_TABLE"] = table # Use a distinct key for the table widget
|
|
|
|
def create_map_merge_rules_widget(self, layout, rules_data):
|
|
"""Creates a widget for editing map merge rules."""
|
|
# This is a more complex structure (list of dicts)
|
|
# Using a ListWidget to select rules and a separate form to edit details
|
|
h_layout = QHBoxLayout()
|
|
layout.addLayout(h_layout)
|
|
|
|
self.merge_rules_list = QListWidget()
|
|
self.merge_rules_list.currentItemChanged.connect(self.display_merge_rule_details)
|
|
h_layout.addWidget(self.merge_rules_list, 1) # Give list more space
|
|
|
|
self.merge_rule_details_group = QGroupBox("Rule Details")
|
|
self.merge_rule_details_layout = QFormLayout(self.merge_rule_details_group)
|
|
h_layout.addWidget(self.merge_rule_details_group, 2) # Give details form more space
|
|
|
|
self.merge_rule_widgets = {} # Widgets for the currently displayed rule
|
|
|
|
self.populate_merge_rules_list(rules_data)
|
|
self.widgets["IMAGE_PROCESSING_SETTINGS.MAP_MERGE_RULES"] = rules_data # Store original data reference
|
|
|
|
def populate_merge_rules_list(self, rules_data):
|
|
"""Populates the list widget with map merge rules."""
|
|
self.merge_rules_list.clear()
|
|
for rule in rules_data:
|
|
item = QListWidgetItem(rule.get("output_name", "Unnamed Rule"))
|
|
item.setData(Qt.UserRole, rule) # Store the rule dictionary in the item
|
|
self.merge_rules_list.addItem(item)
|
|
|
|
def display_merge_rule_details(self, current, previous):
|
|
"""Displays details of the selected merge rule."""
|
|
# Clear previous widgets
|
|
for i in reversed(range(self.merge_rule_details_layout.count())):
|
|
widget_item = self.merge_rule_details_layout.itemAt(i)
|
|
if widget_item:
|
|
widget = widget_item.widget()
|
|
if widget:
|
|
widget.deleteLater()
|
|
layout = widget_item.layout()
|
|
if layout:
|
|
# Recursively delete widgets in layout
|
|
while layout.count():
|
|
item = layout.takeAt(0)
|
|
widget = item.widget()
|
|
if widget:
|
|
widget.deleteLater()
|
|
elif item.layout():
|
|
# Handle nested layouts if necessary
|
|
pass # For simplicity, assuming no deeply nested layouts here
|
|
|
|
self.merge_rule_widgets.clear()
|
|
|
|
if current:
|
|
rule_data = current.data(Qt.UserRole)
|
|
if rule_data:
|
|
for key, value in rule_data.items():
|
|
label = QLabel(key.replace('_', ' ').title() + ":")
|
|
if isinstance(value, str):
|
|
widget = QLineEdit(value)
|
|
elif isinstance(value, (int, float)):
|
|
if isinstance(value, int):
|
|
widget = QSpinBox()
|
|
widget.setRange(-2147483648, 2147483647)
|
|
widget.setValue(value)
|
|
else:
|
|
widget = QDoubleSpinBox()
|
|
widget.setRange(-1.7976931348623157e+308, 1.7976931348623157e+308)
|
|
widget.setValue(value)
|
|
elif isinstance(value, bool):
|
|
widget = QCheckBox()
|
|
widget.setChecked(value)
|
|
elif isinstance(value, list):
|
|
# Assuming list of strings or simple types for now
|
|
widget = QLineEdit(", ".join(map(str, value)))
|
|
elif isinstance(value, dict):
|
|
# Assuming simple key-value dicts for now
|
|
widget = QLineEdit(json.dumps(value)) # Display as JSON string
|
|
else:
|
|
widget = QLabel(f"Unsupported type: {type(value)}")
|
|
|
|
self.merge_rule_details_layout.addRow(label, widget)
|
|
self.merge_rule_widgets[key] = widget # Store widget reference
|
|
|
|
|
|
def browse_path(self, widget, key):
|
|
"""Opens a file or directory dialog based on the setting key."""
|
|
if 'DIR' in key.upper():
|
|
path = QFileDialog.getExistingDirectory(self, "Select Directory", widget.text())
|
|
else:
|
|
path, _ = QFileDialog.getOpenFileName(self, "Select File", widget.text())
|
|
|
|
if path:
|
|
widget.setText(path)
|
|
|
|
def pick_color(self, widget):
|
|
"""Opens a color dialog and sets the selected color in the widget."""
|
|
color = QColorDialog.getColor(QColor(widget.text()))
|
|
if color.isValid():
|
|
widget.setText(color.name()) # Get color as hex string
|
|
|
|
def save_settings(self):
|
|
"""Reads values from widgets and saves them to the configuration file."""
|
|
new_settings = {}
|
|
|
|
# Reconstruct the settings dictionary from widgets
|
|
# This requires iterating through the widgets and mapping them back
|
|
# to the original structure. This is a simplified approach and might
|
|
# need refinement for complex nested structures or dynamic lists/tables.
|
|
|
|
# Start with a deep copy of the original settings structure to preserve
|
|
# sections/keys that might not have dedicated widgets (though ideally all should)
|
|
import copy
|
|
new_settings = copy.deepcopy(self.settings)
|
|
|
|
# Iterate through the stored widgets and update the new_settings dictionary
|
|
for key, widget in self.widgets.items():
|
|
# Handle simple widgets
|
|
if isinstance(widget, (QLineEdit, QSpinBox, QDoubleSpinBox, QCheckBox)):
|
|
# Split the key to navigate the dictionary structure
|
|
keys = key.split('.')
|
|
current_dict = new_settings
|
|
for i, k in enumerate(keys):
|
|
if i == len(keys) - 1:
|
|
# This is the final key, update the value
|
|
if isinstance(widget, QLineEdit):
|
|
# Handle simple lists displayed as comma-separated strings
|
|
if key in ["STANDARD_MAP_TYPES", "RESPECT_VARIANT_MAP_TYPES"]:
|
|
current_dict[k] = [item.strip() for item in widget.text().split(',') if item.strip()]
|
|
else:
|
|
current_dict[k] = widget.text()
|
|
elif isinstance(widget, QSpinBox):
|
|
current_dict[k] = widget.value()
|
|
elif isinstance(widget, QDoubleSpinBox):
|
|
current_dict[k] = widget.value()
|
|
elif isinstance(widget, QCheckBox):
|
|
current_dict[k] = widget.isChecked()
|
|
else:
|
|
# Navigate to the next level
|
|
if k not in current_dict or not isinstance(current_dict[k], dict):
|
|
# This should not happen if create_tabs is correct, but handle defensively
|
|
print(f"Warning: Structure mismatch for key part '{k}' in '{key}'")
|
|
break # Stop processing this key
|
|
current_dict = current_dict[k]
|
|
# Handle TableWidgets (for definitions)
|
|
elif isinstance(widget, QTableWidget):
|
|
keys = key.split('.')
|
|
if len(keys) >= 2:
|
|
section_key = keys[0]
|
|
list_key = keys[1]
|
|
if section_key in new_settings and list_key in new_settings[section_key]:
|
|
if list_key == "ASSET_TYPE_DEFINITIONS":
|
|
new_definitions = {}
|
|
for row in range(widget.rowCount()):
|
|
asset_type_item = widget.item(row, 0)
|
|
description_item = widget.item(row, 1)
|
|
color_widget_container = widget.cellWidget(row, 2)
|
|
if asset_type_item and color_widget_container:
|
|
asset_type = asset_type_item.text()
|
|
description = description_item.text() if description_item else ""
|
|
color_widget = color_widget_container.findChild(QLineEdit)
|
|
if color_widget:
|
|
color = color_widget.text()
|
|
new_definitions[asset_type] = {"description": description, "color": color}
|
|
new_settings[section_key][list_key] = new_definitions
|
|
elif list_key == "FILE_TYPE_DEFINITIONS":
|
|
new_definitions = {}
|
|
for row in range(widget.rowCount()):
|
|
file_type_item = widget.item(row, 0)
|
|
description_item = widget.item(row, 1)
|
|
color_widget_container = widget.cellWidget(row, 2)
|
|
if file_type_item and color_widget_container:
|
|
file_type = file_type_item.text()
|
|
description = description_item.text() if description_item else ""
|
|
color_widget = color_widget_container.findChild(QLineEdit)
|
|
if color_widget:
|
|
color = color_widget.text()
|
|
new_definitions[file_type] = {"description": description, "color": color}
|
|
new_settings[section_key][list_key] = new_definitions
|
|
# Note: IMAGE_RESOLUTIONS and MAP_BIT_DEPTH_RULES tables are not saved here
|
|
# as they are currently displayed as simple text fields due to deferred UI complexity.
|
|
|
|
# Handle Map Merge Rules (more complex)
|
|
# Reconstruct the list from the list widget items' data.
|
|
# Note: Changes made in the details form are NOT saved with this implementation
|
|
# due to deferred complexity in updating the list item's data.
|
|
elif key == "IMAGE_PROCESSING_SETTINGS.MAP_MERGE_RULES":
|
|
new_merge_rules = []
|
|
for i in range(self.merge_rules_list.count()):
|
|
item = self.merge_rules_list.item(i)
|
|
rule_data = item.data(Qt.UserRole)
|
|
if rule_data:
|
|
# Append the rule data stored in the list item.
|
|
# This data reflects the state when the dialog was opened,
|
|
# not changes made in the details form.
|
|
new_merge_rules.append(rule_data)
|
|
|
|
# Update the new_settings dictionary with the reconstructed list
|
|
keys = key.split('.')
|
|
if len(keys) == 2:
|
|
section_key = keys[0]
|
|
list_key = keys[1]
|
|
if section_key in new_settings and list_key in new_settings[section_key]:
|
|
new_settings[section_key][list_key] = new_merge_rules
|
|
|
|
|
|
# Save the new settings
|
|
try:
|
|
save_base_config(new_settings)
|
|
QMessageBox.information(self, "Settings Saved", "Configuration saved successfully.\nRestart the application to apply changes.")
|
|
self.accept() # Close the dialog
|
|
except Exception as e:
|
|
QMessageBox.critical(self, "Saving Error", f"Failed to save configuration: {e}")
|
|
|
|
def populate_widgets_from_settings(self):
|
|
"""Populates the created widgets with loaded settings."""
|
|
if not self.settings or not self.widgets:
|
|
return
|
|
|
|
for key, value in self.settings.items():
|
|
# Handle simple settings directly if they have a corresponding widget
|
|
if key in self.widgets and isinstance(self.widgets[key], (QLineEdit, QSpinBox, QDoubleSpinBox, QCheckBox)):
|
|
widget = self.widgets[key]
|
|
if isinstance(widget, QLineEdit):
|
|
# Handle simple lists displayed as comma-separated strings
|
|
if key in ["STANDARD_MAP_TYPES", "RESPECT_VARIANT_MAP_TYPES"] and isinstance(value, list):
|
|
widget.setText(", ".join(map(str, value)))
|
|
elif isinstance(value, (str, int, float, bool)): # Also handle cases where simple types might be in QLineEdit
|
|
widget.setText(str(value))
|
|
elif isinstance(widget, QSpinBox) and isinstance(value, int):
|
|
widget.setValue(value)
|
|
elif isinstance(widget, QDoubleSpinBox) and isinstance(value, (int, float)):
|
|
widget.setValue(float(value))
|
|
elif isinstance(widget, QCheckBox) and isinstance(value, bool):
|
|
widget.setChecked(value)
|
|
# Add other simple widget types if needed
|
|
|
|
# Handle complex structures with dedicated widgets
|
|
elif key == "ASSET_TYPE_DEFINITIONS" and "DEFINITION_SETTINGS.ASSET_TYPE_DEFINITIONS" in self.widgets:
|
|
self.populate_asset_definitions_table(self.widgets["DEFINITION_SETTINGS.ASSET_TYPE_DEFINITIONS"], value)
|
|
elif key == "FILE_TYPE_DEFINITIONS" and "DEFINITION_SETTINGS.FILE_TYPE_DEFINITIONS" in self.widgets:
|
|
self.populate_file_type_definitions_table(self.widgets["DEFINITION_SETTINGS.FILE_TYPE_DEFINITIONS"], value)
|
|
elif key == "MAP_MERGE_RULES" and hasattr(self, 'merge_rules_list'): # Check if the list widget exists
|
|
self.populate_merge_rules_list(value)
|
|
# Select the first item to display details if the list is not empty
|
|
if self.merge_rules_list.count() > 0:
|
|
self.merge_rules_list.setCurrentRow(0)
|
|
|
|
# Handle complex dicts/lists displayed as strings (if they were created with create_widget_for_setting)
|
|
# These are already handled by the simple widget logic above if they were created as QLineEdit
|
|
# with the string representation.
|
|
|
|
|
|
def populate_asset_definitions_table(self, table: QTableWidget, definitions_data: dict):
|
|
"""Populates the asset definitions table."""
|
|
table.setRowCount(len(definitions_data))
|
|
row = 0
|
|
for asset_type, details in definitions_data.items():
|
|
table.setItem(row, 0, QTableWidgetItem(asset_type))
|
|
table.setItem(row, 1, QTableWidgetItem(details.get("description", "")))
|
|
|
|
# Recreate the color widget for population
|
|
color_widget = QLineEdit(details.get("color", ""))
|
|
color_button = QPushButton("Pick Color...")
|
|
color_button.clicked.connect(lambda checked, w=color_widget: self.pick_color(w))
|
|
h_layout = QHBoxLayout()
|
|
h_layout.addWidget(color_widget)
|
|
h_layout.addWidget(color_button)
|
|
|
|
cell_widget = QWidget()
|
|
cell_widget.setLayout(h_layout)
|
|
table.setCellWidget(row, 2, cell_widget)
|
|
|
|
row += 1
|
|
|
|
def populate_file_type_definitions_table(self, table: QTableWidget, definitions_data: dict):
|
|
"""Populates the file type definitions table."""
|
|
table.setRowCount(len(definitions_data))
|
|
row = 0
|
|
for file_type, details in definitions_data.items():
|
|
table.setItem(row, 0, QTableWidgetItem(file_type))
|
|
table.setItem(row, 1, QTableWidgetItem(details.get("description", "")))
|
|
|
|
# Recreate the color widget for population
|
|
color_widget = QLineEdit(details.get("color", ""))
|
|
color_button = QPushButton("Pick Color...")
|
|
color_button.clicked.connect(lambda checked, w=color_widget: self.pick_color(w))
|
|
h_layout = QHBoxLayout()
|
|
h_layout.addWidget(color_widget)
|
|
h_layout.addWidget(color_button)
|
|
|
|
cell_widget = QWidget()
|
|
cell_widget.setLayout(h_layout)
|
|
table.setCellWidget(row, 2, cell_widget)
|
|
|
|
row += 1
|
|
|
|
|
|
# Example usage (for testing the dialog independently)
|
|
if __name__ == '__main__':
|
|
from PyQt5.QtWidgets import QApplication
|
|
import sys
|
|
|
|
app = QApplication(sys.argv)
|
|
dialog = ConfigEditorDialog()
|
|
dialog.exec_()
|
|
sys.exit(app.exec_()) |