This commit is contained in:
2025-10-10 18:42:13 +02:00
parent 596f640912
commit 6253de27e2
20 changed files with 1327 additions and 12 deletions

View File

@@ -158,6 +158,21 @@ else:
TEXT_TEXTURE_OT_export_presets = MockOperator
TEXT_TEXTURE_OT_import_presets = MockOperator
# Conditionally import text editor operators (PRO feature)
try:
from .operators import (
TEXT_TEXTURE_OT_edit_multiline_text,
)
TEXT_EDITOR_OPERATORS_AVAILABLE = True
except ImportError as e:
import sys
import traceback
print(f"WARNING: text_editor_ops import failed: {e}", file=sys.stderr)
traceback.print_exc()
# Free version - create mock operator
TEXT_TEXTURE_OT_edit_multiline_text = MockOperator
TEXT_EDITOR_OPERATORS_AVAILABLE = False
# Import UI panels and functions
from .ui import (
TEXT_TEXTURE_PT_panel,
@@ -189,6 +204,7 @@ classes = (
TEXT_TEXTURE_OT_duplicate_overlay,
TEXT_TEXTURE_OT_delete_overlay,
TEXT_TEXTURE_OT_move_overlay,
TEXT_TEXTURE_OT_edit_multiline_text,
TEXT_TEXTURE_OT_open_panel,
TEXT_TEXTURE_OT_save_preset,
TEXT_TEXTURE_OT_save_preset_enter,

View File

@@ -377,4 +377,21 @@ def validate_text_rendering(img, text_positions):
pass
import traceback
traceback.print_exc()
return []
return []
from ..utils import constants
def process_text_content(text: str) -> str:
"""Process text content based on version capabilities.
FREE version: Strip newlines and normalize whitespace.
PRO version: Preserve newlines for multiline rendering.
"""
if constants.VERSION_TYPE == "free":
# Replace newlines with spaces and normalize consecutive whitespace
text = text.replace('\n', ' ')
text = ' '.join(text.split())
return text
else: # PRO version
return text

View File

@@ -42,6 +42,23 @@ except ImportError:
pass
# preset_ops module not available (free version)
PRESET_OPERATORS = []
try:
pass
from .text_editor_ops import *
from .text_editor_ops import (
TEXT_TEXTURE_OT_edit_multiline_text,
)
TEXT_EDITOR_OPERATORS = [
'TEXT_TEXTURE_OT_edit_multiline_text',
]
except ImportError as e:
import sys
import traceback
print(f"WARNING: text_editor_ops import failed in operators/__init__.py: {e}", file=sys.stderr)
traceback.print_exc()
# text_editor_ops module not available (free version)
TEXT_EDITOR_OPERATORS = []
try:
pass
@@ -88,4 +105,7 @@ __all__.extend([
__all__.extend(PRESET_OPERATORS)
# Add utility operators if available
# Add text editor operators if available
__all__.extend(TEXT_EDITOR_OPERATORS)
__all__.extend(UTILITY_OPERATORS)

View File

@@ -0,0 +1,79 @@
import bpy
from bpy.types import Operator
from bpy.props import StringProperty
from ..utils.constants import has_multiline_text, get_version_limits
class TEXT_TEXTURE_OT_edit_multiline_text(Operator):
"""Open a text editor for multiline input"""
bl_idname = "text_texture.edit_multiline_text"
bl_label = "Edit Multiline Text"
bl_description = "Open a text editor for multiline input"
bl_options = {'REGISTER', 'UNDO'}
temp_text: StringProperty(
name="Text",
description="Text content being edited",
default="",
maxlen=4096
)
@classmethod
def poll(cls, context):
"""Only available in PRO version"""
return has_multiline_text()
def invoke(self, context, event):
"""Copy current text to temp storage and open dialog"""
props = context.scene.text_texture_props
self.temp_text = props.text
return context.window_manager.invoke_props_dialog(self, width=600)
def draw(self, context):
"""Draw the dialog UI"""
layout = self.layout
limits = get_version_limits()
max_lines = limits.get("max_text_lines", 50)
max_chars = limits.get("max_text_length", 4096)
current_lines = self.temp_text.count('\n') + 1 if self.temp_text else 0
current_chars = len(self.temp_text)
col = layout.column()
col.prop(self, "temp_text", text="")
row = layout.row()
row.label(text=f"Lines: {current_lines}/{max_lines} | Chars: {current_chars}/{max_chars}")
def execute(self, context):
"""Save temp text back to main property with limits enforced"""
props = context.scene.text_texture_props
limits = get_version_limits()
max_lines = limits.get("max_text_lines", 50)
max_chars = limits.get("max_text_length", 4096)
text = self.temp_text[:max_chars]
lines = text.split('\n')
if len(lines) > max_lines:
lines = lines[:max_lines]
text = '\n'.join(lines)
props.text = text
return {'FINISHED'}
classes = (TEXT_TEXTURE_OT_edit_multiline_text,)
def register():
for cls in classes:
bpy.utils.register_class(cls)
def unregister():
for cls in reversed(classes):
bpy.utils.unregister_class(cls)

View File

@@ -12,7 +12,7 @@ from ..utils.constants import (
get_feature_availability_text, get_version_info_details,
has_image_overlays, has_basic_utilities, has_presets,
has_normal_maps, has_batch_processing, has_advanced_utilities,
has_advanced_styling, has_text_fitting
has_advanced_styling, has_text_fitting, has_multiline_text
)
@@ -200,6 +200,14 @@ def draw_text_input_section(layout, props):
pass
"""Draw the main text input field"""
layout.prop(props, "text", text="")
# Add multiline text editor button
row = layout.row()
if has_multiline_text():
row.operator("text_texture.edit_multiline_text", text="Edit Multiline Text", icon='TEXT')
else:
row.enabled = False
row.operator("text_texture.edit_multiline_text", text="Edit Multiline Text (PRO)", icon='LOCKED')
def draw_font_dropdown_section(layout, props):
pass

View File

@@ -20,7 +20,7 @@ ENABLED_FEATURES = ["basic", "preview"] if VERSION_TYPE == "free" else [
"basic", "preview", "presets", "normal_maps", "batch_processing",
"image_overlays", "basic_utilities", "advanced_utilities", "advanced_styling",
"stroke_effects", "blur_effects", "shadow_glow_effects", "shader_generation",
"text_fitting"
"text_fitting", "multiline_text"
]
# Version-specific limits (applied at build time through file exclusions)
@@ -114,6 +114,10 @@ def has_text_fitting():
"""Check if text fitting is available"""
return has_feature("text_fitting")
def has_multiline_text():
"""Check if multiline text feature is available."""
return has_feature("multiline_text")
def get_max_resolution():
"""Get maximum texture resolution based on version"""
limits = get_version_limits()
@@ -134,7 +138,8 @@ def should_show_feature_lock(feature_name):
'blur_effects': has_blur_effects,
'shadow_glow_effects': has_shadow_glow_effects,
'shader_generation': has_shader_generation,
'text_fitting': has_text_fitting
'text_fitting': has_text_fitting,
'multiline_text': has_multiline_text
}
if is_full_version():