refactor
This commit is contained in:
12
presets/__init__.py
Normal file
12
presets/__init__.py
Normal file
@@ -0,0 +1,12 @@
|
||||
"""
|
||||
Preset System Module
|
||||
|
||||
This module contains the three-tier preset storage system for the Text Texture Generator:
|
||||
- Blend file storage (highest priority)
|
||||
- Persistent file storage (survives addon updates)
|
||||
- Legacy file storage (backward compatibility)
|
||||
"""
|
||||
|
||||
# Import all preset functionality
|
||||
from .storage_system import *
|
||||
from .migration import *
|
||||
125
presets/migration.py
Normal file
125
presets/migration.py
Normal file
@@ -0,0 +1,125 @@
|
||||
# Migration functions for preset storage system
|
||||
import bpy
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
from datetime import datetime
|
||||
|
||||
def migrate_presets_if_needed():
|
||||
"""
|
||||
Migrate presets from older versions if needed.
|
||||
This function checks if migration is required and performs it automatically.
|
||||
Returns: dict with 'migrated_count' key indicating number of presets migrated.
|
||||
"""
|
||||
print("[TTG MIGRATION DEBUG] Starting migrate_presets_if_needed()")
|
||||
preferences = bpy.context.preferences.addons.get("Text_Texture_Generator_Pro")
|
||||
if not preferences:
|
||||
print("[TTG MIGRATION DEBUG] No preferences found - returning proper dict format")
|
||||
return {'migrated_count': 0}
|
||||
|
||||
addon_version = preferences.preferences.get("addon_version", "0.0.0")
|
||||
current_version = "1.0.0" # This should match the addon's current version
|
||||
|
||||
if addon_version != current_version:
|
||||
print(f"Text Texture Generator: Migrating presets from version {addon_version} to {current_version}")
|
||||
|
||||
# Backup existing presets before migration
|
||||
backup_success = backup_presets()
|
||||
if not backup_success:
|
||||
print("Text Texture Generator: Warning - Failed to backup presets before migration")
|
||||
|
||||
# Perform migration steps based on version differences
|
||||
migration_success = True
|
||||
migrated_count = 0
|
||||
|
||||
try:
|
||||
# Version-specific migration logic would go here
|
||||
# For now, we'll just update the version number
|
||||
preferences.preferences["addon_version"] = current_version
|
||||
|
||||
# In a real migration, this would be the actual count of migrated presets
|
||||
# For now, we assume 1 migration operation (version update)
|
||||
migrated_count = 1
|
||||
|
||||
if migration_success:
|
||||
print(f"Text Texture Generator: Successfully migrated presets to version {current_version}")
|
||||
else:
|
||||
print("Text Texture Generator: Migration completed with warnings")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Text Texture Generator: Error during preset migration: {str(e)}")
|
||||
migration_success = False
|
||||
migrated_count = 0
|
||||
|
||||
print(f"[TTG MIGRATION DEBUG] Migration completed, returning proper dict format: migrated_count={migrated_count}")
|
||||
return {'migrated_count': migrated_count}
|
||||
|
||||
print("[TTG MIGRATION DEBUG] No migration needed, returning proper dict format: migrated_count=0")
|
||||
return {'migrated_count': 0} # No migration needed
|
||||
|
||||
def backup_presets():
|
||||
"""
|
||||
Create a backup of current presets before migration.
|
||||
Returns True if backup was successful, False otherwise.
|
||||
"""
|
||||
try:
|
||||
# Get the addon directory
|
||||
addon_dir = os.path.dirname(__file__)
|
||||
parent_dir = os.path.dirname(addon_dir)
|
||||
|
||||
# Create backup directory with timestamp
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
backup_dir = os.path.join(parent_dir, f"preset_backup_{timestamp}")
|
||||
|
||||
# Find preset files to backup
|
||||
preset_files = []
|
||||
|
||||
# Check for blend file presets
|
||||
if bpy.data.filepath:
|
||||
blend_file_dir = os.path.dirname(bpy.data.filepath)
|
||||
preset_file = os.path.join(blend_file_dir, ".text_texture_presets.json")
|
||||
if os.path.exists(preset_file):
|
||||
preset_files.append(preset_file)
|
||||
|
||||
# Check for persistent presets
|
||||
preferences = bpy.context.preferences.addons.get("Text_Texture_Generator_Pro")
|
||||
if preferences and hasattr(preferences.preferences, 'persistent_presets_path'):
|
||||
persistent_path = preferences.preferences.persistent_presets_path
|
||||
if persistent_path and os.path.exists(persistent_path):
|
||||
preset_files.append(persistent_path)
|
||||
|
||||
# Check for legacy presets in addon directory
|
||||
legacy_preset_file = os.path.join(parent_dir, "text_texture_presets.json")
|
||||
if os.path.exists(legacy_preset_file):
|
||||
preset_files.append(legacy_preset_file)
|
||||
|
||||
# Create backup if there are files to backup
|
||||
if preset_files:
|
||||
os.makedirs(backup_dir, exist_ok=True)
|
||||
|
||||
for preset_file in preset_files:
|
||||
filename = os.path.basename(preset_file)
|
||||
backup_path = os.path.join(backup_dir, filename)
|
||||
shutil.copy2(preset_file, backup_path)
|
||||
print(f"Text Texture Generator: Backed up {filename} to {backup_dir}")
|
||||
|
||||
# Create a backup info file
|
||||
backup_info = {
|
||||
"backup_timestamp": timestamp,
|
||||
"addon_version_before_migration": bpy.context.preferences.addons.get("Text_Texture_Generator_Pro", {}).get("addon_version", "unknown"),
|
||||
"files_backed_up": [os.path.basename(f) for f in preset_files]
|
||||
}
|
||||
|
||||
info_file = os.path.join(backup_dir, "backup_info.json")
|
||||
with open(info_file, 'w') as f:
|
||||
json.dump(backup_info, f, indent=2)
|
||||
|
||||
print(f"Text Texture Generator: Created preset backup in {backup_dir}")
|
||||
return True
|
||||
else:
|
||||
print("Text Texture Generator: No preset files found to backup")
|
||||
return True # Not an error if there are no presets to backup
|
||||
|
||||
except Exception as e:
|
||||
print(f"Text Texture Generator: Error creating preset backup: {str(e)}")
|
||||
return False
|
||||
462
presets/storage_system.py
Normal file
462
presets/storage_system.py
Normal file
@@ -0,0 +1,462 @@
|
||||
import bpy
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
import platform
|
||||
|
||||
# ============================================================================
|
||||
# PRESET STORAGE SYSTEM - V2.0 (PERSISTENT STORAGE)
|
||||
# ============================================================================
|
||||
#
|
||||
# The Text Texture Generator now uses a THREE-TIER preset storage system
|
||||
# that ensures preset persistence across addon updates:
|
||||
#
|
||||
# 1. BLEND FILE STORAGE (Highest Priority)
|
||||
# - Presets travel with the .blend file
|
||||
# - Perfect for project-specific presets
|
||||
# - Stored in scene custom properties
|
||||
#
|
||||
# 2. PERSISTENT FILE STORAGE (Medium Priority)
|
||||
# - Survives addon updates and Blender upgrades
|
||||
# - Stored in Blender's user config directory
|
||||
# - Shared across all blend files
|
||||
#
|
||||
# 3. LEGACY FILE STORAGE (Lowest Priority)
|
||||
# - Old system for backward compatibility
|
||||
# - Vulnerable to addon updates
|
||||
# - Will be automatically migrated to persistent storage
|
||||
#
|
||||
# MIGRATION SYSTEM:
|
||||
# - Automatically detects addon version changes
|
||||
# - Migrates legacy presets to persistent storage
|
||||
# - Creates backups before migration
|
||||
# - Provides detailed migration reports
|
||||
#
|
||||
# IMPORT/EXPORT SYSTEM:
|
||||
# - Export all presets for manual backup
|
||||
# - Import presets with conflict resolution
|
||||
# - Supports cross-machine preset sharing
|
||||
#
|
||||
# ============================================================================
|
||||
|
||||
def get_preset_path():
|
||||
"""Get path for storing presets (legacy local storage)
|
||||
|
||||
LEGACY SYSTEM: This storage location is vulnerable to addon updates.
|
||||
Presets stored here will be lost when the addon is updated through
|
||||
Blender's Add-ons preferences. This function is maintained for
|
||||
backward compatibility only.
|
||||
|
||||
For new installations, use get_persistent_preset_path() instead.
|
||||
"""
|
||||
addon_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
|
||||
presets_dir = os.path.join(addon_dir, "presets")
|
||||
if not os.path.exists(presets_dir):
|
||||
try:
|
||||
os.makedirs(presets_dir)
|
||||
except OSError as e:
|
||||
print(f"Error creating presets directory: {e}")
|
||||
return presets_dir
|
||||
|
||||
def get_persistent_preset_path():
|
||||
"""Get persistent path for storing presets (survives addon updates)"""
|
||||
import bpy
|
||||
|
||||
# Get Blender's user config directory
|
||||
config_dir = bpy.utils.user_resource('CONFIG')
|
||||
if not config_dir:
|
||||
# Fallback to addon directory if config path unavailable
|
||||
print("[TTG] Warning: Could not get user config directory, falling back to addon directory")
|
||||
return get_preset_path()
|
||||
|
||||
# Create addon-specific subdirectory
|
||||
persistent_dir = os.path.join(config_dir, "text_texture_generator", "presets")
|
||||
|
||||
try:
|
||||
if not os.path.exists(persistent_dir):
|
||||
os.makedirs(persistent_dir, exist_ok=True)
|
||||
return persistent_dir
|
||||
except OSError as e:
|
||||
print(f"[TTG] Error creating persistent presets directory: {e}")
|
||||
# Fallback to addon directory
|
||||
return get_preset_path()
|
||||
|
||||
def get_addon_version():
|
||||
"""Get current addon version for migration tracking"""
|
||||
# Import bl_info from the main addon file
|
||||
import sys
|
||||
import importlib.util
|
||||
|
||||
# Get the main addon module
|
||||
main_module_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
|
||||
init_file = os.path.join(main_module_path, "__init__.py")
|
||||
|
||||
try:
|
||||
spec = importlib.util.spec_from_file_location("main_addon", init_file)
|
||||
main_addon = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(main_addon)
|
||||
return main_addon.bl_info["version"]
|
||||
except Exception as e:
|
||||
print(f"[TTG] Error getting addon version: {e}")
|
||||
return (2, 3, 2) # Fallback version
|
||||
|
||||
def get_version_file_path():
|
||||
"""Get path to version tracking file"""
|
||||
persistent_dir = os.path.dirname(get_persistent_preset_path())
|
||||
return os.path.join(persistent_dir, "addon_version.json")
|
||||
|
||||
def get_stored_version():
|
||||
"""Get previously stored addon version"""
|
||||
version_file = get_version_file_path()
|
||||
try:
|
||||
if os.path.exists(version_file):
|
||||
with open(version_file, 'r') as f:
|
||||
data = json.load(f)
|
||||
return tuple(data.get('version', (0, 0, 0)))
|
||||
except (json.JSONDecodeError, OSError) as e:
|
||||
print(f"[TTG] Error reading version file: {e}")
|
||||
return (0, 0, 0)
|
||||
|
||||
def save_current_version():
|
||||
"""Save current addon version to persistent storage"""
|
||||
version_file = get_version_file_path()
|
||||
try:
|
||||
version_data = {
|
||||
'version': get_addon_version(),
|
||||
'timestamp': time.time()
|
||||
}
|
||||
with open(version_file, 'w') as f:
|
||||
json.dump(version_data, f, indent=2)
|
||||
print(f"[TTG] Saved addon version {get_addon_version()} to persistent storage")
|
||||
except (OSError, json.JSONEncodeError) as e:
|
||||
print(f"[TTG] Error saving version file: {e}")
|
||||
|
||||
def get_blend_file_presets():
|
||||
"""Get presets stored in the current blend file"""
|
||||
try:
|
||||
# Get custom properties from the scene
|
||||
import bpy
|
||||
scene = bpy.context.scene
|
||||
|
||||
# DETAILED LOGGING: Function entry
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] ==================== LOADING FROM BLEND FILE ==================")
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] Function called to get presets from blend file")
|
||||
|
||||
# Store presets in scene custom properties
|
||||
if "text_texture_presets" not in scene:
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] No 'text_texture_presets' found in scene, creating empty")
|
||||
scene["text_texture_presets"] = "{}"
|
||||
else:
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] Found 'text_texture_presets' in scene")
|
||||
|
||||
preset_data = scene.get("text_texture_presets", "{}")
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] Raw preset data type: {type(preset_data)}")
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] Raw preset data length: {len(str(preset_data))} characters")
|
||||
|
||||
if isinstance(preset_data, str):
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] Preset data is string, attempting JSON parse...")
|
||||
try:
|
||||
import json
|
||||
parsed_presets = json.loads(preset_data)
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] Successfully parsed JSON")
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] Parsed presets type: {type(parsed_presets)}")
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] Parsed presets count: {len(parsed_presets) if isinstance(parsed_presets, dict) else 'N/A'}")
|
||||
|
||||
if isinstance(parsed_presets, dict):
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] Preset names: {list(parsed_presets.keys())}")
|
||||
|
||||
# DETAILED VERIFICATION: Check shader properties in each preset
|
||||
for preset_name, preset_content in parsed_presets.items():
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] Preset '{preset_name}' analysis:")
|
||||
if isinstance(preset_content, dict):
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] Keys: {list(preset_content.keys())}")
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] disable_shadows: {preset_content.get('disable_shadows', 'NOT FOUND')}")
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] disable_reflections: {preset_content.get('disable_reflections', 'NOT FOUND')}")
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] disable_backfacing: {preset_content.get('disable_backfacing', 'NOT FOUND')}")
|
||||
else:
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] ERROR: Preset content is not a dict: {type(preset_content)}")
|
||||
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] Returning parsed presets")
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] ================================================================")
|
||||
return parsed_presets
|
||||
|
||||
except json.JSONDecodeError as json_err:
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] JSON decode error: {json_err}")
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] Raw data causing error: {preset_data[:200]}...") # First 200 chars
|
||||
print("Error parsing blend file presets, resetting to empty")
|
||||
scene["text_texture_presets"] = "{}"
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] Reset to empty, returning empty dict")
|
||||
return {}
|
||||
else:
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] Preset data is not string, returning empty dict")
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] ================================================================")
|
||||
return {}
|
||||
except Exception as e:
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] EXCEPTION occurred: {e}")
|
||||
import traceback
|
||||
print(f"[GET_BLEND_FILE_PRESETS DEBUG] Full traceback: {traceback.format_exc()}")
|
||||
print(f"Error getting blend file presets: {e}")
|
||||
return {}
|
||||
|
||||
def save_blend_file_preset(preset_name, preset_data):
|
||||
"""Save a preset to the current blend file"""
|
||||
try:
|
||||
import bpy
|
||||
import json
|
||||
scene = bpy.context.scene
|
||||
|
||||
# DETAILED LOGGING: Function entry
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] ==================== SAVING TO BLEND FILE ===================")
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] Function called with preset_name: '{preset_name}'")
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] Preset data type: {type(preset_data)}")
|
||||
if isinstance(preset_data, dict):
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] Preset data keys: {list(preset_data.keys())}")
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] Shader properties in preset_data:")
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] disable_shadows: {preset_data.get('disable_shadows', 'NOT FOUND')}")
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] disable_reflections: {preset_data.get('disable_reflections', 'NOT FOUND')}")
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] disable_backfacing: {preset_data.get('disable_backfacing', 'NOT FOUND')}")
|
||||
else:
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] ERROR: preset_data is not a dictionary!")
|
||||
|
||||
# Get existing presets
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] Getting existing presets from blend file...")
|
||||
presets = get_blend_file_presets()
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] Existing presets count: {len(presets)}")
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] Existing preset names: {list(presets.keys())}")
|
||||
|
||||
# Add or update the preset
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] Adding/updating preset '{preset_name}'...")
|
||||
presets[preset_name] = preset_data
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] Presets now contains {len(presets)} items")
|
||||
|
||||
# VERIFY: Check that shader properties are in the preset we're about to save
|
||||
if preset_name in presets and isinstance(presets[preset_name], dict):
|
||||
saved_preset = presets[preset_name]
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] VERIFICATION - Shader properties in final preset:")
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] disable_shadows: {saved_preset.get('disable_shadows', 'NOT FOUND')}")
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] disable_reflections: {saved_preset.get('disable_reflections', 'NOT FOUND')}")
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] disable_backfacing: {saved_preset.get('disable_backfacing', 'NOT FOUND')}")
|
||||
|
||||
# Save back to scene custom properties
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] Converting presets to JSON...")
|
||||
json_data = json.dumps(presets, indent=2)
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] JSON data length: {len(json_data)} characters")
|
||||
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] Saving to scene custom properties...")
|
||||
scene["text_texture_presets"] = json_data
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] Successfully saved to scene['text_texture_presets']")
|
||||
|
||||
# FINAL VERIFICATION: Read back from scene to confirm save
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] FINAL VERIFICATION - Reading back from scene...")
|
||||
readback_data = scene.get("text_texture_presets", "{}")
|
||||
if readback_data:
|
||||
try:
|
||||
readback_presets = json.loads(readback_data)
|
||||
if preset_name in readback_presets:
|
||||
readback_preset = readback_presets[preset_name]
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] READBACK VERIFICATION - Shader properties:")
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] disable_shadows: {readback_preset.get('disable_shadows', 'NOT FOUND')}")
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] disable_reflections: {readback_preset.get('disable_reflections', 'NOT FOUND')}")
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] disable_backfacing: {readback_preset.get('disable_backfacing', 'NOT FOUND')}")
|
||||
else:
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] ERROR: Preset '{preset_name}' not found in readback data!")
|
||||
except json.JSONDecodeError as json_err:
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] ERROR: Could not parse readback JSON: {json_err}")
|
||||
else:
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] ERROR: No data in scene['text_texture_presets'] after save!")
|
||||
|
||||
print(f"Saved preset '{preset_name}' to blend file")
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] ================================================================")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] EXCEPTION occurred: {e}")
|
||||
import traceback
|
||||
print(f"[SAVE_BLEND_FILE_PRESET DEBUG] Full traceback: {traceback.format_exc()}")
|
||||
print(f"Error saving preset to blend file: {e}")
|
||||
return False
|
||||
|
||||
def delete_blend_file_preset(preset_name):
|
||||
"""Delete a preset from the current blend file"""
|
||||
try:
|
||||
import bpy
|
||||
import json
|
||||
scene = bpy.context.scene
|
||||
|
||||
# Get existing presets
|
||||
presets = get_blend_file_presets()
|
||||
|
||||
# Remove the preset if it exists
|
||||
if preset_name in presets:
|
||||
del presets[preset_name]
|
||||
scene["text_texture_presets"] = json.dumps(presets, indent=2)
|
||||
print(f"Deleted preset '{preset_name}' from blend file")
|
||||
return True
|
||||
else:
|
||||
print(f"Preset '{preset_name}' not found in blend file")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"Error deleting preset from blend file: {e}")
|
||||
return False
|
||||
|
||||
def initialize_presets():
|
||||
"""Initialize presets with simplified, reliable synchronization"""
|
||||
try:
|
||||
import bpy
|
||||
if not hasattr(bpy.context, 'scene') or not bpy.context.scene:
|
||||
return
|
||||
|
||||
props = bpy.context.scene.text_texture_props
|
||||
if not props:
|
||||
return
|
||||
|
||||
print(f"[TTG] Starting preset initialization...")
|
||||
|
||||
# Clear existing presets to avoid duplicates
|
||||
props.presets.clear()
|
||||
|
||||
# Collect all presets from all sources
|
||||
all_presets = {}
|
||||
|
||||
# 1. Load from blend file (highest priority - travels with file)
|
||||
try:
|
||||
blend_presets = get_blend_file_presets()
|
||||
for name, data in blend_presets.items():
|
||||
all_presets[name] = {
|
||||
'data': data,
|
||||
'source': 'BLEND_FILE'
|
||||
}
|
||||
print(f"[TTG] Found {len(blend_presets)} presets in blend file")
|
||||
except Exception as e:
|
||||
print(f"[TTG] Error loading blend file presets: {e}")
|
||||
|
||||
# 2. Load from persistent storage (survives addon updates)
|
||||
try:
|
||||
persistent_dir = get_persistent_preset_path()
|
||||
if os.path.exists(persistent_dir):
|
||||
for filename in os.listdir(persistent_dir):
|
||||
if filename.endswith('.json'):
|
||||
preset_name = os.path.splitext(filename)[0]
|
||||
# Only add if not already in blend file (blend file has priority)
|
||||
if preset_name not in all_presets:
|
||||
try:
|
||||
with open(os.path.join(persistent_dir, filename), 'r') as f:
|
||||
preset_data = json.load(f)
|
||||
all_presets[preset_name] = {
|
||||
'data': preset_data,
|
||||
'source': 'PERSISTENT_FILE'
|
||||
}
|
||||
except (json.JSONDecodeError, OSError) as e:
|
||||
print(f"[TTG] Error reading persistent preset {preset_name}: {e}")
|
||||
print(f"[TTG] Found {len([p for p in all_presets.values() if p['source'] == 'PERSISTENT_FILE'])} persistent presets")
|
||||
except Exception as e:
|
||||
print(f"[TTG] Error loading persistent presets: {e}")
|
||||
|
||||
# 3. Load from legacy storage (backward compatibility)
|
||||
try:
|
||||
legacy_dir = get_preset_path()
|
||||
if os.path.exists(legacy_dir) and legacy_dir != get_persistent_preset_path():
|
||||
for filename in os.listdir(legacy_dir):
|
||||
if filename.endswith('.json'):
|
||||
preset_name = os.path.splitext(filename)[0]
|
||||
# Only add if not already found in higher priority sources
|
||||
if preset_name not in all_presets:
|
||||
try:
|
||||
with open(os.path.join(legacy_dir, filename), 'r') as f:
|
||||
preset_data = json.load(f)
|
||||
all_presets[preset_name] = {
|
||||
'data': preset_data,
|
||||
'source': 'LOCAL_FILE'
|
||||
}
|
||||
except (json.JSONDecodeError, OSError) as e:
|
||||
print(f"[TTG] Error reading legacy preset {preset_name}: {e}")
|
||||
print(f"[TTG] Found {len([p for p in all_presets.values() if p['source'] == 'LOCAL_FILE'])} legacy presets")
|
||||
except Exception as e:
|
||||
print(f"[TTG] Error loading legacy presets: {e}")
|
||||
|
||||
# Add all presets to UI list
|
||||
for preset_name, preset_info in all_presets.items():
|
||||
preset = props.presets.add()
|
||||
preset.name = preset_name
|
||||
preset.source = preset_info['source']
|
||||
|
||||
# Report results
|
||||
blend_count = len([p for p in props.presets if p.source == 'BLEND_FILE'])
|
||||
persistent_count = len([p for p in props.presets if p.source == 'PERSISTENT_FILE'])
|
||||
legacy_count = len([p for p in props.presets if p.source == 'LOCAL_FILE'])
|
||||
|
||||
print(f"[TTG] ✅ Initialized {len(props.presets)} presets ({blend_count} blend file, {persistent_count} persistent, {legacy_count} legacy)")
|
||||
|
||||
except Exception as e:
|
||||
print(f"[TTG] Critical error in initialize_presets: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def refresh_presets():
|
||||
"""Refresh the preset list by rescanning files (legacy function)"""
|
||||
import bpy
|
||||
refresh_presets_sync()
|
||||
|
||||
# Force UI update
|
||||
try:
|
||||
if bpy.context.area:
|
||||
bpy.context.area.tag_redraw()
|
||||
except:
|
||||
pass
|
||||
|
||||
def refresh_presets_sync():
|
||||
"""Centralized, synchronous preset refresh - guarantees completion"""
|
||||
try:
|
||||
import bpy
|
||||
|
||||
print("[TTG] 🔄 Synchronizing presets...")
|
||||
|
||||
# Ensure we have valid context
|
||||
if not hasattr(bpy.context, 'scene') or not bpy.context.scene:
|
||||
print("[TTG] ⚠️ No valid scene context for preset refresh")
|
||||
return False
|
||||
|
||||
props = bpy.context.scene.text_texture_props
|
||||
if not props:
|
||||
print("[TTG] ⚠️ No text_texture_props found")
|
||||
return False
|
||||
|
||||
# Run the simplified initialization
|
||||
initialize_presets()
|
||||
|
||||
# Validate that presets are actually loaded
|
||||
preset_count = len(props.presets)
|
||||
if preset_count == 0:
|
||||
print("[TTG] ⚠️ Warning: No presets found after refresh")
|
||||
else:
|
||||
print(f"[TTG] ✅ Preset sync complete - {preset_count} presets available")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"[TTG] ❌ Error in refresh_presets_sync: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def ensure_presets_available():
|
||||
"""Defensive programming - ensure presets are loaded before UI operations"""
|
||||
try:
|
||||
import bpy
|
||||
|
||||
if not hasattr(bpy.context, 'scene') or not bpy.context.scene:
|
||||
return False
|
||||
|
||||
props = bpy.context.scene.text_texture_props
|
||||
if not props:
|
||||
return False
|
||||
|
||||
# If no presets loaded, try to load them
|
||||
if len(props.presets) == 0:
|
||||
print("[TTG] 🛡️ No presets available - attempting to load...")
|
||||
return refresh_presets_sync()
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"[TTG] Error in ensure_presets_available: {e}")
|
||||
return False
|
||||
Reference in New Issue
Block a user