From 30251a635fe975b125565b971d395bde7aa89248 Mon Sep 17 00:00:00 2001 From: themancalledjakob Date: Tue, 5 Nov 2024 16:01:15 +0100 Subject: [PATCH] cosmetics --- __init__.py | 768 +++++++++++++++++++++++++++++----------------------- 1 file changed, 426 insertions(+), 342 deletions(-) diff --git a/__init__.py b/__init__.py index d66a828..c68b1f7 100644 --- a/__init__.py +++ b/__init__.py @@ -4,6 +4,14 @@ A 3D font helper """ +import os +from bpy.app.handlers import persistent +from bpy.types import Panel +import functools +import io +import bpy +import importlib + bl_info = { "name": "ABC3D", "author": "Jakob Schlötter, Studio Pointer*", @@ -18,10 +26,7 @@ bl_info = { # when registering # handy for development # first import dependencies for the method -import importlib - -# then import dependencies for our addon -if "bpy" in locals(): +if "Font" in locals(): importlib.reload(Font) importlib.reload(utils) importlib.reload(butils) @@ -34,20 +39,6 @@ else: from . import bimport from . import addon_updater_ops -import bpy -import math -import mathutils -import io -import functools -from bpy.types import Panel -from bpy.app.handlers import persistent -from random import uniform - -import time -import datetime - -import os -import re def getPreferences(context): preferences = context.preferences @@ -97,32 +88,32 @@ class ABC3D_addonPreferences(bpy.types.AddonPreferences): def get_default_assets_dir(): return bpy.utils.user_resource( - 'DATAFILES', - path=f"{__name__}", - create=True) + 'DATAFILES', + path=f"{__name__}", + create=True) def on_change_assets_dir(self, context): if not os.path.isdir(self.assets_dir): - butils.ShowMessageBox( - title=f"{__name__} Warning", - icon="ERROR", - message=("Chosen directory does not exist.", - "Please, reset to default, create it or chose another one.")) + butils.ShowMessageBox( + title=f"{__name__} Warning", + icon="ERROR", + message=("Chosen directory does not exist.", + "Please, reset to default, create it or chose another one.")) elif not os.access(self.assets_dir, os.W_OK): - butils.ShowMessageBox( - title=f"{__name__} Warning", - icon="ERROR", - message=("Chosen directory is not writable.", - "Please reset to default or chose another one.")) + butils.ShowMessageBox( + title=f"{__name__} Warning", + icon="ERROR", + message=("Chosen directory is not writable.", + "Please reset to default or chose another one.")) print(f"{__name__}: change assets_dir to {self.assets_dir}") assets_dir: bpy.props.StringProperty( - name="Assets Folder", - subtype='DIR_PATH', - default=get_default_assets_dir(), - update=on_change_assets_dir, - ) + name="Assets Folder", + subtype='DIR_PATH', + default=get_default_assets_dir(), + update=on_change_assets_dir, + ) def draw(self, context): layout = self.layout @@ -146,9 +137,9 @@ class ABC3D_glyph_properties(bpy.types.PropertyGroup): glyph_id: bpy.props.StringProperty(maxlen=1) glyph_object: bpy.props.PointerProperty(type=bpy.types.Object) letter_spacing: bpy.props.FloatProperty( - name="Letter Spacing", - description="Letter Spacing", - ) + name="Letter Spacing", + description="Letter Spacing", + ) class ABC3D_text_properties(bpy.types.PropertyGroup): @@ -163,17 +154,17 @@ class ABC3D_text_properties(bpy.types.PropertyGroup): d = context.scene.abc3d_data items = self.font_items_callback(context) if len(d.available_fonts) > 0: - if len(d.available_fonts) > d.active_text_index: - f = d.available_fonts[d.active_text_index] - return 0 #f"{f.font_name} {f.face_name}" - else: - f = d.available_fonts[0] - return 0 #f"{f.font_name} {f.face_name}" + if len(d.available_fonts) > d.active_text_index: + f = d.available_fonts[d.active_text_index] + return 0 # f"{f.font_name} {f.face_name}" + else: + f = d.available_fonts[0] + return 0 # f"{f.font_name} {f.face_name}" if type(self.font_name) != type(None) and type(self.face_name) != type(None): - return 0 #f"{self.font_name} {self.face_name}" + return 0 # f"{self.font_name} {self.face_name}" else: - return 0 #"" + return 0 # "" def glyphs_update_callback(self, context): butils.prepare_text(self.font_name, @@ -192,83 +183,89 @@ class ABC3D_text_properties(bpy.types.PropertyGroup): text_id: bpy.props.IntProperty() font: bpy.props.EnumProperty( - items=font_items_callback, - update=font_update_callback, - ) + items=font_items_callback, + update=font_update_callback, + ) font_name: bpy.props.StringProperty( - update=glyphs_update_callback - ) + update=glyphs_update_callback + ) face_name: bpy.props.StringProperty( - update=glyphs_update_callback - ) + update=glyphs_update_callback + ) text_object: bpy.props.PointerProperty(type=bpy.types.Object) text: bpy.props.StringProperty( - update=glyphs_update_callback - ) + update=glyphs_update_callback + ) letter_spacing: bpy.props.FloatProperty( - update=update_callback, - name="Letter Spacing", - description="Letter Spacing", - options={'ANIMATABLE'}, - step=0.01, - ) + update=update_callback, + name="Letter Spacing", + description="Letter Spacing", + options={'ANIMATABLE'}, + step=0.01, + ) orientation: bpy.props.FloatVectorProperty( - update=update_callback, - name="Orientation", - default=(1.5707963267948966, 0.0, 0.0), # 90 degrees in radians - subtype='EULER', - ) + update=update_callback, + name="Orientation", + default=(1.5707963267948966, 0.0, 0.0), # 90 degrees in radians + subtype='EULER', + ) translation: bpy.props.FloatVectorProperty( - update=update_callback, - name="Translation", - default=(0.0, 0.0, 0.0), - subtype='TRANSLATION', - ) + update=update_callback, + name="Translation", + default=(0.0, 0.0, 0.0), + subtype='TRANSLATION', + ) font_size: bpy.props.FloatProperty( - update=update_callback, - name="Font Size", - default=1.0, - subtype='NONE', - ) + update=update_callback, + name="Font Size", + default=1.0, + subtype='NONE', + ) offset: bpy.props.FloatProperty( - update=update_callback, - name="Offset", - default=0.0, - subtype='NONE', - ) + update=update_callback, + name="Offset", + default=0.0, + subtype='NONE', + ) compensate_curvature: bpy.props.BoolProperty( - update=update_callback, - name="Compensate Curvature", - description="Fixes curvature spacing issues for simple curves, don't use on curve with tiny loops.", - default=True, + update=update_callback, + name="Compensate Curvature", + description="Fixes curvature spacing issues for simple curves, don't use on curve with tiny loops.", + default=True, ) ignore_orientation: bpy.props.BoolProperty( - update=update_callback, - name="Ignore Curve Orientation", - default=False, + update=update_callback, + name="Ignore Curve Orientation", + default=False, ) distribution_type: bpy.props.StringProperty() glyphs: bpy.props.CollectionProperty(type=ABC3D_glyph_properties) -#TODO: simply, merge, cut cut cut +# TODO: simply, merge, cut cut cut + + class ABC3D_data(bpy.types.PropertyGroup): - available_fonts: bpy.props.CollectionProperty(type=ABC3D_available_font, name="Available fonts") + available_fonts: bpy.props.CollectionProperty( + type=ABC3D_available_font, name="Available fonts") + def active_font_index_update(self, context): if len(self.available_fonts) <= self.active_font_index: self.active_font_index = len(self.available_fonts) - 1 active_font_index: bpy.props.IntProperty( - default=-1, - update=active_font_index_update, - ) - available_texts: bpy.props.CollectionProperty(type=ABC3D_text_properties, name="Available texts") + default=-1, + update=active_font_index_update, + ) + available_texts: bpy.props.CollectionProperty( + type=ABC3D_text_properties, name="Available texts") + def active_text_index_update(self, context): if self.active_text_index != -1: o = self.available_texts[self.active_text_index].text_object # active_text_index changed. so let's update the selection # check if it is already selected # or perhaps one of the glyphs - if not o.select_get() and not len([ c for c in o.children if c.select_get() ]) > 0: + if not o.select_get() and not len([c for c in o.children if c.select_get()]) > 0: bpy.ops.object.select_all(action="DESELECT") o.select_set(True) bpy.context.view_layer.objects.active = o @@ -278,39 +275,43 @@ class ABC3D_data(bpy.types.PropertyGroup): active_text_index: bpy.props.IntProperty(update=active_text_index_update) # def font_path_update_callback(self, context): - # butils.ShowMessageBox("Friendly Reminder", message="do not forget to click on 'Install new font'") - # bpy.ops.abc3d.install_font() + # butils.ShowMessageBox("Friendly Reminder", message="do not forget to click on 'Install new font'") + # bpy.ops.abc3d.install_font() # stupid hack for Mac OS font_path: bpy.props.StringProperty( - name="Font path", - description="Install a *.glb or *.gltf fontfile from disk", - default="", - maxlen=1024, - # update=font_path_update_callback, - subtype="FILE_PATH") + name="Font path", + description="Install a *.glb or *.gltf fontfile from disk", + default="", + maxlen=1024, + # update=font_path_update_callback, + subtype="FILE_PATH") export_dir: bpy.props.StringProperty( - name="Export Directory", - description=f"The directory in which we will export fonts.\nIf it is blank, we will export to the addon assets path.\nThis is where the fonts are installed.", - subtype="DIR_PATH") + name="Export Directory", + description=f"The directory in which we will export fonts.\nIf it is blank, we will export to the addon assets path.\nThis is where the fonts are installed.", + subtype="DIR_PATH") class ABC3D_UL_fonts(bpy.types.UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): - layout.label(text=f"{index}: {item.font_name} {item.face_name}") # avoids renaming the item by accident + # avoids renaming the item by accident + layout.label(text=f"{index}: {item.font_name} {item.face_name}") def invoke(self, context, event): pass + class ABC3D_UL_texts(bpy.types.UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): split = layout.split(factor=0.3) split.label(text="Id: %d" % (item.text_id)) - split.label(text=f"{item.text}") # avoids renaming the item by accident + # avoids renaming the item by accident + split.label(text=f"{item.text}") def invoke(self, context, event): pass + class ABC3D_PT_Panel(bpy.types.Panel): bl_label = f"{__name__} panel" bl_category = "ABC3D" @@ -325,8 +326,10 @@ class ABC3D_PT_Panel(bpy.types.Panel): icon = 'ERROR' layout.row().label(text='no fonts loaded yet') - layout.operator(f"{__name__}.load_installed_fonts", text="load installed fonts", icon=icon) - layout.operator(f"{__name__}.open_asset_directory", text="open asset directory", icon='FILEBROWSER') + layout.operator(f"{__name__}.load_installed_fonts", + text="load installed fonts", icon=icon) + layout.operator(f"{__name__}.open_asset_directory", + text="open asset directory", icon='FILEBROWSER') class ABC3D_PT_LoadFontPanel(bpy.types.Panel): @@ -365,13 +368,16 @@ class ABC3D_PT_FontList(bpy.types.Panel): abc3d_data = scene.abc3d_data layout.label(text="Available Fonts") - layout.template_list("ABC3D_UL_fonts", "", abc3d_data, "available_fonts", abc3d_data, "active_font_index") + layout.template_list("ABC3D_UL_fonts", "", abc3d_data, + "available_fonts", abc3d_data, "active_font_index") if abc3d_data.active_font_index >= 0: available_font = abc3d_data.available_fonts[abc3d_data.active_font_index] font_name = available_font.font_name face_name = available_font.face_name - available_glyphs = sorted(Font.fonts[font_name].faces[face_name].glyphs_in_fontfile) - loaded_glyphs = sorted(Font.fonts[font_name].faces[face_name].loaded_glyphs) + available_glyphs = sorted( + Font.fonts[font_name].faces[face_name].glyphs_in_fontfile) + loaded_glyphs = sorted( + Font.fonts[font_name].faces[face_name].loaded_glyphs) box = layout.box() box.row().label(text=f"Font Name: {font_name}") box.row().label(text=f"Face Name: {face_name}") @@ -379,21 +385,27 @@ class ABC3D_PT_FontList(bpy.types.Panel): n_rows = int(len(available_glyphs) / n) box.row().label(text=f"Glyphs:") subbox = box.box() - for i in range(0, n_rows + 1): - text = ''.join([f"{u}" for ui, u in enumerate(available_glyphs) if ui < (i+1) * n and ui >= i * n]) + for i in range(0, n_rows + 1): + text = ''.join([f"{u}" for ui, u in enumerate( + available_glyphs) if ui < (i+1) * n and ui >= i * n]) scale_y = 0.5 - row = subbox.row(); row.scale_y = scale_y; row.alignment = 'CENTER' + row = subbox.row() + row.scale_y = scale_y + row.alignment = 'CENTER' row.label(text=text) n_rows = int(len(loaded_glyphs) / n) box.row().label(text=f"Loaded/Used Glyphs:") subbox = box.box() - for i in range(0, n_rows + 1): - text = ''.join([f"{u}" for ui, u in enumerate(loaded_glyphs) if ui < (i+1) * n and ui >= i * n]) + for i in range(0, n_rows + 1): + text = ''.join([f"{u}" for ui, u in enumerate( + loaded_glyphs) if ui < (i+1) * n and ui >= i * n]) scale_y = 0.5 - row = subbox.row(); row.scale_y = scale_y + row = subbox.row() + row.scale_y = scale_y row.label(text=text) row = layout.row() - oper = row.operator(f"{__name__}.load_font", text='Load all glyphs in memory') + oper = row.operator(f"{__name__}.load_font", + text='Load all glyphs in memory') oper.font_name = font_name oper.face_name = face_name @@ -429,6 +441,7 @@ class ABC3D_PT_TextPlacement(bpy.types.Panel): layout.label(text="Cannot place Text.") layout.label(text="Select a curve as active object.") + class ABC3D_PT_TextManagement(bpy.types.Panel): bl_label = "Text Management" bl_parent_id = "ABC3D_PT_Panel" @@ -443,6 +456,7 @@ class ABC3D_PT_TextManagement(bpy.types.Panel): scene = context.scene abc3d_data = scene.abc3d_data # TODO: update available_texts + def update(): if bpy.context.screen.is_animation_playing: return @@ -461,16 +475,17 @@ class ABC3D_PT_TextManagement(bpy.types.Panel): # these might be there in t.glyphs, but linked to removed objects # or they might be lost if type(next((g for g in t.glyphs if type(g.glyph_object) == type(None)), None)) == type(None): - g = next((g for g in t.glyphs if type(g.glyph_object) == type(None)), None) + g = next((g for g in t.glyphs if type( + g.glyph_object) == type(None)), None) # for g in t.glyphs: # if type(g) == type(None): - # print("IS NONE") + # print("IS NONE") # if type(g.glyph_object) == type(None): - # print("go IS NONE") + # print("go IS NONE") # else: - # if g.glyph_object == c: - # # print(g.glyph_object.name) - # pass + # if g.glyph_object == c: + # # print(g.glyph_object.name) + # pass if remove_me: remove_list.append(i) @@ -478,17 +493,18 @@ class ABC3D_PT_TextManagement(bpy.types.Panel): for i in remove_list: if type(abc3d_data.available_texts[i].text_object) != type(None): mom = abc3d_data.available_texts[i].text_object + def delif(o, p): if p in o: del o[p] - delif(mom,f"{utils.prefix()}_linked_textobject") - delif(mom,f"{utils.prefix()}_font_name") - delif(mom,f"{utils.prefix()}_face_name") - delif(mom,f"{utils.prefix()}_font_size") - delif(mom,f"{utils.prefix()}_letter_spacing") - delif(mom,f"{utils.prefix()}_orientation") - delif(mom,f"{utils.prefix()}_translation") - delif(mom,f"{utils.prefix()}_offset") + delif(mom, f"{utils.prefix()}_linked_textobject") + delif(mom, f"{utils.prefix()}_font_name") + delif(mom, f"{utils.prefix()}_face_name") + delif(mom, f"{utils.prefix()}_font_size") + delif(mom, f"{utils.prefix()}_letter_spacing") + delif(mom, f"{utils.prefix()}_orientation") + delif(mom, f"{utils.prefix()}_translation") + delif(mom, f"{utils.prefix()}_offset") abc3d_data.available_texts.remove(i) for i, t in enumerate(abc3d_data.available_texts): @@ -513,8 +529,11 @@ class ABC3D_PT_TextManagement(bpy.types.Panel): abc3d_data = scene.abc3d_data layout.label(text="Text Objects") - layout.template_list("ABC3D_UL_texts", "", abc3d_data, "available_texts", abc3d_data, "active_text_index") - layout.row().operator(f"{__name__}.remove_text", text="Remove Textobject") + layout.template_list("ABC3D_UL_texts", "", abc3d_data, + "available_texts", abc3d_data, "active_text_index") + layout.row().operator( + f"{__name__}.remove_text", text="Remove Textobject") + class ABC3D_PT_FontCreation(bpy.types.Panel): bl_label = "Font Creation" @@ -531,22 +550,29 @@ class ABC3D_PT_FontCreation(bpy.types.Panel): abc3d_data = scene.abc3d_data - layout.row().operator(f"{__name__}.create_font_from_objects", text='Create/Extend Font') + layout.row().operator( + f"{__name__}.create_font_from_objects", text='Create/Extend Font') box = layout.box() box.row().label(text="Exporting a fontfile") box.row().label(text="1. Select export directory:") box.prop(abc3d_data, 'export_dir') box.row().label(text="2. More options and export:") - box.row().operator(f"{__name__}.save_font_to_file", text='Export Font To File') - layout.row().operator(f"{__name__}.toggle_abc3d_collection", text='Toggle Collection') + box.row().operator(f"{__name__}.save_font_to_file", + text='Export Font To File') + layout.row().operator( + f"{__name__}.toggle_abc3d_collection", text='Toggle Collection') box = layout.box() box.label(text="metrics") - box.row().operator(f"{__name__}.add_default_metrics", text='Add Default Metrics') + box.row().operator( + f"{__name__}.add_default_metrics", text='Add Default Metrics') box.row().operator(f"{__name__}.remove_metrics", text='Remove Metrics') box.row().operator(f"{__name__}.align_metrics", text='Align Metrics') - box.row().operator(f"{__name__}.align_metrics_to_active_object", text='Align Metrics to Active Object') - layout.row().operator(f"{__name__}.temporaryhelper", text='Debug Function Do Not Use') + box.row().operator( + f"{__name__}.align_metrics_to_active_object", text='Align Metrics to Active Object') + layout.row().operator( + f"{__name__}.temporaryhelper", text='Debug Function Do Not Use') + class ABC3D_PT_TextPropertiesPanel(bpy.types.Panel): bl_label = "Text Properties" @@ -556,7 +582,8 @@ class ABC3D_PT_TextPropertiesPanel(bpy.types.Panel): bl_region_type = "UI" def get_active_text_properties(self): - if type(bpy.context.active_object) != type(None):# and bpy.context.object.select_get(): + # and bpy.context.object.select_get(): + if type(bpy.context.active_object) != type(None): for t in bpy.context.scene.abc3d_data.available_texts: if bpy.context.active_object == t.text_object: return t @@ -566,17 +593,17 @@ class ABC3D_PT_TextPropertiesPanel(bpy.types.Panel): # def font_items_callback(self, context): # items = [] - # fonts = Font.get_loaded_fonts_and_faces() + # fonts = Font.get_loaded_fonts_and_faces() # for f in fonts: - # items.append((f"{f[0]} {f[1]}", f"{f[0]} {f[1]}", "")) + # items.append((f"{f[0]} {f[1]}", f"{f[0]} {f[1]}", "")) # return items # def font_default_callback(self, context): # t = self.get_active_text_properties(self) # if type(t) != type(None): - # return f"{t.font_name} {t.face_name}" + # return f"{t.font_name} {t.face_name}" # else: - # return None + # return None # def font_update_callback(self, context): # font_name, face_name = self.font.split(" ") @@ -586,13 +613,13 @@ class ABC3D_PT_TextPropertiesPanel(bpy.types.Panel): # butils.set_text_on_curve(t) # font: bpy.props.EnumProperty( - # items=font_items_callback, - # default=font_default_callback, - # update=font_update_callback, - # ) + # items=font_items_callback, + # default=font_default_callback, + # update=font_update_callback, + # ) @classmethod - def poll(self,context): + def poll(self, context): return type(self.get_active_text_properties(self)) != type(None) def draw(self, context): @@ -608,7 +635,7 @@ class ABC3D_PT_TextPropertiesPanel(bpy.types.Panel): # as then polling does not work # however, we are paranoid return - + layout.label(text=f"Mom: {props.text_object.name}") layout.row().prop(props, "font") layout.row().prop(props, "text") @@ -620,6 +647,7 @@ class ABC3D_PT_TextPropertiesPanel(bpy.types.Panel): layout.column().prop(props, "translation") layout.column().prop(props, "orientation") + class ABC3D_OT_InstallFont(bpy.types.Operator): """Install or load Fontfile from path above. (Format must be *.glb or *.gltf)""" @@ -634,18 +662,18 @@ class ABC3D_OT_InstallFont(bpy.types.Operator): print(f"{self.font_path} does not exist") font_path: bpy.props.StringProperty( - name="Font path", - description="Install a *.glb or *.gltf fontfile from disk", - default="", - maxlen=1024, - # update=font_path_update_callback, - subtype="FILE_PATH") + name="Font path", + description="Install a *.glb or *.gltf fontfile from disk", + default="", + maxlen=1024, + # update=font_path_update_callback, + subtype="FILE_PATH") install_in_assets: bpy.props.BoolProperty( - name="install in assets", - description="install the font in the assets directory of the addon", - default=True, - ) + name="install in assets", + description="install the font in the assets directory of the addon", + default=True, + ) load_into_memory: bpy.props.BoolProperty(name="load font data into memory", description="if false, it will load font data on demand", @@ -659,7 +687,8 @@ class ABC3D_OT_InstallFont(bpy.types.Operator): layout.row().prop(self, "install_in_assets") if not self.install_in_assets and not self.load_into_memory: layout.label(text="If the fontfile is not installed,") - layout.label(text="and the font is not loaded in memory completely,") + layout.label( + text="and the font is not loaded in memory completely,") layout.label(text="the fontfile should not be moved.") layout.row().prop(self, "load_into_memory") if self.load_into_memory: @@ -678,8 +707,8 @@ class ABC3D_OT_InstallFont(bpy.types.Operator): message=[ 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?", - ], - ), first_interval=0.1) + ], + ), first_interval=0.1) return context.window_manager.invoke_props_dialog(self) def execute(self, context): @@ -694,11 +723,11 @@ class ABC3D_OT_InstallFont(bpy.types.Operator): f"Could not install font.", f"We believe the font path ({self.font_path}) does not exist.", f"If this is an error, please let us know.", - ], - ) + ], + ) return {'CANCELLED'} - if self.install_in_assets: + if self.install_in_assets: preferences = getPreferences(context) filename = os.path.basename(self.font_path) target = os.path.join(preferences.assets_dir, "fonts", filename) @@ -706,19 +735,20 @@ class ABC3D_OT_InstallFont(bpy.types.Operator): os.makedirs(os.path.dirname(target), exist_ok=True) shutil.copyfile(self.font_path, target) # 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) butils.register_font_from_filepath(target) if self.load_into_memory: butils.load_font_from_filepath(target) butils.update_available_fonts() - else: + else: butils.register_font_from_filepath(self.font_path) if self.load_into_memory: butils.load_font_from_filepath(self.font_path) return {'FINISHED'} + class ABC3D_OT_OpenAssetDirectory(bpy.types.Operator): """Open Asset Directory""" bl_idname = f"{__name__}.open_asset_directory" @@ -733,11 +763,11 @@ class ABC3D_OT_OpenAssetDirectory(bpy.types.Operator): return {'FINISHED'} else: butils.ShowMessageBox( - title=f"{__name__} Warning", - icon="ERROR", - message=("Asset directory does not exist.", - f"Command failed trying to access '{directory}'.", - "Please, make sure it exists or chose another directory.")) + title=f"{__name__} Warning", + icon="ERROR", + message=("Asset directory does not exist.", + f"Command failed trying to access '{directory}'.", + "Please, make sure it exists or chose another directory.")) return {'CANCELLED'} @@ -781,6 +811,7 @@ class ABC3D_OT_LoadInstalledFonts(bpy.types.Operator): return {'FINISHED'} + class ABC3D_OT_LoadFont(bpy.types.Operator): """Load all glyphs from a specific font in memory.\nThis can take a while and slow down Blender.""" bl_idname = f"{__name__}.load_font" @@ -796,6 +827,7 @@ class ABC3D_OT_LoadFont(bpy.types.Operator): butils.load_font_from_filepath(f) return {'FINISHED'} + class ABC3D_OT_AddDefaultMetrics(bpy.types.Operator): """Add default metrics to selected objects""" bl_idname = f"{__name__}.add_default_metrics" @@ -807,6 +839,7 @@ class ABC3D_OT_AddDefaultMetrics(bpy.types.Operator): butils.add_default_metrics_to_objects(objects) return {'FINISHED'} + class ABC3D_OT_RemoveMetrics(bpy.types.Operator): """Remove metrics from selected objects""" bl_idname = f"{__name__}.remove_metrics" @@ -818,6 +851,7 @@ class ABC3D_OT_RemoveMetrics(bpy.types.Operator): butils.remove_metrics_from_objects(objects) return {'FINISHED'} + class ABC3D_OT_AlignMetricsToActiveObject(bpy.types.Operator): """Align metrics of selected objects to metrics of active object""" bl_idname = f"{__name__}.align_metrics_to_active_object" @@ -829,6 +863,7 @@ class ABC3D_OT_AlignMetricsToActiveObject(bpy.types.Operator): butils.align_metrics_of_objects_to_active_object(objects) return {'FINISHED'} + class ABC3D_OT_AlignMetrics(bpy.types.Operator): """Align metrics of selected objects to each other""" bl_idname = f"{__name__}.align_metrics" @@ -840,6 +875,7 @@ class ABC3D_OT_AlignMetrics(bpy.types.Operator): butils.align_metrics_of_objects(objects) return {'FINISHED'} + class ABC3D_OT_TemporaryHelper(bpy.types.Operator): """Temporary Helper ABC3D\nThis could do anything.\nIt's just there to make random functions available for testing.""" bl_idname = f"{__name__}.temporaryhelper" @@ -853,20 +889,21 @@ class ABC3D_OT_TemporaryHelper(bpy.types.Operator): # butils.load_font_from_filepath("/home/jrkb/.config/blender/4.1/datafiles/abc3d/fonts/NM_Origin.glb") butils.update_available_fonts() - + # objects = bpy.context.selected_objects # butils.add_default_metrics_to_objects(objects) # reference_bound_box = None # for o in objects: - # bb = o.bound_box - # reference_bound_box = butils.get_max_bound_box(bb, reference_bound_box) + # bb = o.bound_box + # reference_bound_box = butils.get_max_bound_box(bb, reference_bound_box) # for o in objects: - # metrics = butils.get_metrics_bound_box(o.bound_box, reference_bound_box) - # butils.add_metrics_obj_from_bound_box(o, metrics) + # metrics = butils.get_metrics_bound_box(o.bound_box, reference_bound_box) + # butils.add_metrics_obj_from_bound_box(o, metrics) # bpy.app.timers.register(lambda: butils.remove_metrics_from_objects(objects), first_interval=5) return {'FINISHED'} + class ABC3D_OT_RemoveText(bpy.types.Operator): """Remove Text 3D""" bl_idname = f"{__name__}.remove_text" @@ -874,9 +911,9 @@ class ABC3D_OT_RemoveText(bpy.types.Operator): bl_options = {'REGISTER', 'UNDO'} remove_objects: bpy.props.BoolProperty( - name="Remove Objects", - description="Remove both ABC3D text functionality and the objects/meshes", - default=True) + name="Remove Objects", + description="Remove both ABC3D text functionality and the objects/meshes", + default=True) def invoke(self, context, event): wm = context.window_manager @@ -886,25 +923,26 @@ class ABC3D_OT_RemoveText(bpy.types.Operator): abc3d_data = context.scene.abc3d_data if abc3d_data.active_text_index < 0: butils.ShowMessageBox( - title="No text selected", - message=("Please select a text."), - icon='GHOST_ENABLED') + title="No text selected", + message=("Please select a text."), + icon='GHOST_ENABLED') return {'CANCELLED'} i = abc3d_data.active_text_index if type(abc3d_data.available_texts[i].text_object) != type(None): mom = abc3d_data.available_texts[i].text_object + def delif(o, p): if p in o: del o[p] - delif(mom,f"{utils.prefix()}_linked_textobject") - delif(mom,f"{utils.prefix()}_font_name") - delif(mom,f"{utils.prefix()}_face_name") - delif(mom,f"{utils.prefix()}_font_size") - delif(mom,f"{utils.prefix()}_letter_spacing") - delif(mom,f"{utils.prefix()}_orientation") - delif(mom,f"{utils.prefix()}_translation") - delif(mom,f"{utils.prefix()}_offset") + delif(mom, f"{utils.prefix()}_linked_textobject") + delif(mom, f"{utils.prefix()}_font_name") + delif(mom, f"{utils.prefix()}_face_name") + delif(mom, f"{utils.prefix()}_font_size") + delif(mom, f"{utils.prefix()}_letter_spacing") + delif(mom, f"{utils.prefix()}_orientation") + delif(mom, f"{utils.prefix()}_translation") + delif(mom, f"{utils.prefix()}_offset") if self.remove_objects: remove_list = [] for g in abc3d_data.available_texts[i].glyphs: @@ -925,7 +963,7 @@ class ABC3D_OT_PlaceText(bpy.types.Operator): def font_items_callback(self, context): items = [] - fonts = Font.get_loaded_fonts_and_faces() + fonts = Font.get_loaded_fonts_and_faces() for f in fonts: items.append((f"{f[0]} {f[1]}", f"{f[0]} {f[1]}", "")) return items @@ -936,50 +974,50 @@ class ABC3D_OT_PlaceText(bpy.types.Operator): self.face_name = face_name font_name: bpy.props.StringProperty( - options={'HIDDEN'} - ) + options={'HIDDEN'} + ) face_name: bpy.props.StringProperty( - options={'HIDDEN'} - ) + options={'HIDDEN'} + ) font: bpy.props.EnumProperty(items=font_items_callback, update=font_update_callback ) text: bpy.props.StringProperty( - name="Text", - description="The text.", - default="ABC3D", - maxlen=1024, - ) + name="Text", + description="The text.", + default="ABC3D", + maxlen=1024, + ) # target_object: bpy.props.PointerProperty( - # name="The Target Object", - # description="The target, which will be populated by character children of text.", - # type=bpy.types.Object, - # ) + # name="The Target Object", + # description="The target, which will be populated by character children of text.", + # type=bpy.types.Object, + # ) letter_spacing: bpy.props.FloatProperty( - name="Letter Spacing", - description="Letter Spacing", - default=0.0, - ) + name="Letter Spacing", + description="Letter Spacing", + default=0.0, + ) font_size: bpy.props.FloatProperty( - name="Font Size", - default=1.0, - subtype='NONE', - ) + name="Font Size", + default=1.0, + subtype='NONE', + ) offset: bpy.props.FloatProperty( - name="Offset", - default=0.0, - subtype='NONE', - ) + name="Offset", + default=0.0, + subtype='NONE', + ) translation: bpy.props.FloatVectorProperty( - name="Translation", - default=(0.0, 0.0, 0.0), - subtype='TRANSLATION', - ) + name="Translation", + default=(0.0, 0.0, 0.0), + subtype='TRANSLATION', + ) orientation: bpy.props.FloatVectorProperty( - name="Orientation", - default=(1.5707963267948966, 0.0, 0.0), # 90 degrees in radians - subtype='EULER', - ) + name="Orientation", + default=(1.5707963267948966, 0.0, 0.0), # 90 degrees in radians + subtype='EULER', + ) def invoke(self, context, event): wm = context.window_manager @@ -1007,7 +1045,7 @@ class ABC3D_OT_PlaceText(bpy.types.Operator): text_id = text_id + 1 t = abc3d_data.available_texts.add() # If you wish to set a value and not fire an update, set the id property. - # A property defined via bpy.props for example ob.prop is stored as ob["prop"] once set to non default. + # A property defined via bpy.props for example ob.prop is stored as ob["prop"] once set to non default. t['text_id'] = text_id # t['font'] = self.font # enums want to be set as attribute t['font_name'] = self.font_name @@ -1020,26 +1058,27 @@ class ABC3D_OT_PlaceText(bpy.types.Operator): t['translation'] = self.translation t['orientation'] = self.orientation t['distribution_type'] = distribution_type - t.font = self.font # enums want to be set as attribute - # this also calls the update function - # so we don't need to prepare/set again + t.font = self.font # enums want to be set as attribute + # this also calls the update function + # so we don't need to prepare/set again # no need for these: # butils.prepare_text(t.font_name, - # t.face_name, - # t.text) + # t.face_name, + # t.text) # or this: # butils.set_text_on_curve(t) # else: butils.ShowMessageBox( - title="No object selected", - message=( - "Please select an object.", - "It will be used to put the type on.", - "Thank you :)"), - icon='GHOST_ENABLED') + title="No object selected", + message=( + "Please select an object.", + "It will be used to put the type on.", + "Thank you :)"), + icon='GHOST_ENABLED') return {'FINISHED'} + class ABC3D_OT_ToggleABC3DCollection(bpy.types.Operator): """Toggle ABC3D Collection""" bl_idname = f"{__name__}.toggle_abc3d_collection" @@ -1051,7 +1090,8 @@ class ABC3D_OT_ToggleABC3DCollection(bpy.types.Operator): fontcollection = bpy.data.collections.get("ABC3D") if fontcollection is None: - self.report({'INFO'}, f"{bl_info['name']}: There is no collection. Did you use or create any glyphs yet?") + self.report( + {'INFO'}, f"{bl_info['name']}: There is no collection. Did you use or create any glyphs yet?") elif scene.collection.children.find(fontcollection.name) < 0: scene.collection.children.link(fontcollection) self.report({'INFO'}, f"{bl_info['name']}: show collection") @@ -1073,27 +1113,32 @@ class ABC3D_OT_SaveFontToFile(bpy.types.Operator): preferences = getPreferences(context) abc3d_data = context.scene.abc3d_data if abc3d_data.export_dir == "": - abc3d_data.export_dir = os.path.join(preferences.assets_dir, "fonts") + abc3d_data.export_dir = os.path.join( + preferences.assets_dir, "fonts") return wm.invoke_props_dialog(self) def draw(self, context): abc3d_data = context.scene.abc3d_data layout = self.layout layout.label(text="Available Fonts") - layout.template_list("ABC3D_UL_fonts", "", abc3d_data, "available_fonts", abc3d_data, "active_font_index") + layout.template_list("ABC3D_UL_fonts", "", abc3d_data, + "available_fonts", abc3d_data, "active_font_index") available_font = abc3d_data.available_fonts[abc3d_data.active_font_index] font_name = available_font.font_name face_name = available_font.face_name - loaded_glyphs = sorted(Font.fonts[font_name].faces[face_name].loaded_glyphs) + loaded_glyphs = sorted( + Font.fonts[font_name].faces[face_name].loaded_glyphs) n = 16 n_rows = int(len(loaded_glyphs) / n) box = layout.box() box.row().label(text=f"Glyphs to be exported:") subbox = box.box() - for i in range(0, n_rows + 1): - text = ''.join([f"{u}" for ui, u in enumerate(loaded_glyphs) if ui < (i+1) * n and ui >= i * n]) + for i in range(0, n_rows + 1): + text = ''.join([f"{u}" for ui, u in enumerate( + loaded_glyphs) if ui < (i+1) * n and ui >= i * n]) scale_y = 0.5 - row = subbox.row(); row.scale_y = scale_y + row = subbox.row() + row.scale_y = scale_y row.label(text=text) layout.prop(abc3d_data, 'export_dir') @@ -1110,15 +1155,18 @@ class ABC3D_OT_SaveFontToFile(bpy.types.Operator): return {'CANCELLED'} if abc3d_data.active_font_index < 0: - self.report({'INFO'}, f"{bl_info['name']}: There is no active font") + self.report( + {'INFO'}, f"{bl_info['name']}: There is no active font") return {'CANCELLED'} if len(abc3d_data.available_fonts) <= abc3d_data.active_font_index: - self.report({'INFO'}, f"{bl_info['name']}: Active font is not available") + self.report( + {'INFO'}, f"{bl_info['name']}: Active font is not available") return {'CANCELLED'} # save state to restore later - was_fontcollection_linked = scene.collection.children.find(fontcollection.name) >= 0 + was_fontcollection_linked = scene.collection.children.find( + fontcollection.name) >= 0 was_selection = [] for obj in bpy.context.selected_objects: was_selection.append(obj) @@ -1130,7 +1178,8 @@ class ABC3D_OT_SaveFontToFile(bpy.types.Operator): selected_font = abc3d_data.available_fonts[abc3d_data.active_font_index] # print(selected_font.font_name) - self.report({'INFO'}, f"{bl_info['name']}: {selected_font.font_name} {selected_font.face_name}") + self.report( + {'INFO'}, f"{bl_info['name']}: {selected_font.font_name} {selected_font.face_name}") preferences = getPreferences(context) print(f"assets folder: {preferences.assets_dir}") @@ -1169,12 +1218,14 @@ class ABC3D_OT_SaveFontToFile(bpy.types.Operator): bpy.ops.export_scene.gltf( filepath=filepath, check_existing=False, - export_format='GLB', # GLB or GLTF_SEPARATE (also change filepath) + # GLB or GLTF_SEPARATE (also change filepath) + export_format='GLB', export_extras=True, use_selection=True, use_active_scene=True, ) - bpy.app.timers.register(lambda: bpy.ops.scene.delete(), first_interval=1) + bpy.app.timers.register( + lambda: bpy.ops.scene.delete(), first_interval=1) # bpy.ops.scene.delete() # restore() @@ -1200,20 +1251,20 @@ class ABC3D_OT_CreateFontFromObjects(bpy.types.Operator): bl_options = {'REGISTER', 'UNDO'} font_name: bpy.props.StringProperty( - default="NM_Origin", - ) + default="NM_Origin", + ) face_name: bpy.props.StringProperty( - default="Tender", - ) + default="Tender", + ) import_infix: bpy.props.StringProperty( - default="_NM_Origin_Tender", - ) + default="_NM_Origin_Tender", + ) autodetect_names: bpy.props.BoolProperty( - default=True, - ) + default=True, + ) fix_common_misspellings: bpy.props.BoolProperty( - default=True, - ) + default=True, + ) def invoke(self, context, event): wm = context.window_manager @@ -1229,29 +1280,42 @@ class ABC3D_OT_CreateFontFromObjects(bpy.types.Operator): row.prop(self, 'autodetect_names') if self.autodetect_names: scale_y = 0.5 - row = layout.row(); row.scale_y = scale_y - row.label(text="Watch out, follow convention in naming your meshes:") - row = layout.row(); row.scale_y = scale_y + row = layout.row() + row.scale_y = scale_y + row.label( + text="Watch out, follow convention in naming your meshes:") + row = layout.row() + row.scale_y = scale_y row.label(text="'__'") - row = layout.row(); row.scale_y = scale_y + row = layout.row() + row.scale_y = scale_y row.label(text=" - glyph id: unicode glyph name or raw glyph") - row = layout.row(); row.scale_y = scale_y + row = layout.row() + row.scale_y = scale_y row.label(text=" - font name: font name with underscore") - row = layout.row(); row.scale_y = scale_y + row = layout.row() + row.scale_y = scale_y row.label(text=" - face name: face name") - row = layout.row(); row.scale_y = scale_y + row = layout.row() + row.scale_y = scale_y row.label(text="working examples:") - row = layout.row(); row.scale_y = scale_y + row = layout.row() + row.scale_y = scale_y row.label(text="- 'A_NM_Origin_Tender'") - row = layout.row(); row.scale_y = scale_y + row = layout.row() + row.scale_y = scale_y row.label(text="- 'B_NM_Origin_Tender'") - row = layout.row(); row.scale_y = scale_y + row = layout.row() + row.scale_y = scale_y row.label(text="- 'arrowright_NM_Origin_Tender'") - row = layout.row(); row.scale_y = scale_y + row = layout.row() + row.scale_y = scale_y row.label(text="- '→_NM_Origin_Tender' (equal to above)") - row = layout.row(); row.scale_y = scale_y + row = layout.row() + row.scale_y = scale_y row.label(text="- 'quotesingle_NM_Origin_Tender.001'") - row = layout.row(); row.scale_y = scale_y + row = layout.row() + row.scale_y = scale_y row.label(text="- 'colon_NM_Origin_Tender_2'") box = layout.box() box.enabled = not self.autodetect_names @@ -1264,8 +1328,10 @@ class ABC3D_OT_CreateFontFromObjects(bpy.types.Operator): character = "" if Font.known_misspellings[k] in Font.name_to_glyph_d: character = f" ({Font.name_to_glyph_d[Font.known_misspellings[k]]})" - row = layout.row(); row.scale_y = 0.5 - row.label(text=f"{k} → {Font.known_misspellings[k]}{character}") + row = layout.row() + row.scale_y = 0.5 + row.label( + text=f"{k} → {Font.known_misspellings[k]}{character}") def execute(self, context): print(f"executing {self.bl_idname}") @@ -1300,7 +1366,8 @@ class ABC3D_OT_CreateFontFromObjects(bpy.types.Operator): if self.autodetect_names: ifxsplit = o.name.split('_') if len(ifxsplit) < 4: - print(f"whoops name could not be autodetected {o.name}") + print( + f"whoops name could not be autodetected {o.name}") continue font_name = f"{ifxsplit[1]}_{ifxsplit[2]}" face_name = ifxsplit[3] @@ -1314,25 +1381,25 @@ class ABC3D_OT_CreateFontFromObjects(bpy.types.Operator): name = o.name.split('_')[0] glyph_id = Font.name_to_glyph(name) - if type(glyph_id )!= type(None): + if type(glyph_id) != type(None): o["glyph"] = glyph_id o["font_name"] = font_name o["face_name"] = face_name # butils.apply_all_transforms(o) butils.move_in_fontcollection( - o, - fontcollection) + o, + fontcollection) Font.add_glyph( - font_name, - face_name, - glyph_id, - o) + font_name, + face_name, + glyph_id, + o) - #TODO: is there a better way to iterate over a CollectionProperty? + # TODO: is there a better way to iterate over a CollectionProperty? found = False for f in abc3d_data.available_fonts.values(): if (f.font_name == font_name - and f.face_name == face_name): + and f.face_name == face_name): found = True break if not found: @@ -1341,11 +1408,14 @@ class ABC3D_OT_CreateFontFromObjects(bpy.types.Operator): f.face_name = face_name else: - print(f"import warning: did not understand glyph {name}") - self.report({'INFO'}, f"did not understand glyph {name}") + print( + f"import warning: did not understand glyph {name}") + self.report( + {'INFO'}, f"did not understand glyph {name}") return {'FINISHED'} + class ABC3D_PT_RightPropertiesPanel(bpy.types.Panel): """Creates a Panel in the Object properties window""" bl_label = f"{bl_info['name']}" @@ -1355,10 +1425,12 @@ class ABC3D_PT_RightPropertiesPanel(bpy.types.Panel): bl_context = "object" @classmethod - def poll(self,context): + def poll(self, context): # only show the panel, if it's a textobject or a glyph - is_text = type(next((t for t in context.scene.abc3d_data.available_texts if t.text_object == context.active_object), None)) != type(None) - is_glyph = type(next((t for t in context.scene.abc3d_data.available_texts if t.text_object == context.active_object.parent), None)) != type(None) + is_text = type(next((t for t in context.scene.abc3d_data.available_texts if t.text_object == + context.active_object), None)) != type(None) + is_glyph = type(next((t for t in context.scene.abc3d_data.available_texts if t.text_object == + context.active_object.parent), None)) != type(None) return is_text or is_glyph def draw(self, context): @@ -1370,6 +1442,7 @@ class ABC3D_PT_RightPropertiesPanel(bpy.types.Panel): def is_it_text(): return type(next((t for t in context.scene.abc3d_data.available_texts if t.text_object == context.active_object), None)) != type(None) + def is_it_glyph(): return type(next((t for t in context.scene.abc3d_data.available_texts if t.text_object == context.active_object.parent), None)) != type(None) @@ -1401,60 +1474,63 @@ class ABC3D_PT_RightPropertiesPanel(bpy.types.Panel): if is_glyph: layout.row().label(text="Glyph Properties:") + class ABC3D_OT_Reporter(bpy.types.Operator): bl_idname = f"{__name__}.reporter" bl_label = "Report" label = bpy.props.StringProperty( - name="label", - default="INFO", - ) + name="label", + default="INFO", + ) message = bpy.props.StringProperty( - name="message", - default="I have nothing to say really", - ) + name="message", + default="I have nothing to say really", + ) def execute(self, context): - #this is where I send the message + # this is where I send the message self.report({'INFO'}, 'whatever') - for i in range(0,10): - butils.ShowMessageBox('whatever','INFO','INFO') + for i in range(0, 10): + butils.ShowMessageBox('whatever', 'INFO', 'INFO') return {'FINISHED'} + classes = ( - bimport.ImportGLTF2, - bimport.GetFontFacesInFile, - ABC3D_addonPreferences, - ABC3D_available_font, - ABC3D_glyph_properties, - ABC3D_text_properties, - ABC3D_data, - ABC3D_UL_fonts, - ABC3D_UL_texts, - ABC3D_PT_Panel, - ABC3D_PT_LoadFontPanel, - ABC3D_PT_FontList, - ABC3D_PT_TextPlacement, - ABC3D_PT_TextManagement, - ABC3D_PT_FontCreation, - ABC3D_PT_TextPropertiesPanel, - ABC3D_OT_OpenAssetDirectory, - ABC3D_OT_LoadInstalledFonts, - ABC3D_OT_LoadFont, - ABC3D_OT_AddDefaultMetrics, - ABC3D_OT_RemoveMetrics, - ABC3D_OT_AlignMetricsToActiveObject, - ABC3D_OT_AlignMetrics, - ABC3D_OT_TemporaryHelper, - ABC3D_OT_RemoveText, - ABC3D_OT_PlaceText, - ABC3D_OT_InstallFont, - ABC3D_OT_ToggleABC3DCollection, - ABC3D_OT_SaveFontToFile, - ABC3D_OT_CreateFontFromObjects, - ABC3D_PT_RightPropertiesPanel, - ABC3D_OT_Reporter, - ) + bimport.ImportGLTF2, + bimport.GetFontFacesInFile, + ABC3D_addonPreferences, + ABC3D_available_font, + ABC3D_glyph_properties, + ABC3D_text_properties, + ABC3D_data, + ABC3D_UL_fonts, + ABC3D_UL_texts, + ABC3D_PT_Panel, + ABC3D_PT_LoadFontPanel, + ABC3D_PT_FontList, + ABC3D_PT_TextPlacement, + ABC3D_PT_TextManagement, + ABC3D_PT_FontCreation, + ABC3D_PT_TextPropertiesPanel, + ABC3D_OT_OpenAssetDirectory, + ABC3D_OT_LoadInstalledFonts, + ABC3D_OT_LoadFont, + ABC3D_OT_AddDefaultMetrics, + ABC3D_OT_RemoveMetrics, + ABC3D_OT_AlignMetricsToActiveObject, + ABC3D_OT_AlignMetrics, + ABC3D_OT_TemporaryHelper, + ABC3D_OT_RemoveText, + ABC3D_OT_PlaceText, + ABC3D_OT_InstallFont, + ABC3D_OT_ToggleABC3DCollection, + ABC3D_OT_SaveFontToFile, + ABC3D_OT_CreateFontFromObjects, + ABC3D_PT_RightPropertiesPanel, + ABC3D_OT_Reporter, +) + def compare_text_object_with_object(t, o, strict=False): for k in o.keys(): @@ -1462,7 +1538,7 @@ def compare_text_object_with_object(t, o, strict=False): if o[k] != "textobject": return False elif k.startswith(f"{utils.prefix()}_"): - p = k.replace(f"{utils.prefix()}_","") + p = k.replace(f"{utils.prefix()}_", "") if p in t.keys(): if t[p] != o[k]: return False @@ -1471,9 +1547,10 @@ def compare_text_object_with_object(t, o, strict=False): if strict: return False # for p in t.keys(): - # if + # if return True + def detect_text(): scene = bpy.context.scene abc3d_data = scene.abc3d_data @@ -1483,9 +1560,11 @@ def detect_text(): if len(abc3d_data.available_texts) > linked_textobject \ and abc3d_data.available_texts[linked_textobject].text_object == o: t = abc3d_data.available_texts[linked_textobject] - a = test_availability(o["font_name"], o["face_name"], o["text"]) + a = test_availability( + o["font_name"], o["face_name"], o["text"]) butils.transfer_blender_object_to_text_properties(o, t) + def load_used_glyphs(): print("LOAD USED GLYPHS") scene = bpy.context.scene @@ -1519,16 +1598,19 @@ def load_handler(self, dummy): butils.run_in_main_thread(bpy.ops.abc3d.load_installed_fonts) butils.run_in_main_thread(load_used_glyphs) + def load_handler_unload(): if bpy.app.timers.is_registered(butils.execute_queued_functions): bpy.app.timers.unregister(butils.execute_queued_functions) + @persistent def on_frame_changed(self, dummy): for t in bpy.context.scene.abc3d_data.available_texts: # TODO PERFORMANCE: only on demand butils.set_text_on_curve(t) + @persistent def on_depsgraph_update(scene, depsgraph): for u in depsgraph.updates: @@ -1538,7 +1620,8 @@ def on_depsgraph_update(scene, depsgraph): linked_textobject = u.id[f"{utils.prefix()}_linked_textobject"] if u.is_updated_geometry and len(scene.abc3d_data.available_texts) > linked_textobject and not "prevent_recursion" in u.id: u.id["prevent_recursion"] = True - butils.set_text_on_curve(scene.abc3d_data.available_texts[linked_textobject]) + butils.set_text_on_curve( + scene.abc3d_data.available_texts[linked_textobject]) elif "prevent_recursion" in u.id.keys(): del u.id["prevent_recursion"] @@ -1574,6 +1657,7 @@ def register(): Font.name_to_glyph_d = Font.generate_name_to_glyph_d() + def unregister(): addon_updater_ops.unregister() @@ -1592,6 +1676,6 @@ def unregister(): del bpy.types.Scene.abc3d_data print(f"UNREGISTER {bl_info['name']}") + if __name__ == '__main__': register() -