From 0bf80e01b28dd7b3c215c1222e9b45b6c8eaa8d6 Mon Sep 17 00:00:00 2001 From: themancalledjakob Date: Wed, 14 Aug 2024 13:39:47 +0200 Subject: [PATCH] load installed fonts, fix some minor loading issues --- __init__.py | 52 ++++++++++++++++++++++++++++++++++++------------- butils.py | 20 +++++++++++++------ common/utils.py | 17 +++++++++++++++- 3 files changed, 69 insertions(+), 20 deletions(-) diff --git a/__init__.py b/__init__.py index 355e866..c404b15 100644 --- a/__init__.py +++ b/__init__.py @@ -262,11 +262,16 @@ class ABC3D_PT_Panel(bpy.types.Panel): def draw(self, context): layout = self.layout - layout.label(text=f"{__name__} panel") + icon = 'NONE' + if len(context.scene.abc3d_data.available_fonts) == 0: + icon = 'ERROR' + layout.row().label(text='no fonts loaded yet') + + layout.operator(f"{__name__}.load_installed_fonts", text="load installed fonts", icon=icon) class ABC3D_PT_LoadFontPanel(bpy.types.Panel): - bl_label = "Load a new font" + bl_label = "Install a new font" bl_parent_id = "ABC3D_PT_Panel" bl_category = "ABC3D" bl_space_type = "VIEW_3D" @@ -281,9 +286,9 @@ class ABC3D_PT_LoadFontPanel(bpy.types.Panel): abc3d = scene.abc3d abc3d_data = scene.abc3d_data - layout.label(text="Load FontFile:") + layout.label(text="Install FontFile:") layout.row().prop(abc3d, "font_path") - layout.row().operator('abc3d.loadfont', text='Load Font') + layout.row().operator(f"{__name__}.loadfont", text='Load Font') class ABC3D_PT_FontList(bpy.types.Panel): @@ -497,13 +502,6 @@ class ABC3D_OT_LoadFont(bpy.types.Operator): def execute(self, context): scene = bpy.context.scene - butils.ShowMessageBox( - title=f"{__name__} Warning", - icon="ERROR", - message=f"We believe this functionality is currently not available.", - ) - return {'CANCELLED'} - if not os.path.exists(scene.abc3d.font_path): butils.ShowMessageBox( title=f"{__name__} Warning", @@ -516,6 +514,27 @@ class ABC3D_OT_LoadFont(bpy.types.Operator): return {'FINISHED'} +class ABC3D_OT_LoadInstalledFonts(bpy.types.Operator): + """Load installed fontfiles from datapath.""" + bl_idname = f"{__name__}.load_installed_fonts" + bl_label = "Loading installed Fonts." + bl_options = {'REGISTER', 'UNDO'} + + def draw(self, context): + layout = self.layout + layout.label(text="Loading font files can take a long time.") + + def invoke(self, context, event): + return context.window_manager.invoke_props_dialog(self) + + def execute(self, context): + scene = bpy.context.scene + + butils.load_installed_fonts() + butils.update_available_fonts() + + return {'FINISHED'} + class ABC3D_OT_AddDefaultMetrics(bpy.types.Operator): """Add default metrics to selected objects""" bl_idname = f"{__name__}.add_default_metrics" @@ -735,9 +754,12 @@ class ABC3D_OT_SaveFontToFile(bpy.types.Operator): for obj in fontcollection.objects: if obj["font_name"] == selected_font.font_name: if not butils.is_metrics_object(obj): - # butils.add_faces_to_metrics(obj) obj.select_set(True) export_objects.append(obj) + else: + obj.select_set(True) + butils.add_faces_to_metrics(obj) + export_objects.append(obj) context_override = bpy.context.copy() context_override["selected_objects"] = list(export_objects) @@ -1019,6 +1041,7 @@ classes = ( ABC3D_PT_TextManagement, ABC3D_PT_FontCreation, ABC3D_PT_TextPropertiesPanel, + ABC3D_OT_LoadInstalledFonts, ABC3D_OT_AddDefaultMetrics, ABC3D_OT_RemoveMetrics, ABC3D_OT_AlignMetricsToActiveObject, @@ -1038,6 +1061,7 @@ def load_handler(self, dummy): if not bpy.app.timers.is_registered(butils.execute_queued_functions): bpy.app.timers.register(butils.execute_queued_functions) butils.run_in_main_thread(butils.update_available_fonts) + # butils.run_in_main_thread(bpy.ops.abc3d.load_installed_fonts) def load_handler_unload(): if bpy.app.timers.is_registered(butils.execute_queued_functions): @@ -1071,9 +1095,11 @@ def register(): bpy.app.handlers.frame_change_post.append(on_frame_changed) butils.run_in_main_thread(butils.clear_available_fonts) - butils.run_in_main_thread(butils.load_available_fonts) + # butils.run_in_main_thread(butils.load_installed_fonts) butils.run_in_main_thread(butils.update_available_fonts) + # bpy.ops.abc3d.load_installed_fonts() + Font.name_to_glyph_d = Font.generate_name_to_glyph_d() def unregister(): diff --git a/butils.py b/butils.py index cbe2e26..8e31766 100644 --- a/butils.py +++ b/butils.py @@ -419,7 +419,7 @@ def load_font_from_filepath(filepath): glyph_id = o["glyph"] font_name = o["font_name"] face_name = o["face_name"] - ShowMessageBox("Loading Font", "INFO", f"adding glyph {glyph_id} for {font_name} {face_name}") + # ShowMessageBox("Loading Font", "INFO", f"adding glyph {glyph_id} for {font_name} {face_name}") print(f"adding glyph {glyph_id} for {font_name} {face_name}") glyph_obj = move_in_fontcollection( o, @@ -486,15 +486,13 @@ def getPreferences(context): def clear_available_fonts(): bpy.context.scene.abc3d_data.available_fonts.clear() -def load_available_fonts(): - +def load_installed_fonts(): preferences = getPreferences(bpy.context) - print(f"assets folder: {preferences.assets_dir}") font_dir = f"{preferences.assets_dir}/fonts" for file in os.listdir(font_dir): if file.endswith(".glb") or file.endswith(".gltf"): font_path = os.path.join(font_dir, file) - ShowMessageBox("Loading Font", "INFO", f"loading font from {font_path}") + # ShowMessageBox("Loading Font", "INFO", f"loading font from {font_path}") print(f"loading font from {font_path}") for f in bpy.context.scene.abc3d_data.available_fonts.values(): print(f"available font: {f.font_name} {f.face_name}") @@ -555,7 +553,7 @@ def is_mesh(o): return type(o.data) == bpy.types.Mesh def is_metrics_object(o): - return (re.match("[\w]*_metrics$", o.name) != None or re.match("[\w]*_metrics.[\d]{3}$", o.name) != None) and is_mesh(o) + return (re.match(".*_metrics$", o.name) != None or re.match(".*_metrics.[\d]{3}$", o.name) != None) and is_mesh(o) def is_glyph(o): try: @@ -757,6 +755,15 @@ def add_metrics_obj_from_bound_box(glyph, bound_box=None): obj["face_name"] = glyph["face_name"] obj["glyph"] = glyph["glyph"] obj["type"] = "metrics" + + # remove already existing metrics + remove_metrics = [] + for c in glyph.children: + if is_metrics_object(c): + remove_metrics.append(c) + if len(remove_metrics) > 0: + completely_delete_objects(remove_metrics) + col = glyph.users_collection[0] col.objects.link(obj) # bpy.context.view_layer.objects.active = obj @@ -784,6 +791,7 @@ def add_metrics_obj_from_bound_box(glyph, bound_box=None): def add_faces_to_metrics(obj): mesh = bpy.data.meshes.new(f"{obj.name}") # add the new mesh + print(f"add_faces_to_metrics for {obj.name}") bound_box = bound_box_as_array(obj.bound_box) verts = [bound_box[0], bound_box[1], diff --git a/common/utils.py b/common/utils.py index 9ebb409..17b5ae4 100644 --- a/common/utils.py +++ b/common/utils.py @@ -1,4 +1,3 @@ - import time import datetime from mathutils import ( @@ -19,6 +18,22 @@ def mapRange(in_value, in_min, in_max, out_min, out_max, clamp=False): return max(out_max, min(out_min, output)) else: return output +import warnings +import functools + +def deprecated(func): + """This is a decorator which can be used to mark functions + as deprecated. It will result in a warning being emitted + when the function is used.""" + @functools.wraps(func) + def new_func(*args, **kwargs): + warnings.simplefilter('always', DeprecationWarning) # turn off filter + warnings.warn("Call to deprecated function {}.".format(func.__name__), + category=DeprecationWarning, + stacklevel=2) + warnings.simplefilter('default', DeprecationWarning) # reset filter + return func(*args, **kwargs) + return new_func # # Evaluate a bezier curve for the parameter 0<=t<=1 along its length # def evaluateBezierPoint(p1, h1, h2, p2, t):