Compare commits
8 commits
840fdf1ca4
...
e14251523b
Author | SHA1 | Date | |
---|---|---|---|
e14251523b | |||
8f3d58aad0 | |||
2ace31a246 | |||
88cfaf3be7 | |||
10e57dd46a | |||
c27cf41368 | |||
7a034efd1c | |||
3ea2f0e304 |
4 changed files with 500 additions and 178 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,6 +1,7 @@
|
||||||
# python
|
# python
|
||||||
__pycache__
|
__pycache__
|
||||||
venv
|
venv
|
||||||
|
venv*
|
||||||
|
|
||||||
# vim
|
# vim
|
||||||
*.swo
|
*.swo
|
||||||
|
|
196
__init__.py
196
__init__.py
|
@ -137,9 +137,12 @@ class ABC3D_glyph_properties(bpy.types.PropertyGroup):
|
||||||
|
|
||||||
def update_callback(self, context):
|
def update_callback(self, context):
|
||||||
if self.text_id >= 0:
|
if self.text_id >= 0:
|
||||||
butils.set_text_on_curve(
|
# butils.set_text_on_curve(
|
||||||
context.scene.abc3d_data.available_texts[self.text_id]
|
# context.scene.abc3d_data.available_texts[self.text_id]
|
||||||
)
|
# )
|
||||||
|
t = butils.get_text_properties(self.text_id)
|
||||||
|
if t is not None:
|
||||||
|
butils.set_text_on_curve(t)
|
||||||
|
|
||||||
glyph_id: bpy.props.StringProperty(maxlen=1)
|
glyph_id: bpy.props.StringProperty(maxlen=1)
|
||||||
text_id: bpy.props.IntProperty(
|
text_id: bpy.props.IntProperty(
|
||||||
|
@ -259,6 +262,7 @@ class ABC3D_text_properties(bpy.types.PropertyGroup):
|
||||||
)
|
)
|
||||||
distribution_type: bpy.props.StringProperty()
|
distribution_type: bpy.props.StringProperty()
|
||||||
glyphs: bpy.props.CollectionProperty(type=ABC3D_glyph_properties)
|
glyphs: bpy.props.CollectionProperty(type=ABC3D_glyph_properties)
|
||||||
|
actual_text: bpy.props.StringProperty()
|
||||||
|
|
||||||
|
|
||||||
class ABC3D_data(bpy.types.PropertyGroup):
|
class ABC3D_data(bpy.types.PropertyGroup):
|
||||||
|
@ -280,17 +284,19 @@ class ABC3D_data(bpy.types.PropertyGroup):
|
||||||
|
|
||||||
def active_text_index_update(self, context):
|
def active_text_index_update(self, context):
|
||||||
if self.active_text_index != -1:
|
if self.active_text_index != -1:
|
||||||
o = self.available_texts[self.active_text_index].text_object
|
text_properties = butils.get_text_properties(self.active_text_index, context.scene)
|
||||||
# active_text_index changed. so let's update the selection
|
if text_properties is not None:
|
||||||
# check if it is already selected
|
o = text_properties.text_object
|
||||||
# or perhaps one of the glyphs
|
# active_text_index changed. so let's update the selection
|
||||||
if (
|
# check if it is already selected
|
||||||
not o.select_get()
|
# or perhaps one of the glyphs
|
||||||
and not len([c for c in o.children if c.select_get()]) > 0
|
if (o is not None
|
||||||
):
|
and not o.select_get()
|
||||||
bpy.ops.object.select_all(action="DESELECT")
|
and not len([c for c in o.children if c.select_get()]) > 0
|
||||||
o.select_set(True)
|
):
|
||||||
bpy.context.view_layer.objects.active = o
|
bpy.ops.object.select_all(action="DESELECT")
|
||||||
|
o.select_set(True)
|
||||||
|
context.view_layer.objects.active = o
|
||||||
# else:
|
# else:
|
||||||
# print("already selected")
|
# print("already selected")
|
||||||
|
|
||||||
|
@ -451,7 +457,7 @@ class ABC3D_PT_TextPlacement(bpy.types.Panel):
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(self, context):
|
def poll(self, context):
|
||||||
if (
|
if (
|
||||||
type(context.active_object) != type(None)
|
context.active_object is not None
|
||||||
and context.active_object.type == "CURVE"
|
and context.active_object.type == "CURVE"
|
||||||
):
|
):
|
||||||
self.can_place = True
|
self.can_place = True
|
||||||
|
@ -502,8 +508,8 @@ class ABC3D_PT_TextManagement(bpy.types.Panel):
|
||||||
for c in t.text_object.children:
|
for c in t.text_object.children:
|
||||||
if (
|
if (
|
||||||
len(c.users_collection) > 0
|
len(c.users_collection) > 0
|
||||||
and not isinstance(c.get(f"{utils.prefix()}_linked_textobject"), None)
|
and not isinstance(c.get(f"{utils.prefix()}_text_id"), None)
|
||||||
and c.get(f"{utils.prefix()}_linked_textobject") == t.text_id
|
and c.get(f"{utils.prefix()}_text_id") == t.text_id
|
||||||
):
|
):
|
||||||
remove_me = False
|
remove_me = False
|
||||||
# not sure how to solve this reliably atm,
|
# not sure how to solve this reliably atm,
|
||||||
|
@ -542,14 +548,14 @@ class ABC3D_PT_TextManagement(bpy.types.Panel):
|
||||||
remove_list.append(i)
|
remove_list.append(i)
|
||||||
|
|
||||||
for i in remove_list:
|
for i in remove_list:
|
||||||
if type(abc3d_data.available_texts[i].text_object) != type(None):
|
if abc3d_data.available_texts[i].text_object is not None:
|
||||||
mom = abc3d_data.available_texts[i].text_object
|
mom = abc3d_data.available_texts[i].text_object
|
||||||
|
|
||||||
def delif(o, p):
|
def delif(o, p):
|
||||||
if p in o:
|
if p in o:
|
||||||
del o[p]
|
del o[p]
|
||||||
|
|
||||||
delif(mom, f"{utils.prefix()}_linked_textobject")
|
delif(mom, f"{utils.prefix()}_text_id")
|
||||||
delif(mom, f"{utils.prefix()}_font_name")
|
delif(mom, f"{utils.prefix()}_font_name")
|
||||||
delif(mom, f"{utils.prefix()}_face_name")
|
delif(mom, f"{utils.prefix()}_face_name")
|
||||||
delif(mom, f"{utils.prefix()}_font_size")
|
delif(mom, f"{utils.prefix()}_font_size")
|
||||||
|
@ -736,11 +742,11 @@ class ABC3D_PT_TextPropertiesPanel(bpy.types.Panel):
|
||||||
# and bpy.context.object.select_get():
|
# and bpy.context.object.select_get():
|
||||||
a_o = bpy.context.active_object
|
a_o = bpy.context.active_object
|
||||||
if a_o is not None:
|
if a_o is not None:
|
||||||
if f"{utils.prefix()}_linked_textobject" in a_o:
|
if f"{utils.prefix()}_text_id" in a_o:
|
||||||
text_index = a_o[f"{utils.prefix()}_linked_textobject"]
|
text_index = a_o[f"{utils.prefix()}_text_id"]
|
||||||
return bpy.context.scene.abc3d_data.available_texts[text_index]
|
return bpy.context.scene.abc3d_data.available_texts[text_index]
|
||||||
elif a_o.parent is not None and f"{utils.prefix()}_linked_textobject" in a_o.parent:
|
elif a_o.parent is not None and f"{utils.prefix()}_text_id" in a_o.parent:
|
||||||
text_index = a_o.parent[f"{utils.prefix()}_linked_textobject"]
|
text_index = a_o.parent[f"{utils.prefix()}_text_id"]
|
||||||
return bpy.context.scene.abc3d_data.available_texts[text_index]
|
return bpy.context.scene.abc3d_data.available_texts[text_index]
|
||||||
else:
|
else:
|
||||||
for t in bpy.context.scene.abc3d_data.available_texts:
|
for t in bpy.context.scene.abc3d_data.available_texts:
|
||||||
|
@ -752,9 +758,9 @@ class ABC3D_PT_TextPropertiesPanel(bpy.types.Panel):
|
||||||
def get_active_glyph_properties(self):
|
def get_active_glyph_properties(self):
|
||||||
a_o = bpy.context.active_object
|
a_o = bpy.context.active_object
|
||||||
if a_o is not None:
|
if a_o is not None:
|
||||||
if (f"{utils.prefix()}_linked_textobject" in a_o
|
if (f"{utils.prefix()}_text_id" in a_o
|
||||||
and f"{utils.prefix()}_glyph_index" in a_o):
|
and f"{utils.prefix()}_glyph_index" in a_o):
|
||||||
text_index = a_o[f"{utils.prefix()}_linked_textobject"]
|
text_index = a_o[f"{utils.prefix()}_text_id"]
|
||||||
glyph_index = a_o[f"{utils.prefix()}_glyph_index"]
|
glyph_index = a_o[f"{utils.prefix()}_glyph_index"]
|
||||||
return bpy.context.scene.abc3d_data.available_texts[text_index].glyphs[glyph_index]
|
return bpy.context.scene.abc3d_data.available_texts[text_index].glyphs[glyph_index]
|
||||||
else:
|
else:
|
||||||
|
@ -795,13 +801,13 @@ class ABC3D_PT_TextPropertiesPanel(bpy.types.Panel):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(self, context):
|
def poll(self, context):
|
||||||
return self.get_active_text_properties(self) is not None
|
try:
|
||||||
|
return self.get_active_text_properties(self) is not None
|
||||||
|
except IndexError:
|
||||||
|
return False
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
wm = context.window_manager
|
|
||||||
scene = context.scene
|
|
||||||
abc3d_data = scene.abc3d_data
|
|
||||||
|
|
||||||
props = self.get_active_text_properties()
|
props = self.get_active_text_properties()
|
||||||
glyph_props = self.get_active_glyph_properties()
|
glyph_props = self.get_active_glyph_properties()
|
||||||
|
@ -1190,6 +1196,11 @@ class ABC3D_OT_RemoveText(bpy.types.Operator):
|
||||||
description="Remove both ABC3D text functionality and the objects/meshes",
|
description="Remove both ABC3D text functionality and the objects/meshes",
|
||||||
default=True,
|
default=True,
|
||||||
)
|
)
|
||||||
|
remove_custom_properties: bpy.props.BoolProperty(
|
||||||
|
name="Remove Custom Properties",
|
||||||
|
description="Remove ABC3D custom properties of objects",
|
||||||
|
default=True,
|
||||||
|
)
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
wm = context.window_manager
|
wm = context.window_manager
|
||||||
|
@ -1206,26 +1217,27 @@ class ABC3D_OT_RemoveText(bpy.types.Operator):
|
||||||
return {"CANCELLED"}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
i = abc3d_data.active_text_index
|
i = abc3d_data.active_text_index
|
||||||
if type(abc3d_data.available_texts[i].text_object) != type(None):
|
if abc3d_data.available_texts[i].text_object is not None:
|
||||||
mom = abc3d_data.available_texts[i].text_object
|
mom = abc3d_data.available_texts[i].text_object
|
||||||
|
|
||||||
def delif(o, p):
|
if self.remove_custom_properties:
|
||||||
if p in o:
|
def delif(o, p):
|
||||||
del o[p]
|
if p in o:
|
||||||
|
del o[p]
|
||||||
|
|
||||||
delif(mom, f"{utils.prefix()}_type")
|
delif(mom, f"{utils.prefix()}_type")
|
||||||
delif(mom, f"{utils.prefix()}_linked_textobject")
|
delif(mom, f"{utils.prefix()}_text_id")
|
||||||
delif(mom, f"{utils.prefix()}_font_name")
|
delif(mom, f"{utils.prefix()}_font_name")
|
||||||
delif(mom, f"{utils.prefix()}_face_name")
|
delif(mom, f"{utils.prefix()}_face_name")
|
||||||
delif(mom, f"{utils.prefix()}_font_size")
|
delif(mom, f"{utils.prefix()}_font_size")
|
||||||
delif(mom, f"{utils.prefix()}_letter_spacing")
|
delif(mom, f"{utils.prefix()}_letter_spacing")
|
||||||
delif(mom, f"{utils.prefix()}_orientation")
|
delif(mom, f"{utils.prefix()}_orientation")
|
||||||
delif(mom, f"{utils.prefix()}_translation")
|
delif(mom, f"{utils.prefix()}_translation")
|
||||||
delif(mom, f"{utils.prefix()}_offset")
|
delif(mom, f"{utils.prefix()}_offset")
|
||||||
if self.remove_objects:
|
if self.remove_objects:
|
||||||
remove_list = []
|
remove_list = []
|
||||||
for g in abc3d_data.available_texts[i].glyphs:
|
for g in abc3d_data.available_texts[i].glyphs:
|
||||||
if type(g) != type(None):
|
if g is not None:
|
||||||
remove_list.append(g.glyph_object)
|
remove_list.append(g.glyph_object)
|
||||||
butils.simply_delete_objects(remove_list)
|
butils.simply_delete_objects(remove_list)
|
||||||
|
|
||||||
|
@ -1785,20 +1797,44 @@ def compare_text_object_with_object(t, o, strict=False):
|
||||||
# if
|
# if
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def link_text_object_with_new_text_properties(text_object, scene = None):
|
||||||
|
lock_depsgraph_updates(auto_unlock_s=-1)
|
||||||
|
butils.link_text_object_with_new_text_properties(text_object, scene)
|
||||||
|
unlock_depsgraph_updates()
|
||||||
|
|
||||||
|
|
||||||
def detect_text():
|
def detect_text():
|
||||||
|
lock_depsgraph_updates(auto_unlock_s=-1)
|
||||||
scene = bpy.context.scene
|
scene = bpy.context.scene
|
||||||
abc3d_data = scene.abc3d_data
|
abc3d_data = scene.abc3d_data
|
||||||
for o in scene.objects:
|
required_keys = [
|
||||||
if o[f"{utils.prefix()}_type"] == "textobject":
|
"type",
|
||||||
linked_textobject = int(o[f"{utils.prefix()}_linked_textobject"])
|
"text_id",
|
||||||
|
"font_name",
|
||||||
|
"face_name",
|
||||||
|
"text",
|
||||||
|
]
|
||||||
|
objects = scene.objects
|
||||||
|
for o in objects:
|
||||||
|
valid = True
|
||||||
|
for key in required_keys:
|
||||||
|
if butils.get_key(key) not in o:
|
||||||
|
valid = False
|
||||||
|
break
|
||||||
|
if not valid:
|
||||||
|
continue
|
||||||
|
if o[butils.get_key("type")] == "textobject":
|
||||||
|
current_text_id = int(o[butils.get_key("text_id")])
|
||||||
|
text_properties = butils.get_text_properties(current_text_id)
|
||||||
if (
|
if (
|
||||||
len(abc3d_data.available_texts) > linked_textobject
|
text_properties is not None
|
||||||
and abc3d_data.available_texts[linked_textobject].text_object == o
|
and text_properties.text_object == o
|
||||||
):
|
):
|
||||||
t = abc3d_data.available_texts[linked_textobject]
|
# all good
|
||||||
a = test_availability(o["font_name"], o["face_name"], o["text"])
|
pass
|
||||||
butils.transfer_blender_object_to_text_properties(o, t)
|
else:
|
||||||
|
butils.link_text_object_with_new_text_properties(o, scene)
|
||||||
|
unlock_depsgraph_updates()
|
||||||
|
|
||||||
|
|
||||||
def load_used_glyphs():
|
def load_used_glyphs():
|
||||||
|
@ -1850,51 +1886,50 @@ def on_frame_changed(self, dummy):
|
||||||
butils.set_text_on_curve(t)
|
butils.set_text_on_curve(t)
|
||||||
|
|
||||||
|
|
||||||
depsgraph_updates_locked = False
|
depsgraph_updates_locked = 0
|
||||||
|
|
||||||
|
|
||||||
def unlock_depsgraph_updates():
|
def unlock_depsgraph_updates():
|
||||||
global depsgraph_updates_locked
|
global depsgraph_updates_locked
|
||||||
depsgraph_updates_locked = False
|
depsgraph_updates_locked -= 1
|
||||||
|
|
||||||
|
|
||||||
def lock_depsgraph_updates():
|
def lock_depsgraph_updates(auto_unlock_s=1):
|
||||||
global depsgraph_updates_locked
|
global depsgraph_updates_locked
|
||||||
depsgraph_updates_locked = True
|
depsgraph_updates_locked += 1
|
||||||
if bpy.app.timers.is_registered(unlock_depsgraph_updates):
|
if auto_unlock_s >= 0:
|
||||||
bpy.app.timers.unregister(unlock_depsgraph_updates)
|
if bpy.app.timers.is_registered(unlock_depsgraph_updates):
|
||||||
bpy.app.timers.register(unlock_depsgraph_updates, first_interval=1)
|
bpy.app.timers.unregister(unlock_depsgraph_updates)
|
||||||
|
bpy.app.timers.register(unlock_depsgraph_updates, first_interval=auto_unlock_s)
|
||||||
|
|
||||||
|
def are_depsgraph_updates_locked():
|
||||||
|
global depsgraph_updates_locked
|
||||||
|
return depsgraph_updates_locked > 0
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
||||||
@persistent
|
@persistent
|
||||||
def on_depsgraph_update(scene, depsgraph):
|
def on_depsgraph_update(scene, depsgraph):
|
||||||
global depsgraph_updates_locked
|
if not bpy.context.mode.startswith("EDIT") and not are_depsgraph_updates_locked():
|
||||||
if not bpy.context.mode.startswith("EDIT") and not depsgraph_updates_locked:
|
|
||||||
for u in depsgraph.updates:
|
for u in depsgraph.updates:
|
||||||
if (
|
if (
|
||||||
f"{utils.prefix()}_linked_textobject" in u.id.keys()
|
butils.get_key("text_id") in u.id.keys()
|
||||||
and f"{utils.prefix()}_type" in u.id.keys()
|
and butils.get_key("type") in u.id.keys()
|
||||||
and u.id[f"{utils.prefix()}_type"] == "textobject"
|
and u.id[butils.get_key("type")] == "textobject"
|
||||||
):
|
):
|
||||||
linked_textobject = u.id[f"{utils.prefix()}_linked_textobject"]
|
text_id = u.id[butils.get_key("text_id")]
|
||||||
if (
|
# if u.is_updated_geometry:
|
||||||
u.is_updated_geometry
|
text_properties = butils.get_text_properties(text_id)
|
||||||
and len(scene.abc3d_data.available_texts) > linked_textobject
|
if text_properties is not None:
|
||||||
):
|
if text_properties.text_object == u.id.original:
|
||||||
lock_depsgraph_updates()
|
# nothing to do
|
||||||
|
pass
|
||||||
def later():
|
else:
|
||||||
if butils.lock_depsgraph_update_n_times <= 0:
|
# must be duplicate
|
||||||
butils.set_text_on_curve(
|
link_text_object_with_new_text_properties(u.id.original, scene)
|
||||||
scene.abc3d_data.available_texts[linked_textobject]
|
else:
|
||||||
)
|
# must be new thing
|
||||||
elif butils.lock_depsgraph_update_n_times <= 0:
|
link_text_object_with_new_text_properties(u.id.original, scene)
|
||||||
butils.lock_depsgraph_update_n_times -= 1
|
|
||||||
|
|
||||||
butils.run_in_main_thread(later)
|
|
||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
|
@ -1925,6 +1960,7 @@ def register():
|
||||||
butils.run_in_main_thread(butils.update_available_fonts)
|
butils.run_in_main_thread(butils.update_available_fonts)
|
||||||
butils.run_in_main_thread(load_used_glyphs)
|
butils.run_in_main_thread(load_used_glyphs)
|
||||||
butils.run_in_main_thread(butils.update_types)
|
butils.run_in_main_thread(butils.update_types)
|
||||||
|
butils.run_in_main_thread(detect_text)
|
||||||
|
|
||||||
Font.init()
|
Font.init()
|
||||||
|
|
||||||
|
|
459
butils.py
459
butils.py
|
@ -52,6 +52,9 @@ def get_parent_collection_names(collection, parent_names):
|
||||||
get_parent_collection_names(parent_collection, parent_names)
|
get_parent_collection_names(parent_collection, parent_names)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def get_key(key):
|
||||||
|
return f"{utils.prefix()}_{key}"
|
||||||
|
|
||||||
|
|
||||||
# Ensure it's a curve object
|
# Ensure it's a curve object
|
||||||
# TODO: no raising, please
|
# TODO: no raising, please
|
||||||
|
@ -556,8 +559,8 @@ def update_available_fonts():
|
||||||
# def update_available_texts():
|
# def update_available_texts():
|
||||||
# abc3d_data = bpy.context.scene.abc3d_data
|
# abc3d_data = bpy.context.scene.abc3d_data
|
||||||
# for o in bpy.context.scene.objects:
|
# for o in bpy.context.scene.objects:
|
||||||
# if "linked_textobject" in o.keys():
|
# if "text_id" in o.keys():
|
||||||
# i = o["linked_textobject"]
|
# i = o["text_id"]
|
||||||
# found = False
|
# found = False
|
||||||
# if len(abc3d_data.available_texts) > i:
|
# if len(abc3d_data.available_texts) > i:
|
||||||
# if abc3d_data.available_texts[i].glyphs
|
# if abc3d_data.available_texts[i].glyphs
|
||||||
|
@ -692,7 +695,7 @@ def is_text_object(o):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def is_glyph(o):
|
def is_glyph_object(o):
|
||||||
if f"{utils.prefix()}_type" in o:
|
if f"{utils.prefix()}_type" in o:
|
||||||
return o[f"{utils.prefix()}_type"] == "glyph"
|
return o[f"{utils.prefix()}_type"] == "glyph"
|
||||||
try:
|
try:
|
||||||
|
@ -706,6 +709,10 @@ def is_glyph(o):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def is_glyph(o):
|
||||||
|
return is_glyph_object(o)
|
||||||
|
|
||||||
|
|
||||||
def update_types():
|
def update_types():
|
||||||
scene = bpy.context.scene
|
scene = bpy.context.scene
|
||||||
abc3d_data = scene.abc3d_data
|
abc3d_data = scene.abc3d_data
|
||||||
|
@ -765,6 +772,15 @@ def prepare_text(font_name, face_name, text, allow_replacement=True):
|
||||||
load_font_from_filepath(filepath, loadable, font_name, face_name)
|
load_font_from_filepath(filepath, loadable, font_name, face_name)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def predict_actual_text(text_properties):
|
||||||
|
availability = Font.test_availability(text_properties.font_name, text_properties.face_name, text_properties.text)
|
||||||
|
AVAILABILITY = Font.test_availability(text_properties.font_name, text_properties.face_name, text_properties.text.swapcase())
|
||||||
|
t_text = text_properties.text
|
||||||
|
for c in availability["missing"]:
|
||||||
|
t_text = t_text.replace(c, "")
|
||||||
|
for c in AVAILABILITY["missing"]:
|
||||||
|
t_text = t_text.replace(c, "")
|
||||||
|
return t_text
|
||||||
|
|
||||||
def is_bezier(curve):
|
def is_bezier(curve):
|
||||||
if curve.type != "CURVE":
|
if curve.type != "CURVE":
|
||||||
|
@ -777,10 +793,346 @@ def is_bezier(curve):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def would_regenerate(text_properties):
|
text_object_keys = [
|
||||||
mom = text_properties.text_object
|
"font_name",
|
||||||
|
"face_name",
|
||||||
|
"type",
|
||||||
|
"text_id",
|
||||||
|
"font_size",
|
||||||
|
"letter_spacing",
|
||||||
|
"distribution_type",
|
||||||
|
"orientation",
|
||||||
|
"translation",
|
||||||
|
"offset",
|
||||||
|
"text",
|
||||||
|
]
|
||||||
|
|
||||||
if len(text_properties.text) != len(text_properties.glyphs):
|
glyph_object_keys = [
|
||||||
|
"type",
|
||||||
|
"glyph_index",
|
||||||
|
"glyph_id",
|
||||||
|
"text_id",
|
||||||
|
"font_name",
|
||||||
|
"face_name",
|
||||||
|
"font_size",
|
||||||
|
"letter_spacing",
|
||||||
|
"alternate",
|
||||||
|
]
|
||||||
|
|
||||||
|
ignore_keys_in_text_object_comparison = [
|
||||||
|
"type",
|
||||||
|
]
|
||||||
|
|
||||||
|
ignore_keys_in_glyph_object_comparison = [
|
||||||
|
"type",
|
||||||
|
"glyph_index",
|
||||||
|
"font_name",
|
||||||
|
"face_name",
|
||||||
|
"text_id",
|
||||||
|
]
|
||||||
|
|
||||||
|
ignore_keys_in_glyph_object_transfer = [
|
||||||
|
"type",
|
||||||
|
"text_id",
|
||||||
|
"glyph_index",
|
||||||
|
]
|
||||||
|
|
||||||
|
keys_trigger_regeneration = [
|
||||||
|
"font_name",
|
||||||
|
"face_name",
|
||||||
|
]
|
||||||
|
|
||||||
|
COMPARE_TEXT_OBJECT_SAME = 0
|
||||||
|
COMPARE_TEXT_OBJECT_DIFFER = 1
|
||||||
|
COMPARE_TEXT_OBJECT_REGENERATE = 2
|
||||||
|
|
||||||
|
def find_free_text_id():
|
||||||
|
scene = bpy.context.scene
|
||||||
|
abc3d_data = scene.abc3d_data
|
||||||
|
text_id = 0
|
||||||
|
found_free = False
|
||||||
|
while not found_free:
|
||||||
|
occupied = False
|
||||||
|
for t in abc3d_data.available_texts:
|
||||||
|
if text_id == t.text_id:
|
||||||
|
occupied = True
|
||||||
|
if occupied:
|
||||||
|
text_id += 1
|
||||||
|
else:
|
||||||
|
found_free = True
|
||||||
|
return text_id
|
||||||
|
|
||||||
|
def compare_text_properties_to_text_object(text_properties, o):
|
||||||
|
for key in text_object_keys:
|
||||||
|
if key in ignore_keys_in_text_object_comparison:
|
||||||
|
continue
|
||||||
|
object_key = get_key(key)
|
||||||
|
text_property = text_properties[key] if key in text_properties else getattr(text_properties, key)
|
||||||
|
text_object_property = o[object_key] if object_key in o else False
|
||||||
|
if text_property != text_object_property:
|
||||||
|
if key in keys_trigger_regeneration:
|
||||||
|
return COMPARE_TEXT_OBJECT_REGENERATE
|
||||||
|
elif key in ["translation", "orientation"]:
|
||||||
|
if (
|
||||||
|
text_property[0] != text_object_property[0] or
|
||||||
|
text_property[1] != text_object_property[1] or
|
||||||
|
text_property[2] != text_object_property[2]):
|
||||||
|
return COMPARE_TEXT_OBJECT_DIFFER
|
||||||
|
# else same
|
||||||
|
else:
|
||||||
|
return COMPARE_TEXT_OBJECT_DIFFER
|
||||||
|
# else same
|
||||||
|
return COMPARE_TEXT_OBJECT_SAME
|
||||||
|
|
||||||
|
|
||||||
|
def transfer_text_properties_to_text_object(text_properties, o):
|
||||||
|
for key in text_object_keys:
|
||||||
|
if key in ignore_keys_in_text_object_comparison:
|
||||||
|
continue
|
||||||
|
object_key = get_key(key)
|
||||||
|
text_property = text_properties[key] if key in text_properties else getattr(text_properties, key)
|
||||||
|
o[object_key] = text_property
|
||||||
|
o[get_key("type")] = "textobject"
|
||||||
|
|
||||||
|
|
||||||
|
def get_glyph(glyph_id, font_name, face_name, notify_on_replacement=False):
|
||||||
|
glyph_tmp = Font.get_glyph(font_name,
|
||||||
|
face_name,
|
||||||
|
glyph_id,
|
||||||
|
-1)
|
||||||
|
if glyph_tmp is None:
|
||||||
|
space_width = Font.is_space(glyph_id)
|
||||||
|
if space_width:
|
||||||
|
return space_width
|
||||||
|
|
||||||
|
message = f"Glyph not found for font_name='{text_properties.font_name}' face_name='{text_properties.face_name}' glyph_id='{glyph_id}'"
|
||||||
|
replaced = False
|
||||||
|
if glyph_id.isalpha():
|
||||||
|
possible_replacement = glyph_id.swapcase()
|
||||||
|
glyph_tmp = Font.get_glyph(
|
||||||
|
text_properties.font_name,
|
||||||
|
text_properties.face_name,
|
||||||
|
possible_replacement,
|
||||||
|
-1
|
||||||
|
)
|
||||||
|
if glyph_tmp is not None:
|
||||||
|
message = message + f" (replaced with '{possible_replacement}')"
|
||||||
|
replaced = True
|
||||||
|
|
||||||
|
if notify_on_replacement:
|
||||||
|
ShowMessageBox(
|
||||||
|
title="Glyph replaced" if replaced else "Glyph missing",
|
||||||
|
icon="INFO" if replaced else "ERROR",
|
||||||
|
message=message,
|
||||||
|
prevent_repeat=True,
|
||||||
|
)
|
||||||
|
if not replaced:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return glyph_tmp.original
|
||||||
|
|
||||||
|
def get_text_properties(text_id, scene = None):
|
||||||
|
if scene is None:
|
||||||
|
scene = bpy.context.scene
|
||||||
|
abc3d_data = scene.abc3d_data
|
||||||
|
for t in abc3d_data.available_texts:
|
||||||
|
if text_id == t.text_id:
|
||||||
|
return t
|
||||||
|
return None
|
||||||
|
|
||||||
|
def duplicate(obj, data=True, actions=True, add_to_collection=True, collection=None, recursive=True):
|
||||||
|
obj_copy = obj.copy()
|
||||||
|
if add_to_collection:
|
||||||
|
if collection:
|
||||||
|
collection.objects.link(obj_copy)
|
||||||
|
elif len(obj.users_collection) > 0:
|
||||||
|
obj.users_collection[0].objects.link(obj_copy)
|
||||||
|
if data and obj.data:
|
||||||
|
obj_copy.data = obj.data.copy()
|
||||||
|
if actions and obj.animation_data:
|
||||||
|
obj_copy.animation_data.action = obj.animation_data.action.copy()
|
||||||
|
if recursive and hasattr(obj, "children"):
|
||||||
|
for child in obj.children:
|
||||||
|
child_copy = duplicate(child)
|
||||||
|
child_copy.parent_type = child.parent_type
|
||||||
|
child_copy.parent = obj_copy
|
||||||
|
# child_copy.matrix_parent_inverse = obj_copy.matrix_world.inverted()
|
||||||
|
return obj_copy
|
||||||
|
|
||||||
|
def transfer_text_object_to_text_properties(text_object, text_properties, id_from_text_properties=True):
|
||||||
|
possible_brother_text_id = text_object[get_key("text_id")] if get_key("text_id") in text_object else ""
|
||||||
|
for key in text_object_keys:
|
||||||
|
if key in ignore_keys_in_text_object_comparison:
|
||||||
|
continue
|
||||||
|
object_key = get_key(key)
|
||||||
|
if id_from_text_properties and key == "text_id":
|
||||||
|
text_object[object_key] = text_properties["text_id"]
|
||||||
|
else:
|
||||||
|
text_object_property = text_object[object_key] if object_key in text_object else False
|
||||||
|
if text_object_property is not False:
|
||||||
|
text_properties[key] = text_object_property
|
||||||
|
|
||||||
|
if len(text_object.children) == 0:
|
||||||
|
if possible_brother_text_id != text_properties["text_id"] and possible_brother_text_id != "":
|
||||||
|
possible_brother_properties = get_text_properties(possible_brother_text_id)
|
||||||
|
possible_brother_object = possible_brother_properties.text_object
|
||||||
|
if possible_brother_object is not None:
|
||||||
|
for child in possible_brother_object.children:
|
||||||
|
if is_glyph_object(child):
|
||||||
|
child_copy = duplicate(child)
|
||||||
|
child_copy.parent_type = child.parent_type
|
||||||
|
child_copy.parent = text_object
|
||||||
|
parent_to_curve(child_copy, text_object)
|
||||||
|
# child_copy.matrix_parent_inverse = text_object.matrix_world.inverted()
|
||||||
|
|
||||||
|
found_reconstructable_glyphs = False
|
||||||
|
glyph_objects_with_indices = []
|
||||||
|
required_keys = [
|
||||||
|
"glyph_index",
|
||||||
|
"glyph_id",
|
||||||
|
"type"
|
||||||
|
]
|
||||||
|
for glyph_object in text_object.children:
|
||||||
|
if is_glyph_object(glyph_object):
|
||||||
|
has_required_keys = True
|
||||||
|
for key in required_keys:
|
||||||
|
if get_key(key) not in glyph_object:
|
||||||
|
has_required_keys = False
|
||||||
|
if has_required_keys:
|
||||||
|
inner_node = None
|
||||||
|
glyph_id = glyph_object[get_key("glyph_id")]
|
||||||
|
for c in glyph_object.children:
|
||||||
|
if c.name.startswith(f"{glyph_id}_mesh"):
|
||||||
|
inner_node = c
|
||||||
|
if inner_node is not None:
|
||||||
|
glyph_objects_with_indices.append(glyph_object)
|
||||||
|
|
||||||
|
glyph_objects_with_indices.sort(key=lambda g: g[get_key("glyph_index")])
|
||||||
|
text = ""
|
||||||
|
for g in glyph_objects_with_indices:
|
||||||
|
text += g[get_key("glyph_id")]
|
||||||
|
is_good_text = False
|
||||||
|
if len(text) > 0:
|
||||||
|
if text == text_properties.text:
|
||||||
|
is_good_text = True
|
||||||
|
else:
|
||||||
|
availability = Font.test_availability(text_properties.font_name, text_properties.face_name, text_properties.text)
|
||||||
|
AVAILABILITY = Font.test_availability(text_properties.font_name, text_properties.face_name, text_properties.text.swapcase())
|
||||||
|
t_text = text_properties.text
|
||||||
|
for c in availability["missing"]:
|
||||||
|
t_text = t_text.replace(c, "")
|
||||||
|
for c in AVAILABILITY["missing"]:
|
||||||
|
t_text = t_text.replace(c, "")
|
||||||
|
if len(t_text) == len(text):
|
||||||
|
is_good_text = True
|
||||||
|
if is_good_text:
|
||||||
|
text_properties.actual_text = text
|
||||||
|
text_properties.glyphs.clear()
|
||||||
|
prepare_text(text_properties.font_name, text_properties.face_name, text)
|
||||||
|
fail_after_all = False
|
||||||
|
for glyph_index, glyph_object in enumerate(glyph_objects_with_indices):
|
||||||
|
glyph_id = glyph_object[get_key("glyph_id")]
|
||||||
|
# glyph_tmp = Font.get_glyph(text_properties.font_name,
|
||||||
|
# text_properties.face_name,
|
||||||
|
# glyph_id)
|
||||||
|
# glyph = glyph_tmp.original
|
||||||
|
glyph_properties = text_properties.glyphs.add()
|
||||||
|
|
||||||
|
transfer_glyph_object_to_glyph_properties(glyph_object, glyph_properties)
|
||||||
|
glyph_properties["glyph_object"] = glyph_object
|
||||||
|
glyph_properties["glyph_index"] = glyph_index
|
||||||
|
inner_node = None
|
||||||
|
for c in glyph_object.children:
|
||||||
|
if c.name.startswith(f"{glyph_id}_mesh"):
|
||||||
|
inner_node = c
|
||||||
|
if inner_node is None:
|
||||||
|
fail_after_all = True
|
||||||
|
pass
|
||||||
|
glyph_properties["glyph_object"] = glyph_object
|
||||||
|
if not fail_after_all:
|
||||||
|
found_reconstructable_glyphs = True
|
||||||
|
|
||||||
|
if not found_reconstructable_glyphs:
|
||||||
|
text_properties.actual_text = ""
|
||||||
|
text_properties.glyphs.clear()
|
||||||
|
unfortunate_children = text_object.children
|
||||||
|
completely_delete_objects(unfortunate_children)
|
||||||
|
def kill_children():
|
||||||
|
completely_delete_objects(unfortunate_children)
|
||||||
|
run_in_main_thread(kill_children)
|
||||||
|
|
||||||
|
if "font_name" in text_properties and "face_name" in text_properties:
|
||||||
|
font_name = text_properties["font_name"]
|
||||||
|
face_name = text_properties["face_name"]
|
||||||
|
text_properties.font = f"{font_name} {face_name}"
|
||||||
|
|
||||||
|
|
||||||
|
def link_text_object_with_new_text_properties(text_object, scene=None):
|
||||||
|
if scene is None:
|
||||||
|
scene = bpy.context.scene
|
||||||
|
text_id = find_free_text_id()
|
||||||
|
text_properties = scene.abc3d_data.available_texts.add()
|
||||||
|
text_properties["text_id"] = text_id
|
||||||
|
# text_object[get_key("text_id")] = text_id
|
||||||
|
prepare_text(text_object[get_key("font_name")],
|
||||||
|
text_object[get_key("face_name")],
|
||||||
|
text_object[get_key("text")])
|
||||||
|
text_properties.text_object = text_object
|
||||||
|
transfer_text_object_to_text_properties(text_object, text_properties)
|
||||||
|
|
||||||
|
|
||||||
|
def test_finding():
|
||||||
|
scene = bpy.context.scene
|
||||||
|
abc3d_data = scene.abc3d_data
|
||||||
|
text_id = find_free_text_id()
|
||||||
|
t = abc3d_data.available_texts.add()
|
||||||
|
t["text_id"] = text_id
|
||||||
|
o = bpy.context.active_object
|
||||||
|
transfer_text_object_to_text_properties(o, t)
|
||||||
|
|
||||||
|
# def detect_texts():
|
||||||
|
# scene = bpy.context.scene
|
||||||
|
# abc3d_data = scene.abc3d_data
|
||||||
|
# for o in bpy.data.objects:
|
||||||
|
# if get_key("type") in o \
|
||||||
|
# and o[get_key("type") == "textobject" \
|
||||||
|
# and o[get_key("t
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def link_text_object_and_text_properties(o, text_properties):
|
||||||
|
text_id = text_properties.text_id
|
||||||
|
o["text_id"] = text_id
|
||||||
|
text_properties.textobject = o
|
||||||
|
|
||||||
|
def get_glyph_object_property(text_properties, glyph_properties, key):
|
||||||
|
if key in glyph_properties:
|
||||||
|
return glyph_properties[key]
|
||||||
|
if hasattr(glyph_properties, key):
|
||||||
|
return getattr(glyph_properties, key)
|
||||||
|
return text_properties[key] if key in text_properties else getattr(text_properties, key)
|
||||||
|
|
||||||
|
def transfer_properties_to_glyph_object(text_properties, glyph_properties, glyph_object):
|
||||||
|
for key in glyph_object_keys:
|
||||||
|
if key in ignore_keys_in_glyph_object_transfer:
|
||||||
|
continue
|
||||||
|
object_key = get_key(key)
|
||||||
|
glyph_object[object_key] = get_glyph_object_property(text_properties, glyph_properties, key)
|
||||||
|
glyph_object[get_key("type")] = "glyph"
|
||||||
|
glyph_object[get_key("text_id")] = text_properties["text_id"]
|
||||||
|
|
||||||
|
def transfer_glyph_object_to_glyph_properties(glyph_object, glyph_properties):
|
||||||
|
for key in glyph_object_keys:
|
||||||
|
if key in ignore_keys_in_glyph_object_transfer:
|
||||||
|
continue
|
||||||
|
glyph_properties[key] = glyph_object[get_key(key)]
|
||||||
|
glyph_properties["text_id"] = glyph_object[get_key("text_id")]
|
||||||
|
|
||||||
|
def would_regenerate(text_properties):
|
||||||
|
predicted_text = predict_actual_text(text_properties)
|
||||||
|
if text_properties.actual_text != predicted_text:
|
||||||
|
return True
|
||||||
|
if len(text_properties.glyphs) == 0:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
for i, g in enumerate(text_properties.glyphs):
|
for i, g in enumerate(text_properties.glyphs):
|
||||||
|
@ -789,9 +1141,9 @@ def would_regenerate(text_properties):
|
||||||
elif g.glyph_object.type != "EMPTY":
|
elif g.glyph_object.type != "EMPTY":
|
||||||
return True
|
return True
|
||||||
# check if perhaps one glyph was deleted
|
# check if perhaps one glyph was deleted
|
||||||
elif type(g.glyph_object) == type(None):
|
elif g.glyph_object is None:
|
||||||
return True
|
return True
|
||||||
elif type(g.glyph_object.parent) == type(None):
|
elif g.glyph_object.parent is None:
|
||||||
return True
|
return True
|
||||||
elif g.glyph_object.parent.users_collection != g.glyph_object.users_collection:
|
elif g.glyph_object.parent.users_collection != g.glyph_object.users_collection:
|
||||||
return True
|
return True
|
||||||
|
@ -811,7 +1163,7 @@ def update_matrices(obj):
|
||||||
if obj.parent is None:
|
if obj.parent is None:
|
||||||
obj.matrix_world = obj.matrix_basis
|
obj.matrix_world = obj.matrix_basis
|
||||||
|
|
||||||
else:
|
# else:
|
||||||
obj.matrix_world = obj.parent.matrix_world * \
|
obj.matrix_world = obj.parent.matrix_world * \
|
||||||
obj.matrix_parent_inverse * \
|
obj.matrix_parent_inverse * \
|
||||||
obj.matrix_basis
|
obj.matrix_basis
|
||||||
|
@ -843,6 +1195,7 @@ def parent_to_curve(o, c):
|
||||||
p = cm.vertices[0].co
|
p = cm.vertices[0].co
|
||||||
o.matrix_parent_inverse.translation = p * -1.0
|
o.matrix_parent_inverse.translation = p * -1.0
|
||||||
|
|
||||||
|
|
||||||
def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4, can_regenerate=False):
|
def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4, can_regenerate=False):
|
||||||
"""set_text_on_curve
|
"""set_text_on_curve
|
||||||
|
|
||||||
|
@ -867,6 +1220,7 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4,
|
||||||
|
|
||||||
distribution_type = "CALCULATE" if is_bezier(mom) else "FOLLOW_PATH"
|
distribution_type = "CALCULATE" if is_bezier(mom) else "FOLLOW_PATH"
|
||||||
|
|
||||||
|
|
||||||
# NOTE: following not necessary anymore
|
# NOTE: following not necessary anymore
|
||||||
# as we fixed data_path with parent_to_curve trick
|
# as we fixed data_path with parent_to_curve trick
|
||||||
#
|
#
|
||||||
|
@ -883,20 +1237,11 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4,
|
||||||
|
|
||||||
# if we regenerate.... delete objects
|
# if we regenerate.... delete objects
|
||||||
if regenerate and text_properties.get("glyphs"):
|
if regenerate and text_properties.get("glyphs"):
|
||||||
for g in text_properties.glyphs:
|
|
||||||
print(dict(g))
|
|
||||||
glyph_objects = [g["glyph_object"] for g in text_properties["glyphs"]]
|
glyph_objects = [g["glyph_object"] for g in text_properties["glyphs"]]
|
||||||
completely_delete_objects(glyph_objects, True)
|
completely_delete_objects(glyph_objects, True)
|
||||||
text_properties.glyphs.clear()
|
text_properties.glyphs.clear()
|
||||||
|
|
||||||
mom[f"{utils.prefix()}_type"] = "textobject"
|
transfer_text_properties_to_text_object(text_properties, mom)
|
||||||
mom[f"{utils.prefix()}_linked_textobject"] = text_properties.text_id
|
|
||||||
mom[f"{utils.prefix()}_font_name"] = text_properties.font_name
|
|
||||||
mom[f"{utils.prefix()}_face_name"] = text_properties.face_name
|
|
||||||
mom[f"{utils.prefix()}_font_size"] = text_properties.font_size
|
|
||||||
mom[f"{utils.prefix()}_letter_spacing"] = text_properties.letter_spacing
|
|
||||||
mom[f"{utils.prefix()}_orientation"] = text_properties.orientation
|
|
||||||
mom[f"{utils.prefix()}_translation"] = text_properties.translation
|
|
||||||
|
|
||||||
curve_length = get_curve_length(mom)
|
curve_length = get_curve_length(mom)
|
||||||
advance = text_properties.offset
|
advance = text_properties.offset
|
||||||
|
@ -905,6 +1250,7 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4,
|
||||||
is_command = False
|
is_command = False
|
||||||
previous_spline_index = -1
|
previous_spline_index = -1
|
||||||
|
|
||||||
|
actual_text = ""
|
||||||
for i, c in enumerate(text_properties.text):
|
for i, c in enumerate(text_properties.text):
|
||||||
face = Font.fonts[text_properties.font_name].faces[text_properties.face_name]
|
face = Font.fonts[text_properties.font_name].faces[text_properties.face_name]
|
||||||
scalor = face.unit_factor * text_properties.font_size
|
scalor = face.unit_factor * text_properties.font_size
|
||||||
|
@ -974,6 +1320,7 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4,
|
||||||
glyph_properties["glyph_id"] = glyph_id
|
glyph_properties["glyph_id"] = glyph_id
|
||||||
glyph_properties["text_id"] = text_properties.text_id
|
glyph_properties["text_id"] = text_properties.text_id
|
||||||
glyph_properties["letter_spacing"] = 0
|
glyph_properties["letter_spacing"] = 0
|
||||||
|
actual_text += glyph_id
|
||||||
|
|
||||||
############### NODE SCENE MANAGEMENT
|
############### NODE SCENE MANAGEMENT
|
||||||
|
|
||||||
|
@ -982,16 +1329,11 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4,
|
||||||
if regenerate:
|
if regenerate:
|
||||||
outer_node = bpy.data.objects.new(f"{glyph_id}", None)
|
outer_node = bpy.data.objects.new(f"{glyph_id}", None)
|
||||||
inner_node = bpy.data.objects.new(f"{glyph_id}_mesh", glyph.data)
|
inner_node = bpy.data.objects.new(f"{glyph_id}_mesh", glyph.data)
|
||||||
outer_node[f"{utils.prefix()}_type"] = "glyph"
|
transfer_properties_to_glyph_object(text_properties, glyph_properties, outer_node)
|
||||||
outer_node[f"{utils.prefix()}_linked_textobject"] = text_properties.text_id
|
|
||||||
outer_node[f"{utils.prefix()}_glyph_index"] = glyph_index
|
|
||||||
outer_node[f"{utils.prefix()}_font_name"] = text_properties.font_name
|
|
||||||
outer_node[f"{utils.prefix()}_face_name"] = text_properties.face_name
|
|
||||||
|
|
||||||
# Add into the scene.
|
# Add into the scene.
|
||||||
mom.users_collection[0].objects.link(outer_node)
|
mom.users_collection[0].objects.link(outer_node)
|
||||||
mom.users_collection[0].objects.link(inner_node)
|
mom.users_collection[0].objects.link(inner_node)
|
||||||
# bpy.context.scene.collection.objects.link(inner_node)
|
|
||||||
|
|
||||||
# Parenting is hard.
|
# Parenting is hard.
|
||||||
inner_node.parent_type = 'OBJECT'
|
inner_node.parent_type = 'OBJECT'
|
||||||
|
@ -1001,6 +1343,7 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4,
|
||||||
outer_node.hide_set(True)
|
outer_node.hide_set(True)
|
||||||
|
|
||||||
glyph_properties["glyph_object"] = outer_node
|
glyph_properties["glyph_object"] = outer_node
|
||||||
|
outer_node[f"{utils.prefix()}_glyph_index"] = glyph_index
|
||||||
else:
|
else:
|
||||||
outer_node = glyph_properties.glyph_object
|
outer_node = glyph_properties.glyph_object
|
||||||
outer_node[f"{utils.prefix()}_glyph_index"] = glyph_index
|
outer_node[f"{utils.prefix()}_glyph_index"] = glyph_index
|
||||||
|
@ -1128,52 +1471,15 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4,
|
||||||
glyph_index += 1
|
glyph_index += 1
|
||||||
previous_spline_index = spline_index
|
previous_spline_index = spline_index
|
||||||
|
|
||||||
# NOTE: depsgraph update not locked
|
if regenerate:
|
||||||
# as we fixed data_path with parent_to_curve trick
|
text_properties["actual_text"] = actual_text
|
||||||
# if lock_depsgraph_update_n_times < 0:
|
|
||||||
# lock_depsgraph_update_n_times = len(
|
|
||||||
# bpy.context.selected_objects
|
|
||||||
# )
|
|
||||||
# else:
|
|
||||||
# lock_depsgraph_update_n_times += len(
|
|
||||||
# bpy.context.selected_objects
|
|
||||||
# )
|
|
||||||
# # NOTE: we reset with a timeout, as setting and resetting certain things
|
|
||||||
# # in fast succession will cause visual glitches (e.g. {}.data.use_path).
|
|
||||||
# def reset():
|
|
||||||
# mom.data.use_path = previous_use_path
|
|
||||||
# if counted_reset in bpy.app.handlers.depsgraph_update_post:
|
|
||||||
# bpy.app.handlers.depsgraph_update_post.remove(counted_reset)
|
|
||||||
# if bpy.app.timers.is_registered(reset):
|
|
||||||
# bpy.app.timers.unregister(reset)
|
|
||||||
# molotov = reset_depsgraph_n + 0
|
|
||||||
# def counted_reset(scene, depsgraph):
|
|
||||||
# nonlocal molotov
|
|
||||||
# if molotov == 0:
|
|
||||||
# reset()
|
|
||||||
# else:
|
|
||||||
# molotov -= 1
|
|
||||||
# # unregister previous resets to avoid multiple execution
|
|
||||||
# if bpy.app.timers.is_registered(reset):
|
|
||||||
# bpy.app.timers.unregister(reset)
|
|
||||||
# if counted_reset in bpy.app.handlers.depsgraph_update_post:
|
|
||||||
# bpy.app.handlers.depsgraph_update_post.remove(counted_reset)
|
|
||||||
# if not isinstance(reset_timeout_s, bool):
|
|
||||||
# if reset_timeout_s > 0:
|
|
||||||
# bpy.app.timers.register(reset, first_interval=reset_timeout_s)
|
|
||||||
# elif reset_timeout <= 0:
|
|
||||||
# reset()
|
|
||||||
# bpy.app.handlers.depsgraph_update_post.append(counted_reset)
|
|
||||||
|
|
||||||
# endtime = time.perf_counter_ns()
|
|
||||||
# elapsedtime = endtime - starttime
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
verification_object = {
|
verification_object = {
|
||||||
f"{utils.prefix()}_type": "textobject",
|
f"{utils.prefix()}_type": "textobject",
|
||||||
f"{utils.prefix()}_linked_textobject": 0,
|
f"{utils.prefix()}_text_id": 0,
|
||||||
f"{utils.prefix()}_font_name": "font_name",
|
f"{utils.prefix()}_font_name": "font_name",
|
||||||
f"{utils.prefix()}_face_name": "face_name",
|
f"{utils.prefix()}_face_name": "face_name",
|
||||||
f"{utils.prefix()}_font_size": 42,
|
f"{utils.prefix()}_font_size": 42,
|
||||||
|
@ -1187,28 +1493,6 @@ def verify_text_object(o):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def transfer_text_properties_to_text_object(text_properties, o):
|
|
||||||
o[f"{utils.prefix()}_linked_textobject"] = text_properties.text_id
|
|
||||||
o[f"{utils.prefix()}_font_name"] = text_properties.font_name
|
|
||||||
o[f"{utils.prefix()}_face_name"] = text_properties.face_name
|
|
||||||
o[f"{utils.prefix()}_font_size"] = text_properties.font_size
|
|
||||||
o[f"{utils.prefix()}_letter_spacing"] = text_properties.letter_spacing
|
|
||||||
o[f"{utils.prefix()}_orientation"] = text_properties.orientation
|
|
||||||
o[f"{utils.prefix()}_translation"] = text_properties.translation
|
|
||||||
o[f"{utils.prefix()}_text"] = text_properties["text"]
|
|
||||||
|
|
||||||
|
|
||||||
def transfer_text_object_to_text_properties(o, text_properties):
|
|
||||||
text_properties["text_id"] = o[f"{utils.prefix()}_linked_textobject"]
|
|
||||||
text_properties["font_name"] = o[f"{utils.prefix()}_font_name"]
|
|
||||||
text_properties["face_name"] = o[f"{utils.prefix()}_face_name"]
|
|
||||||
text_properties["font_size"] = o[f"{utils.prefix()}_font_size"]
|
|
||||||
text_properties["letter_spacing"] = o[f"{utils.prefix()}_letter_spacing"]
|
|
||||||
text_properties["orientation"] = o[f"{utils.prefix()}_orientation"]
|
|
||||||
text_properties["translation"] = o[f"{utils.prefix()}_translation"]
|
|
||||||
text_properties["text"] = o[f"{utils.prefix()}_text"]
|
|
||||||
|
|
||||||
|
|
||||||
# blender bound_box vertices
|
# blender bound_box vertices
|
||||||
#
|
#
|
||||||
# 3------7.
|
# 3------7.
|
||||||
|
@ -1686,3 +1970,4 @@ def align_origins_to_active_object(objects=None, axis=2):
|
||||||
# c.location -= mathutils.Vector((diff, 0.0, 0.0)) @ o.matrix_world.inverted()
|
# c.location -= mathutils.Vector((diff, 0.0, 0.0)) @ o.matrix_world.inverted()
|
||||||
|
|
||||||
# return ""
|
# return ""
|
||||||
|
|
||||||
|
|
|
@ -4,20 +4,20 @@ space 0020 0.25
|
||||||
nbspace 00A0 0.25
|
nbspace 00A0 0.25
|
||||||
# ethi:wordspace 1361 # NOTE: has shape
|
# ethi:wordspace 1361 # NOTE: has shape
|
||||||
enquad 2000 0.5
|
enquad 2000 0.5
|
||||||
emquad 2001 1
|
emquad 2001 1.0
|
||||||
enspace 2002 0.5
|
enspace 2002 0.5
|
||||||
emspace 2003 1
|
emspace 2003 1.0
|
||||||
threeperemspace 2004 3
|
threeperemspace 2004 3.0
|
||||||
fourperemspace 2005 4
|
fourperemspace 2005 4.0
|
||||||
sixperemspace 2006 6
|
sixperemspace 2006 6.0
|
||||||
figurespace 2007 1
|
figurespace 2007 1.0
|
||||||
punctuationspace 2008 1
|
punctuationspace 2008 1.0
|
||||||
thinspace 2009 0.1
|
thinspace 2009 0.1
|
||||||
hairspace 200A 0.05
|
hairspace 200A 0.05
|
||||||
zerowidthspace 200B 0
|
zerowidthspace 200B 0.0
|
||||||
narrownobreakspace 202F 0.1
|
narrownobreakspace 202F 0.1
|
||||||
mediummathematicalspace 205F 1
|
mediummathematicalspace 205F 1.0
|
||||||
cntr:space 2420 0.25
|
cntr:space 2420 0.25
|
||||||
ideographicspace 3000 1
|
ideographicspace 3000 1.0
|
||||||
# ideographichalffillspace 303F # NOTE: has shape
|
# ideographichalffillspace 303F # NOTE: has shape
|
||||||
zerowidthnobreakspace FEFF 0
|
zerowidthnobreakspace FEFF 0.0
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue