This commit is contained in:
2025-09-17 19:43:11 +02:00
parent 7c041e2a26
commit 0e9a655ea1
58 changed files with 2821 additions and 892 deletions

View File

@@ -10,53 +10,52 @@ import os
# Import functions from parent module
try:
print("[TTG DEBUG] IMPORT TRACE: Attempting to import from ui.preview...")
print("[TTG DEBUG] IMPORT TRACE: Looking for generate_preview in ui.preview module")
pass
# First, let's see what's actually available in ui.preview
from .. import ui
print(f"[TTG DEBUG] IMPORT TRACE: ui.preview module contents: {dir(ui.preview)}")
# Now try the actual import that's failing
from ..core.generation_engine import generate_preview
print("[TTG DEBUG] IMPORT TRACE: SUCCESS - generate_preview imported from ui.preview")
from ..utils.system import get_system_fonts, get_font_enum_items
from ..presets.storage_system import refresh_presets_sync, ensure_presets_available
from ..utils.constants import sync_margin_values
except ImportError as e:
print(f"[TTG DEBUG] IMPORT ERROR: Failed to import from ui.preview: {e}")
print("[TTG DEBUG] IMPORT TRACE: This confirms generate_preview is NOT in ui.preview")
pass
# Let's check if it's available in core.generation_engine
try:
print("[TTG DEBUG] IMPORT TRACE: Attempting fallback import from core.generation_engine...")
pass
from ..core.generation_engine import generate_preview
print("[TTG DEBUG] IMPORT TRACE: SUCCESS - generate_preview found in core.generation_engine!")
from ..utils.system import get_system_fonts, get_font_enum_items
from ..presets.storage_system import refresh_presets_sync, ensure_presets_available
from ..utils.constants import sync_margin_values
print("[TTG DEBUG] IMPORT TRACE: All imports successful with corrected path")
except ImportError as fallback_error:
print(f"[TTG DEBUG] IMPORT ERROR: Fallback import also failed: {fallback_error}")
print(f"[TTG DEBUG] IMPORT ERROR: Original error was: {e}")
pass
# Fallback imports for development/testing
print("[TTG DEBUG] IMPORT TRACE: Using fallback placeholder functions")
def generate_preview(context):
pass
print("Fallback generate_preview called")
return None
def get_system_fonts():
pass
return {}
def get_font_enum_items():
pass
return [("default", "Default Font", "Use system default font", 0)]
def refresh_presets_sync():
pass
return True
def ensure_presets_available():
pass
return True
def sync_margin_values(props, changed_margin):
pass
pass
class TEXT_TEXTURE_OT_refresh_preview(Operator):
pass
"""Force refresh the preview"""
bl_idname = "text_texture.refresh_preview"
bl_label = "Refresh Preview"
@@ -64,6 +63,7 @@ class TEXT_TEXTURE_OT_refresh_preview(Operator):
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
pass
props = context.scene.text_texture_props
# Clear existing preview first
@@ -73,18 +73,22 @@ class TEXT_TEXTURE_OT_refresh_preview(Operator):
result = generate_preview(context)
if result:
pass
self.report({'INFO'}, f"Preview refreshed at {props.preview_size}px")
else:
pass
self.report({'ERROR'}, "Failed to generate preview - check console for details")
# Force UI update
for area in context.screen.areas:
pass
area.tag_redraw()
return {'FINISHED'}
class TEXT_TEXTURE_OT_view_preview_zoom(Operator):
pass
"""Open preview in new Image Editor window with zoom support"""
bl_idname = "text_texture.view_preview_zoom"
bl_label = "Enable Zoom"
@@ -92,55 +96,66 @@ class TEXT_TEXTURE_OT_view_preview_zoom(Operator):
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
pass
props = context.scene.text_texture_props
# Generate preview image when button is clicked
print("[TTG] Generating preview on button click...")
result = generate_preview(context)
if not result:
pass
self.report({'ERROR'}, "Failed to generate preview")
return {'CANCELLED'}
if not props.preview_image:
pass
self.report({'ERROR'}, "No preview image to display")
return {'CANCELLED'}
# Open a new window with Image Editor
print(f"[ZOOM] Opening new window for preview image: {props.preview_image.name}")
try:
pass
# Create a new window
bpy.ops.screen.userpref_show('INVOKE_DEFAULT')
# Wait a moment and then change the newly opened window to Image Editor
def setup_image_window():
pass
# Find the newest window (should be the one we just opened)
newest_window = None
for window in bpy.context.window_manager.windows:
pass
if window.screen.name.startswith("temp"):
pass
newest_window = window
break
if not newest_window:
pass
# Fallback: use any non-main window
for window in bpy.context.window_manager.windows:
pass
if window != bpy.context.window:
pass
newest_window = window
break
if newest_window:
pass
# Set the area type to Image Editor
for area in newest_window.screen.areas:
pass
if area.type == 'PREFERENCES':
pass
area.type = 'IMAGE_EDITOR'
print("[ZOOM] Changed area to Image Editor")
# Set the preview image
for space in area.spaces:
pass
if space.type == 'IMAGE_EDITOR':
pass
space.image = props.preview_image
print(f"[ZOOM] Set preview image: {props.preview_image.name}")
# Set up proper viewing
override = {
@@ -152,18 +167,17 @@ class TEXT_TEXTURE_OT_view_preview_zoom(Operator):
with bpy.context.temp_override(**override):
try:
pass
bpy.ops.image.view_all(fit_view=True)
print("[ZOOM] Applied fit to view")
except Exception as e:
print(f"[ZOOM] Error applying fit to view: {e}")
pass
break
break
self.report({'INFO'}, "✅ NEW WINDOW OPENED! Use mouse wheel to zoom, middle-mouse to pan")
print("[ZOOM] New window zoom feature activated successfully")
else:
print("[ZOOM] Could not find new window")
pass
self.report({'ERROR'}, "Failed to setup new window")
return None # Stop timer
@@ -172,14 +186,15 @@ class TEXT_TEXTURE_OT_view_preview_zoom(Operator):
bpy.app.timers.register(setup_image_window, first_interval=0.1)
except Exception as e:
print(f"[ZOOM] Error creating new window: {e}")
pass
# Fallback to old behavior if new window creation fails
self.report({'WARNING'}, "New window failed, trying area split instead")
# Find any area to split
for area in context.screen.areas:
pass
if area.type in ['NODE_EDITOR', 'VIEW_3D', 'PROPERTIES']:
print(f"[ZOOM] Fallback: Splitting {area.type} to create Image Editor")
pass
# Split horizontally to create a new area
with context.temp_override(area=area):
@@ -187,14 +202,17 @@ class TEXT_TEXTURE_OT_view_preview_zoom(Operator):
# Find the newly created area
for new_area in context.screen.areas:
pass
if new_area != area and new_area.y != area.y:
pass
new_area.type = 'IMAGE_EDITOR'
# Set the image in the Image Editor
for space in new_area.spaces:
pass
if space.type == 'IMAGE_EDITOR':
pass
space.image = props.preview_image
print("[ZOOM] Fallback: Image set in split Image Editor")
break
# Tag for redraw and fit to view
@@ -205,10 +223,10 @@ class TEXT_TEXTURE_OT_view_preview_zoom(Operator):
with context.temp_override(**override):
try:
pass
bpy.ops.image.view_all(fit_view=True)
print("[ZOOM] Fallback: Fit to view applied")
except Exception as e:
print(f"[ZOOM] Fallback: Error applying fit to view: {e}")
pass
self.report({'INFO'}, "✅ ZOOM ENABLED! Use mouse wheel to zoom, middle-mouse to pan")
return {'FINISHED'}
@@ -221,6 +239,7 @@ class TEXT_TEXTURE_OT_view_preview_zoom(Operator):
class TEXT_TEXTURE_OT_open_panel(Operator):
pass
"""Open Text Texture Generator panel"""
bl_idname = "text_texture.open_panel"
bl_label = "Open Text Texture Panel"
@@ -228,11 +247,16 @@ class TEXT_TEXTURE_OT_open_panel(Operator):
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
pass
# Ensure the sidebar is visible
for area in context.screen.areas:
pass
if area.type == 'VIEW_3D':
pass
for space in area.spaces:
pass
if space.type == 'VIEW_3D':
pass
space.show_region_ui = True
# Switch to Tool tab
area.tag_redraw()
@@ -240,7 +264,9 @@ class TEXT_TEXTURE_OT_open_panel(Operator):
return {'FINISHED'}
elif area.type == 'NODE_EDITOR':
for space in area.spaces:
pass
if space.type == 'NODE_EDITOR':
pass
space.show_region_ui = True
area.tag_redraw()
self.report({'INFO'}, "Text Texture panel opened in Shader Editor sidebar")
@@ -251,6 +277,7 @@ class TEXT_TEXTURE_OT_open_panel(Operator):
class TEXT_TEXTURE_OT_refresh_fonts(Operator):
pass
"""Refresh fonts"""
bl_idname = "text_texture.refresh_fonts"
bl_label = "Refresh Fonts"
@@ -258,7 +285,9 @@ class TEXT_TEXTURE_OT_refresh_fonts(Operator):
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
pass
if hasattr(get_font_enum_items, 'cached_fonts'):
pass
del get_font_enum_items.cached_fonts
get_font_enum_items.cached_fonts = get_system_fonts()
self.report({'INFO'}, f"Found {len(get_font_enum_items.cached_fonts)} fonts")
@@ -266,6 +295,7 @@ class TEXT_TEXTURE_OT_refresh_fonts(Operator):
class TEXT_TEXTURE_OT_refresh_presets(Operator):
pass
"""Refresh presets from blend file and local storage"""
bl_idname = "text_texture.refresh_presets"
bl_label = "Refresh Presets"
@@ -273,11 +303,14 @@ class TEXT_TEXTURE_OT_refresh_presets(Operator):
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
pass
try:
pass
# Use the reliable synchronous refresh system
success = refresh_presets_sync()
if success:
pass
props = context.scene.text_texture_props
total_presets = len(props.presets)
@@ -288,15 +321,18 @@ class TEXT_TEXTURE_OT_refresh_presets(Operator):
self.report({'INFO'}, f"✅ Refreshed {total_presets} presets ({blend_count} blend file, {persistent_count} persistent, {local_count} local)")
else:
pass
self.report({'WARNING'}, "Preset refresh completed with issues - check console for details")
# Force UI redraw
for area in context.screen.areas:
pass
area.tag_redraw()
return {'FINISHED'}
except Exception as e:
pass
self.report({'ERROR'}, f"Failed to refresh presets: {str(e)}")
import traceback
traceback.print_exc()
@@ -304,6 +340,7 @@ class TEXT_TEXTURE_OT_refresh_presets(Operator):
class TEXT_TEXTURE_OT_add_overlay(Operator):
pass
"""Add new image overlay"""
bl_idname = "text_texture.add_overlay"
bl_label = "Add Overlay"
@@ -311,6 +348,7 @@ class TEXT_TEXTURE_OT_add_overlay(Operator):
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
pass
props = context.scene.text_texture_props
overlay = props.image_overlays.add()
@@ -319,6 +357,7 @@ class TEXT_TEXTURE_OT_add_overlay(Operator):
# Force UI redraw
for area in context.screen.areas:
pass
area.tag_redraw()
self.report({'INFO'}, f"Added overlay: {overlay.name}")
@@ -326,6 +365,7 @@ class TEXT_TEXTURE_OT_add_overlay(Operator):
class TEXT_TEXTURE_OT_remove_overlay(Operator):
pass
"""Remove active image overlay"""
bl_idname = "text_texture.remove_overlay"
bl_label = "Remove Overlay"
@@ -333,28 +373,34 @@ class TEXT_TEXTURE_OT_remove_overlay(Operator):
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
pass
props = context.scene.text_texture_props
if props.image_overlays and props.active_overlay_index < len(props.image_overlays):
pass
overlay_name = props.image_overlays[props.active_overlay_index].name
props.image_overlays.remove(props.active_overlay_index)
# Update active index
if props.active_overlay_index >= len(props.image_overlays) and props.image_overlays:
pass
props.active_overlay_index = len(props.image_overlays) - 1
# Force UI redraw
for area in context.screen.areas:
pass
area.tag_redraw()
self.report({'INFO'}, f"Removed overlay: {overlay_name}")
else:
pass
self.report({'WARNING'}, "No overlay to remove")
return {'FINISHED'}
class TEXT_TEXTURE_OT_set_anchor_point(Operator):
pass
"""Set anchor point for text positioning"""
bl_idname = "text_texture.set_anchor_point"
bl_label = "Set Anchor Point"
@@ -364,12 +410,14 @@ class TEXT_TEXTURE_OT_set_anchor_point(Operator):
anchor_point: StringProperty()
def execute(self, context):
pass
props = context.scene.text_texture_props
props.anchor_point = self.anchor_point
return {'FINISHED'}
class TEXT_TEXTURE_OT_sync_margins(Operator):
pass
"""Sync margin values when linked"""
bl_idname = "text_texture.sync_margins"
bl_label = "Sync Margins"
@@ -379,12 +427,14 @@ class TEXT_TEXTURE_OT_sync_margins(Operator):
margin_type: StringProperty()
def execute(self, context):
pass
props = context.scene.text_texture_props
sync_margin_values(props, self.margin_type)
return {'FINISHED'}
class TEXT_TEXTURE_OT_duplicate_overlay(Operator):
pass
"""Duplicate image overlay"""
bl_idname = "text_texture.duplicate_overlay"
bl_label = "Duplicate Overlay"
@@ -394,19 +444,14 @@ class TEXT_TEXTURE_OT_duplicate_overlay(Operator):
overlay_index: IntProperty()
def execute(self, context):
pass
props = context.scene.text_texture_props
if 0 <= self.overlay_index < len(props.image_overlays):
pass
source_overlay = props.image_overlays[self.overlay_index]
# Debug logging
print(f"[DUPLICATE DEBUG] Duplicating overlay '{source_overlay.name}'")
print(f"[DUPLICATE DEBUG] Source properties:")
print(f"[DUPLICATE DEBUG] image_path: '{source_overlay.image_path}'")
print(f"[DUPLICATE DEBUG] enabled: {source_overlay.enabled}")
print(f"[DUPLICATE DEBUG] positioning_mode: '{source_overlay.positioning_mode}'")
print(f"[DUPLICATE DEBUG] scale: {source_overlay.scale}")
print(f"[DUPLICATE DEBUG] z_index: {source_overlay.z_index}")
new_overlay = props.image_overlays.add()
@@ -421,10 +466,11 @@ class TEXT_TEXTURE_OT_duplicate_overlay(Operator):
# For PREPEND/APPEND overlays, increment z_index to ensure duplicate appears above original
# This prevents the duplicate from being rendered behind the original overlay
if source_overlay.positioning_mode in ['PREPEND', 'APPEND']:
pass
# Increment z_index to ensure proper layering order for duplicated overlay
new_overlay.z_index = min(source_overlay.z_index + 1, 10) # Cap at max z_index value
print(f"[DUPLICATE DEBUG] Fixed z_index for {source_overlay.positioning_mode} overlay: {source_overlay.z_index} -> {new_overlay.z_index}")
else:
pass
# For ABSOLUTE overlays, keep same z_index (different positions so no overlap issue)
new_overlay.z_index = source_overlay.z_index
new_overlay.positioning_mode = source_overlay.positioning_mode
@@ -433,55 +479,47 @@ class TEXT_TEXTURE_OT_duplicate_overlay(Operator):
new_overlay.enabled = source_overlay.enabled
# Verify the copy was successful
print(f"[DUPLICATE DEBUG] New overlay properties:")
print(f"[DUPLICATE DEBUG] name: '{new_overlay.name}'")
print(f"[DUPLICATE DEBUG] image_path: '{new_overlay.image_path}'")
print(f"[DUPLICATE DEBUG] enabled: {new_overlay.enabled}")
print(f"[DUPLICATE DEBUG] positioning_mode: '{new_overlay.positioning_mode}'")
print(f"[DUPLICATE DEBUG] scale: {new_overlay.scale}")
print(f"[DUPLICATE DEBUG] z_index: {new_overlay.z_index}")
# Move to position after source
new_index = len(props.image_overlays) - 1
target_index = min(self.overlay_index + 1, new_index)
if new_index != target_index:
pass
props.image_overlays.move(new_index, target_index)
print(f"[DUPLICATE DEBUG] Moved overlay from index {new_index} to {target_index}")
props.active_overlay_index = target_index
# Clear any cached images to force reload
print(f"[DUPLICATE DEBUG] Clearing image cache and forcing preview update...")
# Set the updating flag to prevent recursive updates
props.is_updating = True
try:
pass
# Force immediate preview regeneration
print(f"[DUPLICATE DEBUG] Generating new preview...")
preview_result = generate_preview(context)
if preview_result:
print(f"[DUPLICATE DEBUG] Preview generated successfully")
pass
else:
print(f"[DUPLICATE DEBUG] Preview generation failed")
pass
# Force UI redraw
for area in context.screen.areas:
pass
area.tag_redraw()
except Exception as e:
print(f"[DUPLICATE DEBUG] Error updating preview: {e}")
pass
import traceback
traceback.print_exc()
finally:
props.is_updating = False
print(f"[DUPLICATE DEBUG] Total overlays now: {len(props.image_overlays)}")
print(f"[DUPLICATE DEBUG] Duplication operation completed")
self.report({'INFO'}, f"✅ Duplicated overlay: {source_overlay.name}")
else:
pass
self.report({'ERROR'}, "Invalid overlay index")
return {'CANCELLED'}
@@ -489,6 +527,7 @@ class TEXT_TEXTURE_OT_duplicate_overlay(Operator):
class TEXT_TEXTURE_OT_delete_overlay(Operator):
pass
"""Delete image overlay"""
bl_idname = "text_texture.delete_overlay"
bl_label = "Delete Overlay"
@@ -498,38 +537,39 @@ class TEXT_TEXTURE_OT_delete_overlay(Operator):
overlay_index: IntProperty()
def execute(self, context):
pass
props = context.scene.text_texture_props
print(f"[DELETE DEBUG] Deleting overlay at index {self.overlay_index}")
if 0 <= self.overlay_index < len(props.image_overlays):
pass
overlay_name = props.image_overlays[self.overlay_index].name
print(f"[DELETE DEBUG] Deleting overlay: '{overlay_name}'")
props.image_overlays.remove(self.overlay_index)
# Update active index
if props.active_overlay_index >= len(props.image_overlays) and props.image_overlays:
pass
props.active_overlay_index = len(props.image_overlays) - 1
elif not props.image_overlays:
props.active_overlay_index = 0
print(f"[DELETE DEBUG] Overlay deleted successfully. Total overlays now: {len(props.image_overlays)}")
# Force preview update after deletion
try:
pass
generate_preview(context)
print(f"[DELETE DEBUG] Preview updated after deletion")
except Exception as e:
print(f"[DELETE DEBUG] Error updating preview: {e}")
pass
# Force UI redraw
for area in context.screen.areas:
pass
area.tag_redraw()
self.report({'INFO'}, f"Deleted overlay: {overlay_name}")
else:
print(f"[DELETE DEBUG] Invalid overlay index: {self.overlay_index}")
pass
self.report({'ERROR'}, "Invalid overlay index")
return {'CANCELLED'}
@@ -537,6 +577,7 @@ class TEXT_TEXTURE_OT_delete_overlay(Operator):
class TEXT_TEXTURE_OT_move_overlay(Operator):
pass
"""Move image overlay up or down in the list"""
bl_idname = "text_texture.move_overlay"
bl_label = "Move Overlay"
@@ -552,39 +593,41 @@ class TEXT_TEXTURE_OT_move_overlay(Operator):
)
def execute(self, context):
pass
props = context.scene.text_texture_props
print(f"[MOVE DEBUG] Moving overlay at index {self.overlay_index} direction: {self.direction}")
if 0 <= self.overlay_index < len(props.image_overlays):
pass
current_index = self.overlay_index
new_index = current_index
if self.direction == 'UP' and current_index > 0:
pass
new_index = current_index - 1
elif self.direction == 'DOWN' and current_index < len(props.image_overlays) - 1:
new_index = current_index + 1
if new_index != current_index:
pass
overlay_name = props.image_overlays[current_index].name
props.image_overlays.move(current_index, new_index)
props.active_overlay_index = new_index
print(f"[MOVE DEBUG] Successfully moved overlay '{overlay_name}' from {current_index} to {new_index}")
# Force preview update after moving (order affects rendering)
try:
pass
generate_preview(context)
print(f"[MOVE DEBUG] Preview updated after move operation")
except Exception as e:
print(f"[MOVE DEBUG] Error updating preview: {e}")
pass
self.report({'INFO'}, f"Moved overlay {self.direction.lower()}")
else:
print(f"[MOVE DEBUG] No movement needed - overlay is already at edge")
pass
self.report({'INFO'}, f"Overlay is already at {self.direction.lower()} edge")
else:
print(f"[MOVE DEBUG] Invalid overlay index: {self.overlay_index}")
pass
self.report({'ERROR'}, "Invalid overlay index")
return {'CANCELLED'}