prepend append

This commit is contained in:
2025-08-11 14:40:14 +07:00
parent 4b39131efa
commit a46be309c0
3 changed files with 408 additions and 51 deletions

View File

@@ -495,12 +495,57 @@ def generate_texture_image(props, width, height):
print("WARNING: Using default font - this may not support mixed-case properly!")
print("WARNING: Consider installing additional fonts for proper mixed-case support")
# Calculate text position
text = props.text if props.text and props.text.strip() else "Hello World"
# ============================================================================
# PREPEND/APPEND TEXT PROCESSING
# ============================================================================
# Get the main text
main_text = props.text if props.text and props.text.strip() else "Hello World"
# Get prepend and append text
prepend_text = props.prepend_text.strip() if props.prepend_text else ""
append_text = props.append_text.strip() if props.append_text else ""
# Calculate margins as pixels (percentage of font size)
prepend_margin_px = int((props.prepend_margin / 100.0) * font_size_pixels) if prepend_text else 0
append_margin_px = int((props.append_margin / 100.0) * font_size_pixels) if append_text else 0
# Combine text based on layout
if props.prepend_append_layout == 'HORIZONTAL':
# Horizontal layout: [prepend] [margin] [main] [margin] [append]
text_parts = []
if prepend_text:
text_parts.append(prepend_text)
# Add proper spacing based on margin percentage
if prepend_margin_px > 0:
# Convert margin pixels to approximate space characters
space_count = max(1, int(prepend_margin_px / (font_size_pixels * 0.3)))
text_parts.append(" " * space_count)
else:
text_parts.append(" ") # Default single space
text_parts.append(main_text)
if append_text:
# Add proper spacing based on margin percentage
if append_margin_px > 0:
space_count = max(1, int(append_margin_px / (font_size_pixels * 0.3)))
text_parts.append(" " * space_count)
else:
text_parts.append(" ") # Default single space
text_parts.append(append_text)
text = "".join(text_parts)
else:
# Vertical layout will be handled separately - for now use main text
text = main_text
# ENHANCED DIAGNOSTIC LOGGING for uppercase text issue
print(f"DEBUG UPPERCASE ISSUE - Original text input: '{props.text}'")
print(f"DEBUG UPPERCASE ISSUE - Processed text: '{text}'")
print(f"DEBUG PREPEND/APPEND - Original main text: '{props.text}'")
print(f"DEBUG PREPEND/APPEND - Prepend text: '{prepend_text}'")
print(f"DEBUG PREPEND/APPEND - Append text: '{append_text}'")
print(f"DEBUG PREPEND/APPEND - Layout: '{props.prepend_append_layout}'")
print(f"DEBUG PREPEND/APPEND - Final combined text: '{text}'")
print(f"DEBUG UPPERCASE ISSUE - Text type: {type(text)}")
print(f"DEBUG UPPERCASE ISSUE - Has upper chars: {any(c.isupper() for c in text)}")
print(f"DEBUG UPPERCASE ISSUE - Has lower chars: {any(c.islower() for c in text)}")
@@ -516,14 +561,52 @@ def generate_texture_image(props, width, height):
print("WARNING: Current font may not support mixed-case rendering properly!")
print("This could be the cause of uppercase-only text rendering")
try:
bbox = draw.textbbox((0, 0), text, font=font)
text_width = max(1, bbox[2] - bbox[0])
text_height = max(1, bbox[3] - bbox[1])
except (OSError, ZeroDivisionError, ValueError) as e:
print(f"Error getting text bbox: {e}")
text_width = int(len(text) * font_size_pixels * 0.6)
text_height = font_size_pixels
# Handle vertical layout separately if needed
if props.prepend_append_layout == 'VERTICAL' and (prepend_text or append_text):
# For vertical layout, we need to render each text part separately
# and position them vertically with proper margins
# Calculate dimensions for each text part
main_bbox = draw.textbbox((0, 0), main_text, font=font)
main_width = max(1, main_bbox[2] - main_bbox[0])
main_height = max(1, main_bbox[3] - main_bbox[1])
total_width = main_width
total_height = main_height
text_elements = [(main_text, main_width, main_height)]
if prepend_text:
prepend_bbox = draw.textbbox((0, 0), prepend_text, font=font)
prepend_width = max(1, prepend_bbox[2] - prepend_bbox[0])
prepend_height = max(1, prepend_bbox[3] - prepend_bbox[1])
total_width = max(total_width, prepend_width)
total_height += prepend_height + prepend_margin_px
text_elements.insert(0, (prepend_text, prepend_width, prepend_height))
if append_text:
append_bbox = draw.textbbox((0, 0), append_text, font=font)
append_width = max(1, append_bbox[2] - append_bbox[0])
append_height = max(1, append_bbox[3] - append_bbox[1])
total_width = max(total_width, append_width)
total_height += append_height + append_margin_px
text_elements.append((append_text, append_width, append_height))
text_width = total_width
text_height = total_height
print(f"DEBUG VERTICAL LAYOUT - Total dimensions: {text_width}x{text_height}")
print(f"DEBUG VERTICAL LAYOUT - Text elements: {len(text_elements)}")
else:
# Standard bbox calculation for horizontal layout or single text
try:
bbox = draw.textbbox((0, 0), text, font=font)
text_width = max(1, bbox[2] - bbox[0])
text_height = max(1, bbox[3] - bbox[1])
except (OSError, ZeroDivisionError, ValueError) as e:
print(f"Error getting text bbox: {e}")
text_width = int(len(text) * font_size_pixels * 0.6)
text_height = font_size_pixels
# ============================================================================
# ENHANCED POSITIONING SYSTEM - Replaces hardcoded vertical centering
@@ -550,10 +633,41 @@ def generate_texture_image(props, width, height):
if len(props.text_color) > 3:
text_color += (int(props.text_color[3] * 255),)
print(f"DEBUG UPPERCASE ISSUE - About to draw text: '{text}' with font: {font}")
draw.text((x, y), text, fill=text_color, font=font)
print(f"Text drawn at ({x}, {y})")
print(f"DEBUG UPPERCASE ISSUE - Text drawing completed")
# Handle vertical layout rendering
if props.prepend_append_layout == 'VERTICAL' and (prepend_text or append_text):
print(f"DEBUG VERTICAL LAYOUT - Rendering vertical text layout")
# Calculate starting Y position for vertical stack
current_y = y
# Render prepend text if exists
if prepend_text:
print(f"DEBUG VERTICAL LAYOUT - Drawing prepend text: '{prepend_text}' at y={current_y}")
draw.text((x, current_y), prepend_text, fill=text_color, font=font)
prepend_bbox = draw.textbbox((0, 0), prepend_text, font=font)
prepend_height = prepend_bbox[3] - prepend_bbox[1]
current_y += prepend_height + prepend_margin_px
# Render main text
print(f"DEBUG VERTICAL LAYOUT - Drawing main text: '{main_text}' at y={current_y}")
draw.text((x, current_y), main_text, fill=text_color, font=font)
main_bbox = draw.textbbox((0, 0), main_text, font=font)
main_height = main_bbox[3] - main_bbox[1]
current_y += main_height + append_margin_px
# Render append text if exists
if append_text:
print(f"DEBUG VERTICAL LAYOUT - Drawing append text: '{append_text}' at y={current_y}")
draw.text((x, current_y), append_text, fill=text_color, font=font)
print(f"DEBUG VERTICAL LAYOUT - Vertical text rendering completed")
else:
# Standard horizontal rendering
print(f"DEBUG UPPERCASE ISSUE - About to draw text: '{text}' with font: {font}")
draw.text((x, y), text, fill=text_color, font=font)
print(f"Text drawn at ({x}, {y})")
print(f"DEBUG UPPERCASE ISSUE - Text drawing completed")
# Add text to elements list
elements.append((0, 'text', text_img, 0, 0))
@@ -851,6 +965,12 @@ class TEXT_TEXTURE_Properties(PropertyGroup):
default=False
)
expand_colors: BoolProperty(
name="Colors",
description="Show/hide Colors section",
default=False
)
text: StringProperty(
name="Text",
description="Text to render as texture",
@@ -859,6 +979,54 @@ class TEXT_TEXTURE_Properties(PropertyGroup):
update=update_live_preview
)
# Prepend/Append Text Properties
prepend_text: StringProperty(
name="Prepend Text",
description="Text to prepend before main text",
default="",
maxlen=512,
update=update_live_preview
)
append_text: StringProperty(
name="Append Text",
description="Text to append after main text",
default="",
maxlen=512,
update=update_live_preview
)
prepend_margin: FloatProperty(
name="Prepend Margin",
description="Margin between prepend text and main text as percentage of font size",
default=50.0,
min=0.0,
max=200.0,
precision=1,
update=update_live_preview
)
append_margin: FloatProperty(
name="Append Margin",
description="Margin between main text and append text as percentage of font size",
default=50.0,
min=0.0,
max=200.0,
precision=1,
update=update_live_preview
)
prepend_append_layout: EnumProperty(
name="Layout",
description="Layout arrangement for prepend/main/append text",
items=[
('HORIZONTAL', 'Horizontal', 'Arrange text horizontally: [prepend] [main] [append]'),
('VERTICAL', 'Vertical', 'Arrange text vertically: prepend above, main center, append below'),
],
default='HORIZONTAL',
update=update_live_preview
)
texture_width: IntProperty(
name="Width",
description="Texture width in pixels",
@@ -1442,8 +1610,16 @@ class TEXT_TEXTURE_OT_save_preset(Operator):
# Validate preset name characters (avoid filesystem issues)
import re
if not re.match(r'^[a-zA-Z0-9_\-\s]+$', preset_name):
self.report({'ERROR'}, "Preset name can only contain letters, numbers, spaces, hyphens, and underscores")
# Allow Unicode letters, numbers, spaces, hyphens, underscores, and common accented characters
# This pattern supports international characters like ö, ü, ñ, etc.
if not re.match(r'^[\w\s\-]+$', preset_name, re.UNICODE):
self.report({'ERROR'}, "Preset name contains invalid characters for filesystem compatibility")
return {'CANCELLED'}
# Additional check for filesystem-unsafe characters
invalid_chars = ['<', '>', ':', '"', '|', '?', '*', '/', '\\']
if any(char in preset_name for char in invalid_chars):
self.report({'ERROR'}, f"Preset name cannot contain: {' '.join(invalid_chars)}")
return {'CANCELLED'}
# Check for duplicate names
@@ -1473,6 +1649,11 @@ class TEXT_TEXTURE_OT_save_preset(Operator):
'custom_font_path': props.custom_font_path,
'use_custom_font': props.use_custom_font,
'text_align': props.text_align,
'prepend_text': props.prepend_text,
'append_text': props.append_text,
'prepend_margin': props.prepend_margin,
'append_margin': props.append_margin,
'prepend_append_layout': props.prepend_append_layout,
'image_overlays': []
}
@@ -1587,6 +1768,11 @@ class TEXT_TEXTURE_OT_load_preset(Operator):
props.custom_font_path = preset_data.get('custom_font_path', props.custom_font_path)
props.use_custom_font = preset_data.get('use_custom_font', props.use_custom_font)
props.text_align = preset_data.get('text_align', props.text_align)
props.prepend_text = preset_data.get('prepend_text', props.prepend_text)
props.append_text = preset_data.get('append_text', props.append_text)
props.prepend_margin = preset_data.get('prepend_margin', props.prepend_margin)
props.append_margin = preset_data.get('append_margin', props.append_margin)
props.prepend_append_layout = preset_data.get('prepend_append_layout', props.prepend_append_layout)
# Load overlay data
props.image_overlays.clear()
@@ -1859,6 +2045,25 @@ def draw_positioning_section(layout, props):
row.prop(props, "texture_width", text="Width")
row.prop(props, "texture_height", text="Height")
layout.separator()
# Prepend/Append Text Section
layout.label(text="Additional Text:", icon='TEXT')
# Compact layout selector
layout.prop(props, "prepend_append_layout", text="Layout")
# Minimal prepend/append controls
row = layout.row(align=True)
row.prop(props, "prepend_text", text="Prepend")
if props.prepend_text.strip():
row.prop(props, "prepend_margin", text="", slider=True)
row = layout.row(align=True)
row.prop(props, "append_text", text="Append")
if props.append_text.strip():
row.prop(props, "append_margin", text="", slider=True)
layout.separator()
layout.prop(props, "position_mode", text="Mode")
@@ -1927,20 +2132,26 @@ def draw_font_settings_section(layout, props):
row = layout.row(align=True)
row.prop(props, "padding")
row.prop(props, "text_align")
def draw_colors_section(layout, props):
"""Draw color controls for text and background"""
layout.label(text="Text Color:", icon='COLOR')
layout.prop(props, "text_color", text="")
layout.separator()
layout.label(text="Colors:")
layout.prop(props, "text_color")
layout.label(text="Background Color:", icon='IMAGE_PLANE')
layout.prop(props, "background_transparent")
if not props.background_transparent:
layout.prop(props, "background_color")
layout.prop(props, "background_color", text="")
def draw_preview_options_section(layout, props):
"""Draw preview options"""
"""Draw preview options (preview-specific settings only)"""
layout.prop(props, "preview_size", text="Preview Size")
layout.separator()
layout.label(text="Preview Background Display:", icon='SCENE')
layout.prop(props, "preview_bg_type", text="Background")
if props.preview_bg_type == 'color':
layout.prop(props, "preview_bg_color", text="Background Color")
layout.prop(props, "preview_bg_color", text="Preview Display Color")
elif props.preview_bg_type == 'gradient':
layout.prop(props, "preview_bg_color", text="Color 1")
layout.prop(props, "preview_bg_color2", text="Color 2")
@@ -2048,6 +2259,10 @@ class TEXT_TEXTURE_PT_panel(Panel):
layout.separator()
draw_generate_button(layout)
# Preview Button at top level
layout.separator()
layout.operator("text_texture.view_preview_zoom", text="Open Preview Window", icon='WINDOW')
layout.separator()
# COLLAPSIBLE SECTIONS
@@ -2067,16 +2282,10 @@ class TEXT_TEXTURE_PT_panel(Panel):
if font_section:
draw_font_settings_section(font_section, props)
# Preview Options Section (collapsed by default)
preview_section = draw_collapsible_header(layout, "expand_preview_options", "Preview Options", 'IMAGE_DATA')
if preview_section:
draw_preview_options_section(preview_section, props)
# Preview Button in expanded section
layout.separator()
preview_section.separator()
button_row = preview_section.row()
button_row.operator("text_texture.view_preview_zoom", text="Open Preview Window", icon='WINDOW')
# Colors Section (collapsed by default)
colors_section = draw_collapsible_header(layout, "expand_colors", "Colors", 'COLOR')
if colors_section:
draw_colors_section(colors_section, props)
# Presets Section (collapsed by default)
presets_section = draw_collapsible_header(layout, "expand_presets", "Presets", 'PRESET')
@@ -2108,6 +2317,10 @@ class TEXT_TEXTURE_PT_panel_3d(Panel):
layout.separator()
draw_generate_button(layout)
# Preview Button at top level
layout.separator()
layout.operator("text_texture.view_preview_zoom", text="Open Preview Window", icon='WINDOW')
layout.separator()
# COLLAPSIBLE SECTIONS
@@ -2127,15 +2340,10 @@ class TEXT_TEXTURE_PT_panel_3d(Panel):
if font_section:
draw_font_settings_section(font_section, props)
# Preview Options Section (collapsed by default)
preview_section = draw_collapsible_header(layout, "expand_preview_options", "Preview Options", 'IMAGE_DATA')
if preview_section:
draw_preview_options_section(preview_section, props)
# Preview Button in expanded section
preview_section.separator()
button_row = preview_section.row()
button_row.operator("text_texture.view_preview_zoom", text="Open Preview Window", icon='WINDOW')
# Colors Section (collapsed by default)
colors_section = draw_collapsible_header(layout, "expand_colors", "Colors", 'COLOR')
if colors_section:
draw_colors_section(colors_section, props)
# Presets Section (collapsed by default)
presets_section = draw_collapsible_header(layout, "expand_presets", "Presets", 'PRESET')
@@ -2167,6 +2375,10 @@ class TEXT_TEXTURE_PT_panel_properties(Panel):
layout.separator()
draw_generate_button(layout)
# Preview Button at top level
layout.separator()
layout.operator("text_texture.view_preview_zoom", text="Open Preview Window", icon='WINDOW')
layout.separator()
# COLLAPSIBLE SECTIONS
@@ -2186,15 +2398,10 @@ class TEXT_TEXTURE_PT_panel_properties(Panel):
if font_section:
draw_font_settings_section(font_section, props)
# Preview Options Section (collapsed by default)
preview_section = draw_collapsible_header(layout, "expand_preview_options", "Preview Options", 'IMAGE_DATA')
if preview_section:
draw_preview_options_section(preview_section, props)
# Preview Button in expanded section
preview_section.separator()
button_row = preview_section.row()
button_row.operator("text_texture.view_preview_zoom", text="Open Preview Window", icon='WINDOW')
# Colors Section (collapsed by default)
colors_section = draw_collapsible_header(layout, "expand_colors", "Colors", 'COLOR')
if colors_section:
draw_colors_section(colors_section, props)
# Presets Section (collapsed by default)
presets_section = draw_collapsible_header(layout, "expand_presets", "Presets", 'PRESET')