font path adventures with Mac OS

This commit is contained in:
themancalledjakob 2024-08-23 16:32:40 +02:00
parent edb2c8cb8b
commit 3631ac8e49
2 changed files with 71 additions and 89 deletions

View file

@ -93,60 +93,11 @@ class ABC3D_addonPreferences(bpy.types.AddonPreferences):
layout.prop(self, "assets_dir") layout.prop(self, "assets_dir")
class ABC3D_settings(bpy.types.PropertyGroup):
font_path: bpy.props.StringProperty(
name="Font path",
description="Load a *.glb or *.gltf fontfile from disk",
default="",
maxlen=1024,
subtype="FILE_PATH")
import_infix: bpy.props.StringProperty(
name="Font name import infix",
description="The infix which all font objects to import have. obj name: 'A_NM_Origin_Tender' -> infix: '_NM_Origin_Tender'",
default="_NM_",
maxlen=1024,
)
text: bpy.props.StringProperty(
name="Text",
description="The text.",
default="HELLO",
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,
)
letter_spacing: bpy.props.FloatProperty(
name="Letter Spacing",
description="Letter Spacing",
default=0.0,
)
font_size: bpy.props.FloatProperty(
name="Font Size",
default=1.0,
subtype='NONE',
)
translation: bpy.props.FloatVectorProperty(
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',
)
offset: bpy.props.FloatProperty(
name="Offset",
default=0.0,
subtype='NONE',
)
class ABC3D_available_font(bpy.types.PropertyGroup): class ABC3D_available_font(bpy.types.PropertyGroup):
font_name: bpy.props.StringProperty(name="") font_name: bpy.props.StringProperty(name="")
face_name: bpy.props.StringProperty(name="") face_name: bpy.props.StringProperty(name="")
class ABC3D_glyph_properties(bpy.types.PropertyGroup): class ABC3D_glyph_properties(bpy.types.PropertyGroup):
glyph_id: bpy.props.StringProperty(maxlen=1) glyph_id: bpy.props.StringProperty(maxlen=1)
glyph_object: bpy.props.PointerProperty(type=bpy.types.Object) glyph_object: bpy.props.PointerProperty(type=bpy.types.Object)
@ -282,6 +233,20 @@ class ABC3D_data(bpy.types.PropertyGroup):
active_text_index: bpy.props.IntProperty(update=active_text_index_update) 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()
# 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")
class ABC3D_UL_fonts(bpy.types.UIList): class ABC3D_UL_fonts(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): 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 layout.label(text=f"{index}: {item.font_name} {item.face_name}") # avoids renaming the item by accident
@ -313,27 +278,25 @@ class ABC3D_PT_Panel(bpy.types.Panel):
layout.row().label(text='no fonts loaded yet') 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__}.load_installed_fonts", text="load installed fonts", icon=icon)
layout.row().prop(context.scene.abc3d_data, "font_path")
layout.row().operator(f"{__name__}.install_font", text='Install new font')
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"
bl_options = {"DEFAULT_CLOSED"}
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 = scene.abc3d # abc3d_data = scene.abc3d_data
abc3d_data = scene.abc3d_data
layout.label(text="Install FontFile:") # layout.row().operator(f"{__name__}.install_font", text='Install new font')
layout.row().prop(abc3d, "font_path")
layout.row().operator(f"{__name__}.install_font", text='Install')
class ABC3D_PT_FontList(bpy.types.Panel): class ABC3D_PT_FontList(bpy.types.Panel):
@ -348,7 +311,6 @@ class ABC3D_PT_FontList(bpy.types.Panel):
wm = context.window_manager wm = context.window_manager
scene = context.scene scene = context.scene
abc3d = scene.abc3d
abc3d_data = scene.abc3d_data abc3d_data = scene.abc3d_data
layout.label(text="Available Fonts") layout.label(text="Available Fonts")
@ -403,7 +365,6 @@ class ABC3D_PT_TextPlacement(bpy.types.Panel):
wm = context.window_manager wm = context.window_manager
scene = context.scene scene = context.scene
abc3d = scene.abc3d
abc3d_data = scene.abc3d_data abc3d_data = scene.abc3d_data
placerow = layout.row() placerow = layout.row()
@ -425,7 +386,6 @@ class ABC3D_PT_TextManagement(bpy.types.Panel):
@classmethod @classmethod
def poll(self, context): def poll(self, context):
scene = context.scene scene = context.scene
abc3d = scene.abc3d
abc3d_data = scene.abc3d_data abc3d_data = scene.abc3d_data
# TODO: update available_texts # TODO: update available_texts
def update(): def update():
@ -495,7 +455,6 @@ class ABC3D_PT_TextManagement(bpy.types.Panel):
wm = context.window_manager wm = context.window_manager
scene = context.scene scene = context.scene
abc3d = scene.abc3d
abc3d_data = scene.abc3d_data abc3d_data = scene.abc3d_data
layout.label(text="Text Objects") layout.label(text="Text Objects")
@ -515,7 +474,6 @@ class ABC3D_PT_FontCreation(bpy.types.Panel):
wm = context.window_manager wm = context.window_manager
scene = context.scene scene = context.scene
abc3d = scene.abc3d
abc3d_data = scene.abc3d_data 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')
@ -580,7 +538,6 @@ class ABC3D_PT_TextPropertiesPanel(bpy.types.Panel):
layout = self.layout layout = self.layout
wm = context.window_manager wm = context.window_manager
scene = context.scene scene = context.scene
abc3d = scene.abc3d
abc3d_data = scene.abc3d_data abc3d_data = scene.abc3d_data
props = self.get_active_text_properties() props = self.get_active_text_properties()
@ -609,6 +566,20 @@ class ABC3D_OT_InstallFont(bpy.types.Operator):
bl_label = "Load Font" bl_label = "Load Font"
bl_options = {'REGISTER', 'UNDO'} bl_options = {'REGISTER', 'UNDO'}
def font_path_update_callback(self, context):
if os.path.exists(self.font_path):
print(f"{self.font_path} does exist")
else:
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")
install_in_assets: bpy.props.BoolProperty( install_in_assets: bpy.props.BoolProperty(
name="install in assets", name="install in assets",
description="install the font in the assets directory of the addon", description="install the font in the assets directory of the addon",
@ -620,7 +591,9 @@ class ABC3D_OT_InstallFont(bpy.types.Operator):
default=False) default=False)
def draw(self, context): def draw(self, context):
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, "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:
layout.label(text="If the fontfile is not installed,") layout.label(text="If the fontfile is not installed,")
@ -634,27 +607,42 @@ 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 = abc3d_data.font_path
if not os.path.exists(self.font_path):
bpy.app.timers.register(lambda: butils.ShowMessageBox(
title=f"{__name__} Warning",
icon="ERROR",
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)
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
if not os.path.exists(scene.abc3d.font_path): abc3d_data = context.scene.abc3d_data
if not os.path.exists(self.font_path):
butils.ShowMessageBox( butils.ShowMessageBox(
title=f"{__name__} Warning", title=f"{__name__} Warning",
icon="ERROR", icon="ERROR",
message=f"We believe the font path ({scene.abc3d.font_path}) does not exist.", message=[
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'} return {'CANCELLED'}
if self.install_in_assets: if self.install_in_assets:
preferences = getPreferences(context) preferences = getPreferences(context)
filename = os.path.basename(scene.abc3d.font_path) filename = os.path.basename(self.font_path)
target = os.path.join(preferences.assets_dir, "fonts", filename) target = os.path.join(preferences.assets_dir, "fonts", filename)
print(f"installing {scene.abc3d.font_path} -> {target}")
import shutil import shutil
os.makedirs(os.path.dirname(target), exist_ok=True) os.makedirs(os.path.dirname(target), exist_ok=True)
shutil.copyfile(scene.abc3d.font_path, target) shutil.copyfile(self.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)
@ -663,9 +651,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(scene.abc3d.font_path) butils.register_font_from_filepath(self.font_path)
if self.load_into_memory: if self.load_into_memory:
butils.load_font_from_filepath(scene.abc3d.font_path) butils.load_font_from_filepath(self.font_path)
return {'FINISHED'} return {'FINISHED'}
@ -692,6 +680,7 @@ class ABC3D_OT_LoadInstalledFonts(bpy.types.Operator):
return context.window_manager.invoke_props_dialog(self) return context.window_manager.invoke_props_dialog(self)
def execute(self, context): def execute(self, context):
print("EXECUTE LOAD INSTALLED FONTS")
scene = bpy.context.scene scene = bpy.context.scene
if self.load_into_memory: if self.load_into_memory:
@ -907,9 +896,6 @@ class ABC3D_OT_PlaceText(bpy.types.Operator):
selected = bpy.context.view_layer.objects.active selected = bpy.context.view_layer.objects.active
# if abc3d.target_object:
# selected = abc3d.target_object
if selected: if selected:
# font = abc3d_data.available_fonts[abc3d_data.active_font_index] # font = abc3d_data.available_fonts[abc3d_data.active_font_index]
# font_name = font.font_name # font_name = font.font_name
@ -1181,7 +1167,7 @@ class ABC3D_OT_CreateFontFromObjects(bpy.types.Operator):
if fontcollection is None: if fontcollection is None:
fontcollection = bpy.data.collections.new("ABC3D") fontcollection = bpy.data.collections.new("ABC3D")
ifxsplit = abc3d.import_infix.split('_') ifxsplit = self.import_infix.split('_')
# if len(ifxsplit) != 4: # if len(ifxsplit) != 4:
# font_name = f"{ifxsplit[1]}_{ifxsplit[2]}" # font_name = f"{ifxsplit[1]}_{ifxsplit[2]}"
@ -1207,7 +1193,6 @@ class ABC3D_OT_CreateFontFromObjects(bpy.types.Operator):
if butils.is_mesh(o) and not butils.is_metrics_object(o): if butils.is_mesh(o) and not butils.is_metrics_object(o):
uc = o.users_collection uc = o.users_collection
# regex = f"{abc3d.import_infix}(.)*"
if self.fix_common_misspellings: if self.fix_common_misspellings:
o.name = Font.fix_glyph_name_misspellings(o.name) o.name = Font.fix_glyph_name_misspellings(o.name)
# name = re.sub(regex, "", o.name) # name = re.sub(regex, "", o.name)
@ -1332,11 +1317,10 @@ classes = (
ABC3D_glyph_properties, ABC3D_glyph_properties,
ABC3D_text_properties, ABC3D_text_properties,
ABC3D_data, ABC3D_data,
ABC3D_settings,
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,
@ -1378,7 +1362,6 @@ def on_frame_changed(self, dummy):
def register(): def register():
for cls in classes: for cls in classes:
bpy.utils.register_class(cls) bpy.utils.register_class(cls)
bpy.types.Scene.abc3d = bpy.props.PointerProperty(type=ABC3D_settings)
bpy.types.Scene.abc3d_data = bpy.props.PointerProperty(type=ABC3D_data) bpy.types.Scene.abc3d_data = bpy.props.PointerProperty(type=ABC3D_data)
# bpy.types.Object.__del__ = lambda self: print(f"Bye {self.name}") # bpy.types.Object.__del__ = lambda self: print(f"Bye {self.name}")
print(f"REGISTER {bl_info['name']}") print(f"REGISTER {bl_info['name']}")
@ -1413,7 +1396,6 @@ def unregister():
if on_frame_changed in bpy.app.handlers.frame_change_post: if on_frame_changed in bpy.app.handlers.frame_change_post:
bpy.app.handlers.frame_change_post.remove(on_frame_changed) bpy.app.handlers.frame_change_post.remove(on_frame_changed)
del bpy.types.Scene.abc3d
del bpy.types.Scene.abc3d_data del bpy.types.Scene.abc3d_data
print(f"UNREGISTER {bl_info['name']}") print(f"UNREGISTER {bl_info['name']}")

View file

@ -416,7 +416,7 @@ def register_font_from_filepath(filepath):
def load_font_from_filepath(filepath, glyphs="", font_name="", face_name=""): def load_font_from_filepath(filepath, glyphs="", font_name="", face_name=""):
if not filepath.endswith(".glb") and not filepath.endswith(".gltf"): if not filepath.endswith(".glb") and not filepath.endswith(".gltf"):
ShowMessageBox(f"{bl_info['name']} Font loading error", 'ERROR', f"Filepath({filepath}) is not a *.glb or *.gltf file") ShowMessageBox(f"Font loading error", 'ERROR', f"Filepath({filepath}) is not a *.glb or *.gltf file")
return False return False
marker_property = "font_import" marker_property = "font_import"