Major Terminogy unification and refactor [Needs thorough testing]
This commit is contained in:
@@ -242,7 +242,6 @@ class ConfigEditorDialog(QDialog):
|
||||
|
||||
# Clear potentially lingering widget references for this tab
|
||||
self.widgets.pop("TARGET_FILENAME_PATTERN", None)
|
||||
self.widgets.pop("STANDARD_MAP_TYPES_LIST", None)
|
||||
self.widgets.pop("RESPECT_VARIANT_MAP_TYPES", None)
|
||||
self.widgets.pop("ASPECT_RATIO_DECIMALS", None)
|
||||
|
||||
@@ -276,24 +275,7 @@ class ConfigEditorDialog(QDialog):
|
||||
self.widgets["ASPECT_RATIO_DECIMALS"] = aspect_ratio_spinbox
|
||||
|
||||
main_tab_layout.addLayout(form_layout)
|
||||
|
||||
# 4. STANDARD_MAP_TYPES: QListWidget + Add/Remove Buttons
|
||||
standard_maps_layout = QVBoxLayout()
|
||||
standard_maps_label = QLabel("Standard Map Types:")
|
||||
standard_maps_layout.addWidget(standard_maps_label)
|
||||
|
||||
|
||||
standard_maps_button_layout = QHBoxLayout()
|
||||
add_button = QPushButton("Add")
|
||||
remove_button = QPushButton("Remove")
|
||||
# TODO: Connect add/remove buttons signals
|
||||
standard_maps_button_layout.addWidget(add_button)
|
||||
standard_maps_button_layout.addWidget(remove_button)
|
||||
standard_maps_button_layout.addStretch() # Push buttons left
|
||||
standard_maps_layout.addLayout(standard_maps_button_layout)
|
||||
|
||||
main_tab_layout.addLayout(standard_maps_layout)
|
||||
|
||||
|
||||
# Add the main layout to the tab's provided layout
|
||||
layout.addLayout(main_tab_layout)
|
||||
layout.addStretch() # Keep stretch at the end of the tab's main layout
|
||||
@@ -900,7 +882,7 @@ class ConfigEditorDialog(QDialog):
|
||||
# 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"]:
|
||||
if key == "RESPECT_VARIANT_MAP_TYPES":
|
||||
current_dict[k] = [item.strip() for item in widget.text().split(',') if item.strip()]
|
||||
else:
|
||||
current_dict[k] = widget.text()
|
||||
@@ -1039,7 +1021,7 @@ class ConfigEditorDialog(QDialog):
|
||||
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):
|
||||
if key == "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))
|
||||
|
||||
@@ -214,29 +214,18 @@ class SupplierSearchDelegate(QStyledItemDelegate):
|
||||
class ItemTypeSearchDelegate(QStyledItemDelegate):
|
||||
"""
|
||||
Delegate for editing item types using a QLineEdit with auto-completion.
|
||||
Loads known item types from the UnifiedViewModel's cached keys.
|
||||
Loads known item types from the provided list.
|
||||
"""
|
||||
def __init__(self, parent=None):
|
||||
def __init__(self, item_type_keys: list[str] | None = None, parent=None):
|
||||
super().__init__(parent)
|
||||
# No persistent list needed here, suggestions come from the model
|
||||
self.item_type_keys = item_type_keys if item_type_keys else []
|
||||
log.debug(f"ItemTypeSearchDelegate initialized with {len(self.item_type_keys)} keys: {self.item_type_keys}")
|
||||
|
||||
def createEditor(self, parent, option, index: QModelIndex):
|
||||
"""Creates the QLineEdit editor with a QCompleter."""
|
||||
editor = QLineEdit(parent)
|
||||
model = index.model()
|
||||
item_keys = []
|
||||
|
||||
# Get keys directly from the UnifiedViewModel
|
||||
if hasattr(model, '_file_type_keys'):
|
||||
try:
|
||||
item_keys = model._file_type_keys # Use cached keys
|
||||
except Exception as e:
|
||||
log.error(f"Error getting _file_type_keys from model in ItemTypeSearchDelegate: {e}")
|
||||
item_keys = []
|
||||
else:
|
||||
log.warning("ItemTypeSearchDelegate: Model is missing _file_type_keys attribute. Suggestions will be empty.")
|
||||
|
||||
completer = QCompleter(item_keys, editor)
|
||||
# Use the keys passed during initialization
|
||||
completer = QCompleter(self.item_type_keys, editor)
|
||||
completer.setCaseSensitivity(Qt.CaseInsensitive)
|
||||
completer.setFilterMode(Qt.MatchContains)
|
||||
completer.setCompletionMode(QCompleter.PopupCompletion)
|
||||
|
||||
@@ -71,16 +71,18 @@ class MainPanelWidget(QWidget):
|
||||
# Notify when Blender settings change
|
||||
blender_settings_changed = Signal(bool, str, str) # enabled, ng_path, mat_path
|
||||
|
||||
def __init__(self, unified_model: UnifiedViewModel, parent=None):
|
||||
def __init__(self, unified_model: UnifiedViewModel, parent=None, file_type_keys: list[str] | None = None):
|
||||
"""
|
||||
Initializes the MainPanelWidget.
|
||||
|
||||
Args:
|
||||
unified_model: The shared UnifiedViewModel instance.
|
||||
parent: The parent widget.
|
||||
file_type_keys: A list of available file type names (keys from FILE_TYPE_DEFINITIONS).
|
||||
"""
|
||||
super().__init__(parent)
|
||||
self.unified_model = unified_model
|
||||
self.file_type_keys = file_type_keys if file_type_keys else []
|
||||
self.llm_processing_active = False # Track if LLM is running (set by MainWindow)
|
||||
|
||||
# Get project root for resolving default paths if needed here
|
||||
@@ -137,7 +139,8 @@ class MainPanelWidget(QWidget):
|
||||
# TODO: Revisit ComboBoxDelegate dependency
|
||||
comboBoxDelegate = ComboBoxDelegate(self) # Pass only parent (self)
|
||||
supplierSearchDelegate = SupplierSearchDelegate(self) # Pass parent
|
||||
itemTypeSearchDelegate = ItemTypeSearchDelegate(self) # Instantiate new delegate
|
||||
# Pass file_type_keys to ItemTypeSearchDelegate
|
||||
itemTypeSearchDelegate = ItemTypeSearchDelegate(self.file_type_keys, self)
|
||||
|
||||
# Set Delegates for Columns
|
||||
self.unified_view.setItemDelegateForColumn(UnifiedViewModel.COL_SUPPLIER, supplierSearchDelegate)
|
||||
|
||||
@@ -161,8 +161,22 @@ class MainWindow(QMainWindow):
|
||||
# --- Create Panels ---
|
||||
self.preset_editor_widget = PresetEditorWidget()
|
||||
self.llm_editor_widget = LLMEditorWidget() # Instantiate the LLM editor
|
||||
# Instantiate MainPanelWidget, passing the model and self (MainWindow) for context
|
||||
self.main_panel_widget = MainPanelWidget(self.unified_model, self)
|
||||
|
||||
# --- Load File Type Definitions for Rule Editor ---
|
||||
file_type_keys = []
|
||||
try:
|
||||
# Attempt to load from base config first
|
||||
base_cfg_data = load_base_config()
|
||||
if base_cfg_data and "FILE_TYPE_DEFINITIONS" in base_cfg_data:
|
||||
file_type_keys = list(base_cfg_data["FILE_TYPE_DEFINITIONS"].keys())
|
||||
log.info(f"Loaded {len(file_type_keys)} FILE_TYPE_DEFINITIONS keys for RuleEditor.")
|
||||
else:
|
||||
log.warning("FILE_TYPE_DEFINITIONS not found in base_config. RuleEditor item_type dropdown might be empty.")
|
||||
except Exception as e:
|
||||
log.exception(f"Error loading FILE_TYPE_DEFINITIONS for RuleEditor: {e}")
|
||||
|
||||
# Instantiate MainPanelWidget, passing the model, self (MainWindow) for context, and file_type_keys
|
||||
self.main_panel_widget = MainPanelWidget(self.unified_model, self, file_type_keys=file_type_keys)
|
||||
self.log_console = LogConsoleWidget(self)
|
||||
|
||||
# --- Create Left Pane with Static Selector and Stacked Editor ---
|
||||
|
||||
@@ -407,24 +407,95 @@ class RuleBasedPredictionHandler(BasePredictionHandler):
|
||||
preset_name=preset_name
|
||||
)
|
||||
asset_rules = []
|
||||
asset_type_definitions = config._core_settings.get('ASSET_TYPE_DEFINITIONS', {})
|
||||
# asset_type_definitions = config._core_settings.get('ASSET_TYPE_DEFINITIONS', {}) # Use accessor
|
||||
file_type_definitions = config._core_settings.get('FILE_TYPE_DEFINITIONS', {})
|
||||
|
||||
for asset_name, files_info in classified_assets.items():
|
||||
if self._is_cancelled: raise RuntimeError("Prediction cancelled during hierarchy building (assets).")
|
||||
if not files_info: continue
|
||||
|
||||
item_types_in_asset = {f_info['item_type'] for f_info in files_info}
|
||||
predicted_asset_type = "Surface"
|
||||
material_indicators = {"MAP_COL", "MAP_NRM", "MAP_ROUGH", "MAP_METAL", "MAP_AO", "MAP_DISP", "COL", "NRM", "ROUGH", "METAL", "AO", "DISP"}
|
||||
if any(it in material_indicators for it in item_types_in_asset if it not in ["EXTRA", "FILE_IGNORE"]):
|
||||
predicted_asset_type = "Surface"
|
||||
asset_category_rules = config.asset_category_rules
|
||||
asset_type_definitions = config.get_asset_type_definitions() # Use new accessor
|
||||
asset_type_keys = list(asset_type_definitions.keys())
|
||||
|
||||
if asset_type_definitions and predicted_asset_type not in asset_type_definitions:
|
||||
log.warning(f"Predicted AssetType '{predicted_asset_type}' for asset '{asset_name}' is not in ASSET_TYPE_DEFINITIONS. Falling back.")
|
||||
default_type = config.default_asset_category
|
||||
if default_type in asset_type_definitions: predicted_asset_type = default_type
|
||||
elif asset_type_definitions: predicted_asset_type = list(asset_type_definitions.keys())[0]
|
||||
# Initialize predicted_asset_type using the validated default
|
||||
predicted_asset_type = config.default_asset_category
|
||||
log.debug(f"Asset '{asset_name}': Initial predicted_asset_type set to default: '{predicted_asset_type}'.")
|
||||
|
||||
# 1. Check asset_category_rules from preset
|
||||
determined_by_rule = False
|
||||
|
||||
# Check for Model type based on file patterns
|
||||
if "Model" in asset_type_keys:
|
||||
model_patterns_regex = config.compiled_model_regex # Already compiled
|
||||
for f_info in files_info:
|
||||
# Only consider files not marked as EXTRA or FILE_IGNORE for model classification
|
||||
if f_info['item_type'] in ["EXTRA", "FILE_IGNORE"]:
|
||||
continue
|
||||
file_path_obj = Path(f_info['file_path'])
|
||||
for pattern_re in model_patterns_regex:
|
||||
if pattern_re.search(file_path_obj.name):
|
||||
predicted_asset_type = "Model"
|
||||
determined_by_rule = True
|
||||
log.debug(f"Asset '{asset_name}' classified as 'Model' due to file '{file_path_obj.name}' matching pattern '{pattern_re.pattern}'.")
|
||||
break
|
||||
if determined_by_rule:
|
||||
break
|
||||
|
||||
# Check for Decal type based on keywords in asset name (if not already Model)
|
||||
if not determined_by_rule and "Decal" in asset_type_keys:
|
||||
decal_keywords = asset_category_rules.get('decal_keywords', [])
|
||||
for keyword in decal_keywords:
|
||||
# Ensure keyword is a string before trying to escape it
|
||||
if isinstance(keyword, str) and keyword: # Added check for non-empty string
|
||||
try:
|
||||
if re.search(r'\b' + re.escape(keyword) + r'\b', asset_name, re.IGNORECASE): # Match whole word
|
||||
predicted_asset_type = "Decal"
|
||||
determined_by_rule = True
|
||||
log.debug(f"Asset '{asset_name}' classified as 'Decal' due to keyword '{keyword}'.")
|
||||
break
|
||||
except re.error as e_re:
|
||||
log.warning(f"Regex error with decal_keyword '{keyword}': {e_re}")
|
||||
if determined_by_rule:
|
||||
pass # Already logged if Decal
|
||||
|
||||
# 2. If not determined by specific rules, check for Surface (if not Model/Decal by rule)
|
||||
if not determined_by_rule and predicted_asset_type == config.default_asset_category and "Surface" in asset_type_keys:
|
||||
item_types_in_asset = {f_info['item_type'] for f_info in files_info}
|
||||
# Ensure we are checking against standard map types from FILE_TYPE_DEFINITIONS
|
||||
# This check is primarily for PBR texture sets.
|
||||
material_indicators = {
|
||||
ft_key for ft_key, ft_def in config.get_file_type_definitions_with_examples().items()
|
||||
if ft_def.get('standard_type') and ft_def.get('standard_type') not in ["", "EXTRA", "FILE_IGNORE", "MODEL"]
|
||||
}
|
||||
# Add common direct standard types as well for robustness
|
||||
material_indicators.update({"COL", "NRM", "ROUGH", "METAL", "AO", "DISP"})
|
||||
|
||||
|
||||
has_material_map = False
|
||||
for item_type in item_types_in_asset:
|
||||
# Check if the item_type itself is a material indicator or its standard_type is
|
||||
if item_type in material_indicators:
|
||||
has_material_map = True
|
||||
break
|
||||
# Check standard type if item_type is a key in FILE_TYPE_DEFINITIONS
|
||||
item_def = config.get_file_type_definitions_with_examples().get(item_type)
|
||||
if item_def and item_def.get('standard_type') in material_indicators:
|
||||
has_material_map = True
|
||||
break
|
||||
|
||||
if has_material_map:
|
||||
predicted_asset_type = "Surface"
|
||||
log.debug(f"Asset '{asset_name}' classified as 'Surface' due to material indicators.")
|
||||
|
||||
# 3. Final validation: Ensure predicted_asset_type is a valid key.
|
||||
# config.default_asset_category is already validated to be a key.
|
||||
if predicted_asset_type not in asset_type_keys:
|
||||
log.warning(f"Derived AssetType '{predicted_asset_type}' for asset '{asset_name}' is not in ASSET_TYPE_DEFINITIONS. "
|
||||
f"Falling back to default: '{config.default_asset_category}'.")
|
||||
predicted_asset_type = config.default_asset_category
|
||||
# This case should ideally not be hit if logic above correctly uses asset_type_keys
|
||||
# and default_asset_category is valid.
|
||||
|
||||
asset_rule = AssetRule(asset_name=asset_name, asset_type=predicted_asset_type)
|
||||
file_rules = []
|
||||
|
||||
@@ -20,6 +20,8 @@ script_dir = Path(__file__).parent
|
||||
project_root = script_dir.parent
|
||||
PRESETS_DIR = project_root / "Presets" # Corrected path
|
||||
TEMPLATE_PATH = PRESETS_DIR / "_template.json"
|
||||
APP_SETTINGS_PATH_LOCAL = project_root / "config" / "app_settings.json"
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -49,6 +51,7 @@ class PresetEditorWidget(QWidget):
|
||||
self._init_ui()
|
||||
|
||||
# --- Initial State ---
|
||||
self._ftd_keys = self._get_file_type_definition_keys() # Load FTD keys
|
||||
self._clear_editor() # Clear/disable editor fields initially
|
||||
self._set_editor_enabled(False) # Disable editor initially
|
||||
self.populate_presets() # Populate preset list
|
||||
@@ -56,6 +59,24 @@ class PresetEditorWidget(QWidget):
|
||||
# --- Connect Editor Signals ---
|
||||
self._connect_editor_change_signals()
|
||||
|
||||
def _get_file_type_definition_keys(self) -> list[str]:
|
||||
"""Loads FILE_TYPE_DEFINITIONS keys from app_settings.json."""
|
||||
keys = []
|
||||
try:
|
||||
if APP_SETTINGS_PATH_LOCAL.is_file():
|
||||
with open(APP_SETTINGS_PATH_LOCAL, 'r', encoding='utf-8') as f:
|
||||
settings = json.load(f)
|
||||
ftd = settings.get("FILE_TYPE_DEFINITIONS", {})
|
||||
keys = list(ftd.keys())
|
||||
log.debug(f"Successfully loaded {len(keys)} FILE_TYPE_DEFINITIONS keys.")
|
||||
else:
|
||||
log.error(f"app_settings.json not found at {APP_SETTINGS_PATH_LOCAL} for PresetEditorWidget.")
|
||||
except json.JSONDecodeError as e:
|
||||
log.error(f"Failed to parse app_settings.json in PresetEditorWidget: {e}")
|
||||
except Exception as e:
|
||||
log.error(f"Error loading FILE_TYPE_DEFINITIONS keys in PresetEditorWidget: {e}")
|
||||
return keys
|
||||
|
||||
def _init_ui(self):
|
||||
"""Initializes the UI elements for the preset editor."""
|
||||
main_layout = QVBoxLayout(self)
|
||||
@@ -306,7 +327,21 @@ class PresetEditorWidget(QWidget):
|
||||
"""Adds an empty row to the specified table widget in the editor."""
|
||||
row_count = table_widget.rowCount()
|
||||
table_widget.insertRow(row_count)
|
||||
for col in range(table_widget.columnCount()): table_widget.setItem(row_count, col, QTableWidgetItem(""))
|
||||
|
||||
if table_widget == self.editor_table_map_type_mapping:
|
||||
# Column 0: Standard Type (QComboBox)
|
||||
combo_box = QComboBox()
|
||||
if self._ftd_keys:
|
||||
combo_box.addItems(self._ftd_keys)
|
||||
else:
|
||||
log.warning("FILE_TYPE_DEFINITIONS keys not available for ComboBox in map_type_mapping.")
|
||||
combo_box.currentIndexChanged.connect(self._mark_editor_unsaved) # Mark unsaved on change
|
||||
table_widget.setCellWidget(row_count, 0, combo_box)
|
||||
# Column 1: Input Keywords (QTableWidgetItem)
|
||||
table_widget.setItem(row_count, 1, QTableWidgetItem(""))
|
||||
else: # For other tables
|
||||
for col in range(table_widget.columnCount()):
|
||||
table_widget.setItem(row_count, col, QTableWidgetItem(""))
|
||||
self._mark_editor_unsaved()
|
||||
|
||||
def _editor_remove_table_row(self, table_widget: QTableWidget):
|
||||
@@ -409,18 +444,36 @@ class PresetEditorWidget(QWidget):
|
||||
self.editor_table_bit_depth_variants.setItem(i, 1, QTableWidgetItem(pattern))
|
||||
self.editor_list_extra_patterns.clear()
|
||||
self.editor_list_extra_patterns.addItems(preset_data.get("move_to_extra_patterns", []))
|
||||
self.editor_table_map_type_mapping.setRowCount(0)
|
||||
|
||||
self.editor_table_map_type_mapping.setRowCount(0) # Clear before populating
|
||||
map_mappings = preset_data.get("map_type_mapping", [])
|
||||
for i, mapping_dict in enumerate(map_mappings):
|
||||
if isinstance(mapping_dict, dict) and "target_type" in mapping_dict and "keywords" in mapping_dict:
|
||||
std_type = mapping_dict["target_type"]
|
||||
keywords = mapping_dict["keywords"]
|
||||
self.editor_table_map_type_mapping.insertRow(i)
|
||||
self.editor_table_map_type_mapping.setItem(i, 0, QTableWidgetItem(std_type))
|
||||
|
||||
# Column 0: Standard Type (QComboBox)
|
||||
combo_box = QComboBox()
|
||||
if self._ftd_keys:
|
||||
combo_box.addItems(self._ftd_keys)
|
||||
if std_type in self._ftd_keys:
|
||||
combo_box.setCurrentText(std_type)
|
||||
else:
|
||||
log.warning(f"Preset '{preset_data.get('preset_name', 'Unknown')}': target_type '{std_type}' not found in FILE_TYPE_DEFINITIONS. Selecting first available.")
|
||||
if self._ftd_keys: combo_box.setCurrentIndex(0)
|
||||
else:
|
||||
log.warning("FILE_TYPE_DEFINITIONS keys not available for ComboBox in map_type_mapping during population.")
|
||||
|
||||
combo_box.currentIndexChanged.connect(self._mark_editor_unsaved) # Connect signal
|
||||
self.editor_table_map_type_mapping.setCellWidget(i, 0, combo_box)
|
||||
|
||||
# Column 1: Input Keywords (QTableWidgetItem)
|
||||
keywords_str = [str(k) for k in keywords if isinstance(k, str)]
|
||||
self.editor_table_map_type_mapping.setItem(i, 1, QTableWidgetItem(", ".join(keywords_str)))
|
||||
else:
|
||||
log.warning(f"Skipping invalid map_type_mapping item during editor population: {mapping_dict}")
|
||||
|
||||
category_rules = preset_data.get("asset_category_rules", {})
|
||||
self.editor_list_model_patterns.clear()
|
||||
self.editor_list_model_patterns.addItems(category_rules.get("model_patterns", []))
|
||||
@@ -543,18 +596,34 @@ class PresetEditorWidget(QWidget):
|
||||
for r in range(self.editor_table_bit_depth_variants.rowCount()) if self.editor_table_bit_depth_variants.item(r, 0) and self.editor_table_bit_depth_variants.item(r, 1)}
|
||||
preset_data["source_naming"] = naming_data
|
||||
preset_data["move_to_extra_patterns"] = [self.editor_list_extra_patterns.item(i).text() for i in range(self.editor_list_extra_patterns.count())]
|
||||
|
||||
map_mappings = []
|
||||
for r in range(self.editor_table_map_type_mapping.rowCount()):
|
||||
type_item = self.editor_table_map_type_mapping.item(r, 0)
|
||||
target_type_widget = self.editor_table_map_type_mapping.cellWidget(r, 0)
|
||||
keywords_item = self.editor_table_map_type_mapping.item(r, 1)
|
||||
if type_item and type_item.text() and keywords_item and keywords_item.text():
|
||||
target_type = type_item.text().strip()
|
||||
|
||||
target_type = ""
|
||||
if isinstance(target_type_widget, QComboBox):
|
||||
target_type = target_type_widget.currentText()
|
||||
elif self.editor_table_map_type_mapping.item(r, 0): # Fallback if item is not a widget
|
||||
target_type_item = self.editor_table_map_type_mapping.item(r, 0)
|
||||
if target_type_item:
|
||||
target_type = target_type_item.text().strip()
|
||||
|
||||
if target_type and keywords_item and keywords_item.text():
|
||||
keywords = [k.strip() for k in keywords_item.text().split(',') if k.strip()]
|
||||
if target_type and keywords:
|
||||
if keywords: # Ensure keywords list is not empty after stripping
|
||||
map_mappings.append({"target_type": target_type, "keywords": keywords})
|
||||
else: log.warning(f"Skipping row {r} in map type mapping table due to empty target type or keywords.")
|
||||
else: log.warning(f"Skipping row {r} in map type mapping table due to missing items.")
|
||||
else:
|
||||
log.warning(f"Skipping row {r} in map type mapping table due to empty keywords after processing for target_type '{target_type}'.")
|
||||
else:
|
||||
# Log if target_type is empty or keywords_item is problematic
|
||||
if not target_type:
|
||||
log.warning(f"Skipping row {r} in map type mapping table due to empty target_type.")
|
||||
if not (keywords_item and keywords_item.text()):
|
||||
log.warning(f"Skipping row {r} in map type mapping table for target_type '{target_type}' due to missing or empty keywords item.")
|
||||
preset_data["map_type_mapping"] = map_mappings
|
||||
|
||||
category_rules = {}
|
||||
category_rules["model_patterns"] = [self.editor_list_model_patterns.item(i).text() for i in range(self.editor_list_model_patterns.count())]
|
||||
category_rules["decal_keywords"] = [self.editor_list_decal_keywords.item(i).text() for i in range(self.editor_list_decal_keywords.count())]
|
||||
|
||||
@@ -14,16 +14,18 @@ class RuleEditorWidget(QWidget):
|
||||
"""
|
||||
rule_updated = Signal(object) # Signal emitted when a rule is updated
|
||||
|
||||
def __init__(self, asset_types: list[str] | None = None, parent=None):
|
||||
def __init__(self, asset_types: list[str] | None = None, file_types: list[str] | None = None, parent=None):
|
||||
"""
|
||||
Initializes the RuleEditorWidget.
|
||||
|
||||
Args:
|
||||
asset_types (list[str] | None): A list of available asset type names. Defaults to None.
|
||||
file_types (list[str] | None): A list of available file type names (keys from FILE_TYPE_DEFINITIONS). Defaults to None.
|
||||
parent: The parent widget.
|
||||
"""
|
||||
super().__init__(parent)
|
||||
self.asset_types = asset_types if asset_types else [] # Store asset types
|
||||
self.file_types = file_types if file_types else [] # Store file types
|
||||
self.current_rule_type = None
|
||||
self.current_rule_object = None
|
||||
|
||||
@@ -71,12 +73,26 @@ class RuleEditorWidget(QWidget):
|
||||
Creates an appropriate editor widget based on the attribute type.
|
||||
"""
|
||||
# --- Special Handling for Asset Type Dropdown ---
|
||||
if self.current_rule_type == 'AssetRule' and attr_name == 'asset_type' and self.asset_types:
|
||||
if self.current_rule_type == 'AssetRule' and attr_name in ('asset_type', 'asset_type_override') and self.asset_types:
|
||||
widget = QComboBox()
|
||||
widget.addItems(self.asset_types)
|
||||
if attr_value in self.asset_types:
|
||||
# Handle None case for override: if None, don't select anything or select a placeholder
|
||||
if attr_value is None and attr_name == 'asset_type_override':
|
||||
# Optionally add a placeholder like "<None>" or "<Default>"
|
||||
# widget.insertItem(0, "<Default>") # Example placeholder
|
||||
widget.setCurrentIndex(-1) # No selection or placeholder
|
||||
elif attr_value in self.asset_types:
|
||||
widget.setCurrentText(attr_value)
|
||||
elif self.asset_types: # Select first item if current value is invalid
|
||||
elif self.asset_types: # Select first item if current value is invalid (and not None override)
|
||||
widget.setCurrentIndex(0)
|
||||
return widget
|
||||
# --- Special Handling for FileRule item_type and item_type_override ---
|
||||
elif self.current_rule_type == 'FileRule' and attr_name in ('item_type', 'item_type_override') and self.file_types:
|
||||
widget = QComboBox()
|
||||
widget.addItems(self.file_types)
|
||||
if attr_value in self.file_types:
|
||||
widget.setCurrentText(attr_value)
|
||||
elif self.file_types: # Select first item if current value is invalid
|
||||
widget.setCurrentIndex(0)
|
||||
return widget
|
||||
# --- Standard Type Handling ---
|
||||
@@ -187,7 +203,8 @@ if __name__ == '__main__':
|
||||
|
||||
# Example usage: Provide asset types during instantiation
|
||||
asset_types_from_config = ["Surface", "Model", "Decal", "Atlas", "UtilityMap"] # Example list
|
||||
editor = RuleEditorWidget(asset_types=asset_types_from_config)
|
||||
file_types_from_config = ["MAP_COL", "MAP_NRM", "MAP_METAL", "MAP_ROUGH", "MAP_AO", "MAP_DISP", "MAP_REFL", "MAP_SSS", "MAP_FUZZ", "MAP_IDMAP", "MAP_MASK", "MAP_IMPERFECTION", "MODEL", "EXTRA", "FILE_IGNORE"] # Example list
|
||||
editor = RuleEditorWidget(asset_types=asset_types_from_config, file_types=file_types_from_config)
|
||||
|
||||
# Test loading different rule types
|
||||
source_rule = SourceRule()
|
||||
|
||||
Reference in New Issue
Block a user