Compare commits

...

4 commits

Author SHA1 Message Date
themancalledjakob
f6b1649c71 smoother install font & depsgraph update
when we set a text, we don't want our manual depsgraph update, because
this would trigger another setting of the text, which would trigger the
manual depsgraph update, which would trigger another setting of the
text, which would trigger the manual depsgraph update, which will
eventually be too much.

So, we ignore the depsgraph update n-times, where "n = n-letters + 1".
worst side effect: might not update the text automatically in edge
cases.
2024-11-15 20:24:06 +01:00
themancalledjakob
b24d0dbca4 cross-platform acrobatics 2024-11-15 20:17:50 +01:00
themancalledjakob
0320a18002 bpy_to_abspath 2024-11-15 20:17:28 +01:00
themancalledjakob
cb40391e0d print to stderr 2024-11-15 20:16:59 +01:00
4 changed files with 71 additions and 50 deletions

View file

@ -326,31 +326,32 @@ class ABC3D_PT_Panel(bpy.types.Panel):
icon = 'ERROR' icon = 'ERROR'
layout.row().label(text='no fonts loaded yet') layout.row().label(text='no fonts loaded yet')
layout.operator(f"{__name__}.install_font", text='Install new font')
layout.operator(f"{__name__}.load_installed_fonts", layout.operator(f"{__name__}.load_installed_fonts",
text="load installed fonts", icon=icon) text="load installed fonts", icon=icon)
layout.operator(f"{__name__}.open_asset_directory", layout.operator(f"{__name__}.open_asset_directory",
text="open asset directory", icon='FILEBROWSER') text="open asset directory", icon='FILEBROWSER')
class ABC3D_PT_LoadFontPanel(bpy.types.Panel): # class ABC3D_PT_LoadFontPanel(bpy.types.Panel):
bl_label = "Install a new font" # bl_label = "Install a new font"
bl_parent_id = "ABC3D_PT_Panel" # bl_parent_id = "ABC3D_PT_Panel"
bl_category = "ABC3D" # bl_category = "ABC3D"
bl_space_type = "VIEW_3D" # bl_space_type = "VIEW_3D"
bl_region_type = "UI" # bl_region_type = "UI"
def draw(self, context): # def draw(self, context):
layout = self.layout # layout = self.layout
wm = context.window_manager # wm = context.window_manager
scene = context.scene # scene = context.scene
abc3d_data = scene.abc3d_data # abc3d_data = scene.abc3d_data
box = layout.box() # box = layout.box()
box.row().label(text="1. Select fontfile") # box.row().label(text="1. Select fontfile")
box.row().prop(context.scene.abc3d_data, "font_path") # box.row().prop(context.scene.abc3d_data, "font_path")
box.row().label(text="2. Install it:") # box.row().label(text="2. Install it:")
box.row().operator(f"{__name__}.install_font", text='Install new font') # box.row().operator(f"{__name__}.install_font", text='Install new font')
class ABC3D_PT_FontList(bpy.types.Panel): class ABC3D_PT_FontList(bpy.types.Panel):
@ -666,7 +667,7 @@ class ABC3D_OT_InstallFont(bpy.types.Operator):
description="Install a *.glb or *.gltf fontfile from disk", description="Install a *.glb or *.gltf fontfile from disk",
default="", default="",
maxlen=1024, maxlen=1024,
# update=font_path_update_callback, update=font_path_update_callback,
subtype="FILE_PATH") subtype="FILE_PATH")
install_in_assets: bpy.props.BoolProperty( install_in_assets: bpy.props.BoolProperty(
@ -682,7 +683,7 @@ class ABC3D_OT_InstallFont(bpy.types.Operator):
def draw(self, context): def draw(self, context):
abc3d_data = context.scene.abc3d_data abc3d_data = context.scene.abc3d_data
layout = self.layout layout = self.layout
# layout.row().prop(self, "font_path") # crashes on Mac OS? layout.row().prop(self, "font_path")
# layout.row().prop(abc3d_data, "font_path") # closes the stupid panel on Mac OS.. # layout.row().prop(abc3d_data, "font_path") # closes the stupid panel on Mac OS..
layout.row().prop(self, "install_in_assets") layout.row().prop(self, "install_in_assets")
if not self.install_in_assets and not self.load_into_memory: if not self.install_in_assets and not self.load_into_memory:
@ -698,30 +699,30 @@ class ABC3D_OT_InstallFont(bpy.types.Operator):
layout.label(text="load the font data on demand.") layout.label(text="load the font data on demand.")
def invoke(self, context, event): def invoke(self, context, event):
abc3d_data = context.scene.abc3d_data # self.font_path = butils.bpy_to_abspath(self.font_path)
self.font_path = abc3d_data.font_path # if not os.path.exists(self.font_path):
if not os.path.exists(self.font_path): # bpy.app.timers.register(lambda: butils.ShowMessageBox(
bpy.app.timers.register(lambda: butils.ShowMessageBox( # title=f"{__name__} Warning",
title=f"{__name__} Warning", # icon="ERROR",
icon="ERROR", # message=[
message=[ # f"We believe the font path ({self.font_path}) does not exist.",
f"We believe the font path ({self.font_path}) does not exist.", # f"Did you select your fontfile in the field above the 'Install new font'-button?",
f"Did you select your fontfile in the field above the 'Install new font'-button?", # ],
], # ), first_interval=0.1)
), first_interval=0.1)
return context.window_manager.invoke_props_dialog(self) return context.window_manager.invoke_props_dialog(self)
def execute(self, context): def execute(self, context):
scene = bpy.context.scene scene = bpy.context.scene
abc3d_data = context.scene.abc3d_data abc3d_data = context.scene.abc3d_data
if not os.path.exists(self.font_path): font_path = butils.bpy_to_abspath(self.font_path)
if not os.path.exists(font_path):
butils.ShowMessageBox( butils.ShowMessageBox(
title=f"{__name__} Warning", title=f"{__name__} Warning",
icon="ERROR", icon="ERROR",
message=[ message=[
f"Could not install font.", f"Could not install font.",
f"We believe the font path ({self.font_path}) does not exist.", f"We believe the font path ({font_path}) does not exist.",
f"If this is an error, please let us know.", f"If this is an error, please let us know.",
], ],
) )
@ -729,11 +730,11 @@ class ABC3D_OT_InstallFont(bpy.types.Operator):
if self.install_in_assets: if self.install_in_assets:
preferences = getPreferences(context) preferences = getPreferences(context)
filename = os.path.basename(self.font_path) filename = os.path.basename(font_path)
target = os.path.join(preferences.assets_dir, "fonts", filename) target = os.path.join(preferences.assets_dir, "fonts", filename)
import shutil import shutil
os.makedirs(os.path.dirname(target), exist_ok=True) os.makedirs(os.path.dirname(target), exist_ok=True)
shutil.copyfile(self.font_path, target) shutil.copyfile(font_path, target)
# def register_load(target, load=False): # def register_load(target, load=False):
# print(f"registering installed fonts") # print(f"registering installed fonts")
# bpy.app.timers.register(lambda: register_load(target, self.load_into_memory), first_interval=5) # bpy.app.timers.register(lambda: register_load(target, self.load_into_memory), first_interval=5)
@ -742,9 +743,9 @@ class ABC3D_OT_InstallFont(bpy.types.Operator):
butils.load_font_from_filepath(target) butils.load_font_from_filepath(target)
butils.update_available_fonts() butils.update_available_fonts()
else: else:
butils.register_font_from_filepath(self.font_path) butils.register_font_from_filepath(font_path)
if self.load_into_memory: if self.load_into_memory:
butils.load_font_from_filepath(self.font_path) butils.load_font_from_filepath(font_path)
return {'FINISHED'} return {'FINISHED'}
@ -1507,7 +1508,7 @@ classes = (
ABC3D_UL_fonts, ABC3D_UL_fonts,
ABC3D_UL_texts, ABC3D_UL_texts,
ABC3D_PT_Panel, ABC3D_PT_Panel,
ABC3D_PT_LoadFontPanel, # ABC3D_PT_LoadFontPanel,
ABC3D_PT_FontList, ABC3D_PT_FontList,
ABC3D_PT_TextPlacement, ABC3D_PT_TextPlacement,
ABC3D_PT_TextManagement, ABC3D_PT_TextManagement,
@ -1585,7 +1586,7 @@ def load_used_glyphs():
[f"Font {t.font_name} is there,", [f"Font {t.font_name} is there,",
f"but the FontFace {t.face_name} is missing,", f"but the FontFace {t.face_name} is missing,",
"Do you have it installed?"]) "Do you have it installed?"])
if len(a["maybe"]) > 0: elif len(a["maybe"]) > 0:
for fp in a["filepaths"]: for fp in a["filepaths"]:
butils.load_font_from_filepath(fp, a["maybe"]) butils.load_font_from_filepath(fp, a["maybe"])
@ -1610,20 +1611,25 @@ def on_frame_changed(self, dummy):
# TODO PERFORMANCE: only on demand # TODO PERFORMANCE: only on demand
butils.set_text_on_curve(t) butils.set_text_on_curve(t)
@persistent @persistent
def on_depsgraph_update(scene, depsgraph): def on_depsgraph_update(scene, depsgraph):
for u in depsgraph.updates: if not bpy.context.mode.startswith("EDIT"):
if f"{utils.prefix()}_linked_textobject" in u.id.keys() \ for u in depsgraph.updates:
and f"{utils.prefix()}_type" in u.id.keys() \ if f"{utils.prefix()}_linked_textobject" in u.id.keys() \
and u.id[f"{utils.prefix()}_type"] == 'textobject': and f"{utils.prefix()}_type" in u.id.keys() \
linked_textobject = u.id[f"{utils.prefix()}_linked_textobject"] and u.id[f"{utils.prefix()}_type"] == 'textobject':
if u.is_updated_geometry and len(scene.abc3d_data.available_texts) > linked_textobject and not "prevent_recursion" in u.id: linked_textobject = u.id[f"{utils.prefix()}_linked_textobject"]
u.id["prevent_recursion"] = True if u.is_updated_geometry and len(scene.abc3d_data.available_texts) > linked_textobject:
butils.set_text_on_curve( def later():
scene.abc3d_data.available_texts[linked_textobject]) if not "lock_depsgraph_update_ntimes" in scene.abc3d_data \
elif "prevent_recursion" in u.id.keys(): or scene.abc3d_data["lock_depsgraph_update_ntimes"] == 0:
del u.id["prevent_recursion"] print("******* not yet")
butils.set_text_on_curve(
scene.abc3d_data.available_texts[linked_textobject])
elif scene.abc3d_data["lock_depsgraph_update_ntimes"] > 0:
scene.abc3d_data['lock_depsgraph_update_ntimes'] -= 1
butils.run_in_main_thread(later)
def register(): def register():

View file

@ -424,7 +424,13 @@ class ImportGLTF2(Operator, ConvertGLTF2_Base, ImportHelper):
elapsed_s = "{:.2f}s".format(time.time() - start_time) elapsed_s = "{:.2f}s".format(time.time() - start_time)
print("font import gltf finished in " + elapsed_s) print("font import gltf finished in " + elapsed_s)
gltf.log.removeHandler(gltf.log_handler) # acrobatics to not break on MacOS
if hasattr(gltf, "log_handler"):
if hasattr(gltf.log, "removeHandler"):
gltf.log.removeHandler(gltf.log_handler)
elif hasattr(gltf.log, "logger"):
if hasattr(gltf.log.logger, "removeHandler"):
gltf.log.logger.removeHandler(gltf.log_handler)
return {'FINISHED'} return {'FINISHED'}

View file

@ -392,6 +392,9 @@ def move_in_fontcollection(obj, fontcollection, allow_duplicates=False):
return obj return obj
def bpy_to_abspath(blender_path):
return os.path.realpath(bpy.path.abspath(blender_path))
def register_font_from_filepath(filepath): def register_font_from_filepath(filepath):
from .bimport import get_font_faces_in_file from .bimport import get_font_faces_in_file
@ -857,6 +860,8 @@ def set_text_on_curve(text_properties, recursive=True):
mom[f"{utils.prefix()}_translation"] = text_properties.translation mom[f"{utils.prefix()}_translation"] = text_properties.translation
bpy.context.view_layer.objects.active = mom bpy.context.view_layer.objects.active = mom
bpy.ops.object.parent_set(type='OBJECT') bpy.ops.object.parent_set(type='OBJECT')
bpy.context.scene.abc3d_data["lock_depsgraph_update_ntimes"] = len(bpy.context.selected_objects)
mom["lock_depsgraph_update_ntimes"] = len(bpy.context.selected_objects)
# endtime = time.perf_counter_ns() # endtime = time.perf_counter_ns()
# elapsedtime = endtime - starttime # elapsedtime = endtime - starttime

View file

@ -68,6 +68,10 @@ def open_file_browser(directory):
# xdg-open *should* be supported by recent Gnome, KDE, Xfce # xdg-open *should* be supported by recent Gnome, KDE, Xfce
def printerr(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)
# # Evaluate a bezier curve for the parameter 0<=t<=1 along its length # # Evaluate a bezier curve for the parameter 0<=t<=1 along its length
# def evaluateBezierPoint(p1, h1, h2, p2, t): # def evaluateBezierPoint(p1, h1, h2, p2, t):
# return ((1 - t)**3) * p1 + (3 * t * (1 - t)**2) * h1 + (3 * (t**2) * (1 - t)) * h2 + (t**3) * p2 # return ((1 - t)**3) * p1 + (3 * t * (1 - t)**2) * h1 + (3 * (t**2) * (1 - t)) * h2 + (t**3) * p2