607 lines
26 KiB
Python
607 lines
26 KiB
Python
"""
|
|
Text Texture Generator - Utility Operators
|
|
Handles preview refresh, font refresh, UI operations, overlay management, and positioning utilities.
|
|
"""
|
|
|
|
import bpy
|
|
from bpy.types import Operator
|
|
from bpy.props import StringProperty, IntProperty, EnumProperty
|
|
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")
|
|
|
|
# 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")
|
|
|
|
# Let's check if it's available in core.generation_engine
|
|
try:
|
|
print("[TTG DEBUG] IMPORT TRACE: Attempting fallback import from core.generation_engine...")
|
|
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}")
|
|
# Fallback imports for development/testing
|
|
print("[TTG DEBUG] IMPORT TRACE: Using fallback placeholder functions")
|
|
def generate_preview(context):
|
|
print("Fallback generate_preview called")
|
|
return None
|
|
def get_system_fonts():
|
|
return {}
|
|
def get_font_enum_items():
|
|
return [("default", "Default Font", "Use system default font", 0)]
|
|
def refresh_presets_sync():
|
|
return True
|
|
def ensure_presets_available():
|
|
return True
|
|
def sync_margin_values(props, changed_margin):
|
|
pass
|
|
|
|
|
|
class TEXT_TEXTURE_OT_refresh_preview(Operator):
|
|
"""Force refresh the preview"""
|
|
bl_idname = "text_texture.refresh_preview"
|
|
bl_label = "Refresh Preview"
|
|
bl_description = "Force refresh the preview image"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
props = context.scene.text_texture_props
|
|
|
|
# Clear existing preview first
|
|
props.preview_image = None
|
|
|
|
# Generate new preview
|
|
result = generate_preview(context)
|
|
|
|
if result:
|
|
self.report({'INFO'}, f"Preview refreshed at {props.preview_size}px")
|
|
else:
|
|
self.report({'ERROR'}, "Failed to generate preview - check console for details")
|
|
|
|
# Force UI update
|
|
for area in context.screen.areas:
|
|
area.tag_redraw()
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class TEXT_TEXTURE_OT_view_preview_zoom(Operator):
|
|
"""Open preview in new Image Editor window with zoom support"""
|
|
bl_idname = "text_texture.view_preview_zoom"
|
|
bl_label = "Enable Zoom"
|
|
bl_description = "Open preview in new Image Editor window with zoom and pan controls"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
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:
|
|
self.report({'ERROR'}, "Failed to generate preview")
|
|
return {'CANCELLED'}
|
|
|
|
if not props.preview_image:
|
|
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:
|
|
# 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():
|
|
# Find the newest window (should be the one we just opened)
|
|
newest_window = None
|
|
for window in bpy.context.window_manager.windows:
|
|
if window.screen.name.startswith("temp"):
|
|
newest_window = window
|
|
break
|
|
|
|
if not newest_window:
|
|
# Fallback: use any non-main window
|
|
for window in bpy.context.window_manager.windows:
|
|
if window != bpy.context.window:
|
|
newest_window = window
|
|
break
|
|
|
|
if newest_window:
|
|
# Set the area type to Image Editor
|
|
for area in newest_window.screen.areas:
|
|
if area.type == 'PREFERENCES':
|
|
area.type = 'IMAGE_EDITOR'
|
|
print("[ZOOM] Changed area to Image Editor")
|
|
|
|
# Set the preview image
|
|
for space in area.spaces:
|
|
if space.type == 'IMAGE_EDITOR':
|
|
space.image = props.preview_image
|
|
print(f"[ZOOM] Set preview image: {props.preview_image.name}")
|
|
|
|
# Set up proper viewing
|
|
override = {
|
|
'window': newest_window,
|
|
'screen': newest_window.screen,
|
|
'area': area,
|
|
'region': area.regions[0] if area.regions else None
|
|
}
|
|
|
|
with bpy.context.temp_override(**override):
|
|
try:
|
|
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}")
|
|
|
|
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")
|
|
self.report({'ERROR'}, "Failed to setup new window")
|
|
|
|
return None # Stop timer
|
|
|
|
# Use a timer to set up the window after it opens
|
|
bpy.app.timers.register(setup_image_window, first_interval=0.1)
|
|
|
|
except Exception as e:
|
|
print(f"[ZOOM] Error creating new window: {e}")
|
|
# 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:
|
|
if area.type in ['NODE_EDITOR', 'VIEW_3D', 'PROPERTIES']:
|
|
print(f"[ZOOM] Fallback: Splitting {area.type} to create Image Editor")
|
|
|
|
# Split horizontally to create a new area
|
|
with context.temp_override(area=area):
|
|
bpy.ops.screen.area_split(direction='HORIZONTAL', factor=0.6)
|
|
|
|
# Find the newly created area
|
|
for new_area in context.screen.areas:
|
|
if new_area != area and new_area.y != area.y:
|
|
new_area.type = 'IMAGE_EDITOR'
|
|
|
|
# Set the image in the Image Editor
|
|
for space in new_area.spaces:
|
|
if space.type == 'IMAGE_EDITOR':
|
|
space.image = props.preview_image
|
|
print("[ZOOM] Fallback: Image set in split Image Editor")
|
|
break
|
|
|
|
# Tag for redraw and fit to view
|
|
new_area.tag_redraw()
|
|
override = context.copy()
|
|
override['area'] = new_area
|
|
override['region'] = new_area.regions[0]
|
|
|
|
with context.temp_override(**override):
|
|
try:
|
|
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}")
|
|
|
|
self.report({'INFO'}, "✅ ZOOM ENABLED! Use mouse wheel to zoom, middle-mouse to pan")
|
|
return {'FINISHED'}
|
|
break
|
|
|
|
self.report({'ERROR'}, "Failed to create Image Editor")
|
|
return {'CANCELLED'}
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class TEXT_TEXTURE_OT_open_panel(Operator):
|
|
"""Open Text Texture Generator panel"""
|
|
bl_idname = "text_texture.open_panel"
|
|
bl_label = "Open Text Texture Panel"
|
|
bl_description = "Open the Text Texture Generator panel in the sidebar"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
# Ensure the sidebar is visible
|
|
for area in context.screen.areas:
|
|
if area.type == 'VIEW_3D':
|
|
for space in area.spaces:
|
|
if space.type == 'VIEW_3D':
|
|
space.show_region_ui = True
|
|
# Switch to Tool tab
|
|
area.tag_redraw()
|
|
self.report({'INFO'}, "Text Texture panel opened in 3D View sidebar (press N if not visible)")
|
|
return {'FINISHED'}
|
|
elif area.type == 'NODE_EDITOR':
|
|
for space in area.spaces:
|
|
if space.type == 'NODE_EDITOR':
|
|
space.show_region_ui = True
|
|
area.tag_redraw()
|
|
self.report({'INFO'}, "Text Texture panel opened in Shader Editor sidebar")
|
|
return {'FINISHED'}
|
|
|
|
self.report({'WARNING'}, "Please open a 3D View or Shader Editor first")
|
|
return {'CANCELLED'}
|
|
|
|
|
|
class TEXT_TEXTURE_OT_refresh_fonts(Operator):
|
|
"""Refresh fonts"""
|
|
bl_idname = "text_texture.refresh_fonts"
|
|
bl_label = "Refresh Fonts"
|
|
bl_description = "Refresh font list"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
if hasattr(get_font_enum_items, 'cached_fonts'):
|
|
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")
|
|
return {'FINISHED'}
|
|
|
|
|
|
class TEXT_TEXTURE_OT_refresh_presets(Operator):
|
|
"""Refresh presets from blend file and local storage"""
|
|
bl_idname = "text_texture.refresh_presets"
|
|
bl_label = "Refresh Presets"
|
|
bl_description = "Reload presets from blend file and local storage"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
try:
|
|
# Use the reliable synchronous refresh system
|
|
success = refresh_presets_sync()
|
|
|
|
if success:
|
|
props = context.scene.text_texture_props
|
|
total_presets = len(props.presets)
|
|
|
|
# Count by source for detailed reporting
|
|
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'])
|
|
local_count = len([p for p in props.presets if p.source == 'LOCAL_FILE'])
|
|
|
|
self.report({'INFO'}, f"✅ Refreshed {total_presets} presets ({blend_count} blend file, {persistent_count} persistent, {local_count} local)")
|
|
else:
|
|
self.report({'WARNING'}, "Preset refresh completed with issues - check console for details")
|
|
|
|
# Force UI redraw
|
|
for area in context.screen.areas:
|
|
area.tag_redraw()
|
|
|
|
return {'FINISHED'}
|
|
|
|
except Exception as e:
|
|
self.report({'ERROR'}, f"Failed to refresh presets: {str(e)}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
return {'CANCELLED'}
|
|
|
|
|
|
class TEXT_TEXTURE_OT_add_overlay(Operator):
|
|
"""Add new image overlay"""
|
|
bl_idname = "text_texture.add_overlay"
|
|
bl_label = "Add Overlay"
|
|
bl_description = "Add new image overlay"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
props = context.scene.text_texture_props
|
|
|
|
overlay = props.image_overlays.add()
|
|
overlay.name = f"Overlay {len(props.image_overlays)}"
|
|
props.active_overlay_index = len(props.image_overlays) - 1
|
|
|
|
# Force UI redraw
|
|
for area in context.screen.areas:
|
|
area.tag_redraw()
|
|
|
|
self.report({'INFO'}, f"Added overlay: {overlay.name}")
|
|
return {'FINISHED'}
|
|
|
|
|
|
class TEXT_TEXTURE_OT_remove_overlay(Operator):
|
|
"""Remove active image overlay"""
|
|
bl_idname = "text_texture.remove_overlay"
|
|
bl_label = "Remove Overlay"
|
|
bl_description = "Remove active image overlay"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
props = context.scene.text_texture_props
|
|
|
|
if props.image_overlays and props.active_overlay_index < len(props.image_overlays):
|
|
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:
|
|
props.active_overlay_index = len(props.image_overlays) - 1
|
|
|
|
# Force UI redraw
|
|
for area in context.screen.areas:
|
|
area.tag_redraw()
|
|
|
|
self.report({'INFO'}, f"Removed overlay: {overlay_name}")
|
|
else:
|
|
self.report({'WARNING'}, "No overlay to remove")
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class TEXT_TEXTURE_OT_set_anchor_point(Operator):
|
|
"""Set anchor point for text positioning"""
|
|
bl_idname = "text_texture.set_anchor_point"
|
|
bl_label = "Set Anchor Point"
|
|
bl_description = "Set text anchor position"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
anchor_point: StringProperty()
|
|
|
|
def execute(self, context):
|
|
props = context.scene.text_texture_props
|
|
props.anchor_point = self.anchor_point
|
|
return {'FINISHED'}
|
|
|
|
|
|
class TEXT_TEXTURE_OT_sync_margins(Operator):
|
|
"""Sync margin values when linked"""
|
|
bl_idname = "text_texture.sync_margins"
|
|
bl_label = "Sync Margins"
|
|
bl_description = "Synchronize margin values"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
margin_type: StringProperty()
|
|
|
|
def execute(self, context):
|
|
props = context.scene.text_texture_props
|
|
sync_margin_values(props, self.margin_type)
|
|
return {'FINISHED'}
|
|
|
|
|
|
class TEXT_TEXTURE_OT_duplicate_overlay(Operator):
|
|
"""Duplicate image overlay"""
|
|
bl_idname = "text_texture.duplicate_overlay"
|
|
bl_label = "Duplicate Overlay"
|
|
bl_description = "Duplicate this image overlay"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
overlay_index: IntProperty()
|
|
|
|
def execute(self, context):
|
|
props = context.scene.text_texture_props
|
|
|
|
if 0 <= self.overlay_index < len(props.image_overlays):
|
|
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()
|
|
|
|
# Copy all properties with explicit verification
|
|
new_overlay.name = f"{source_overlay.name} Copy"
|
|
new_overlay.image_path = source_overlay.image_path
|
|
new_overlay.x_position = source_overlay.x_position
|
|
new_overlay.y_position = source_overlay.y_position
|
|
new_overlay.scale = source_overlay.scale
|
|
new_overlay.rotation = source_overlay.rotation
|
|
# Fix z-index assignment for duplicated overlays to ensure proper visibility
|
|
# 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']:
|
|
# 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:
|
|
# 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
|
|
new_overlay.text_spacing = source_overlay.text_spacing
|
|
new_overlay.image_spacing = source_overlay.image_spacing
|
|
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:
|
|
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:
|
|
# 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")
|
|
else:
|
|
print(f"[DUPLICATE DEBUG] Preview generation failed")
|
|
|
|
# Force UI redraw
|
|
for area in context.screen.areas:
|
|
area.tag_redraw()
|
|
|
|
except Exception as e:
|
|
print(f"[DUPLICATE DEBUG] Error updating preview: {e}")
|
|
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:
|
|
self.report({'ERROR'}, "Invalid overlay index")
|
|
return {'CANCELLED'}
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class TEXT_TEXTURE_OT_delete_overlay(Operator):
|
|
"""Delete image overlay"""
|
|
bl_idname = "text_texture.delete_overlay"
|
|
bl_label = "Delete Overlay"
|
|
bl_description = "Delete this image overlay"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
overlay_index: IntProperty()
|
|
|
|
def execute(self, context):
|
|
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):
|
|
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:
|
|
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:
|
|
generate_preview(context)
|
|
print(f"[DELETE DEBUG] Preview updated after deletion")
|
|
except Exception as e:
|
|
print(f"[DELETE DEBUG] Error updating preview: {e}")
|
|
|
|
# Force UI redraw
|
|
for area in context.screen.areas:
|
|
area.tag_redraw()
|
|
|
|
self.report({'INFO'}, f"Deleted overlay: {overlay_name}")
|
|
else:
|
|
print(f"[DELETE DEBUG] Invalid overlay index: {self.overlay_index}")
|
|
self.report({'ERROR'}, "Invalid overlay index")
|
|
return {'CANCELLED'}
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class TEXT_TEXTURE_OT_move_overlay(Operator):
|
|
"""Move image overlay up or down in the list"""
|
|
bl_idname = "text_texture.move_overlay"
|
|
bl_label = "Move Overlay"
|
|
bl_description = "Move overlay up or down in the list"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
overlay_index: IntProperty()
|
|
direction: EnumProperty(
|
|
items=[
|
|
('UP', 'Up', 'Move overlay up in list'),
|
|
('DOWN', 'Down', 'Move overlay down in list')
|
|
]
|
|
)
|
|
|
|
def execute(self, context):
|
|
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):
|
|
current_index = self.overlay_index
|
|
new_index = current_index
|
|
|
|
if self.direction == 'UP' and current_index > 0:
|
|
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:
|
|
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:
|
|
generate_preview(context)
|
|
print(f"[MOVE DEBUG] Preview updated after move operation")
|
|
except Exception as e:
|
|
print(f"[MOVE DEBUG] Error updating preview: {e}")
|
|
|
|
self.report({'INFO'}, f"Moved overlay {self.direction.lower()}")
|
|
else:
|
|
print(f"[MOVE DEBUG] No movement needed - overlay is already at edge")
|
|
self.report({'INFO'}, f"Overlay is already at {self.direction.lower()} edge")
|
|
else:
|
|
print(f"[MOVE DEBUG] Invalid overlay index: {self.overlay_index}")
|
|
self.report({'ERROR'}, "Invalid overlay index")
|
|
return {'CANCELLED'}
|
|
|
|
return {'FINISHED'}
|
|
|
|
# Export all operator classes for wildcard imports
|
|
__all__ = [
|
|
'TEXT_TEXTURE_OT_refresh_preview',
|
|
'TEXT_TEXTURE_OT_view_preview_zoom',
|
|
'TEXT_TEXTURE_OT_open_panel',
|
|
'TEXT_TEXTURE_OT_refresh_fonts',
|
|
'TEXT_TEXTURE_OT_refresh_presets',
|
|
'TEXT_TEXTURE_OT_add_overlay',
|
|
'TEXT_TEXTURE_OT_remove_overlay',
|
|
'TEXT_TEXTURE_OT_set_anchor_point',
|
|
'TEXT_TEXTURE_OT_sync_margins',
|
|
'TEXT_TEXTURE_OT_duplicate_overlay',
|
|
'TEXT_TEXTURE_OT_delete_overlay',
|
|
'TEXT_TEXTURE_OT_move_overlay',
|
|
] |