cosmetics

This commit is contained in:
themancalledjakob 2024-11-05 16:01:15 +01:00
parent 4a10584710
commit 30251a635f

View file

@ -4,6 +4,14 @@
A 3D font helper 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 = { bl_info = {
"name": "ABC3D", "name": "ABC3D",
"author": "Jakob Schlötter, Studio Pointer*", "author": "Jakob Schlötter, Studio Pointer*",
@ -18,10 +26,7 @@ bl_info = {
# when registering # when registering
# handy for development # handy for development
# first import dependencies for the method # first import dependencies for the method
import importlib if "Font" in locals():
# then import dependencies for our addon
if "bpy" in locals():
importlib.reload(Font) importlib.reload(Font)
importlib.reload(utils) importlib.reload(utils)
importlib.reload(butils) importlib.reload(butils)
@ -34,20 +39,6 @@ else:
from . import bimport from . import bimport
from . import addon_updater_ops 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): def getPreferences(context):
preferences = context.preferences preferences = context.preferences
@ -165,15 +156,15 @@ class ABC3D_text_properties(bpy.types.PropertyGroup):
if len(d.available_fonts) > 0: if len(d.available_fonts) > 0:
if len(d.available_fonts) > d.active_text_index: if len(d.available_fonts) > d.active_text_index:
f = d.available_fonts[d.active_text_index] f = d.available_fonts[d.active_text_index]
return 0 #f"{f.font_name} {f.face_name}" return 0 # f"{f.font_name} {f.face_name}"
else: else:
f = d.available_fonts[0] f = d.available_fonts[0]
return 0 #f"{f.font_name} {f.face_name}" return 0 # f"{f.font_name} {f.face_name}"
if type(self.font_name) != type(None) and type(self.face_name) != type(None): 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: else:
return 0 #"" return 0 # ""
def glyphs_update_callback(self, context): def glyphs_update_callback(self, context):
butils.prepare_text(self.font_name, butils.prepare_text(self.font_name,
@ -250,9 +241,13 @@ 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)
#TODO: simply, merge, cut cut cut # TODO: simply, merge, cut cut cut
class ABC3D_data(bpy.types.PropertyGroup): 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): def active_font_index_update(self, context):
if len(self.available_fonts) <= self.active_font_index: if len(self.available_fonts) <= self.active_font_index:
self.active_font_index = len(self.available_fonts) - 1 self.active_font_index = len(self.available_fonts) - 1
@ -261,14 +256,16 @@ class ABC3D_data(bpy.types.PropertyGroup):
default=-1, default=-1,
update=active_font_index_update, update=active_font_index_update,
) )
available_texts: bpy.props.CollectionProperty(type=ABC3D_text_properties, name="Available texts") available_texts: bpy.props.CollectionProperty(
type=ABC3D_text_properties, name="Available texts")
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 o = self.available_texts[self.active_text_index].text_object
# active_text_index changed. so let's update the selection # active_text_index changed. so let's update the selection
# check if it is already selected # check if it is already selected
# or perhaps one of the glyphs # 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") bpy.ops.object.select_all(action="DESELECT")
o.select_set(True) o.select_set(True)
bpy.context.view_layer.objects.active = o bpy.context.view_layer.objects.active = o
@ -297,20 +294,24 @@ class ABC3D_data(bpy.types.PropertyGroup):
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 # avoids renaming the item by accident
layout.label(text=f"{index}: {item.font_name} {item.face_name}")
def invoke(self, context, event): def invoke(self, context, event):
pass pass
class ABC3D_UL_texts(bpy.types.UIList): class ABC3D_UL_texts(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):
split = layout.split(factor=0.3) split = layout.split(factor=0.3)
split.label(text="Id: %d" % (item.text_id)) 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): def invoke(self, context, event):
pass pass
class ABC3D_PT_Panel(bpy.types.Panel): class ABC3D_PT_Panel(bpy.types.Panel):
bl_label = f"{__name__} panel" bl_label = f"{__name__} panel"
bl_category = "ABC3D" bl_category = "ABC3D"
@ -325,8 +326,10 @@ 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__}.load_installed_fonts", text="load installed fonts", icon=icon) layout.operator(f"{__name__}.load_installed_fonts",
layout.operator(f"{__name__}.open_asset_directory", text="open asset directory", icon='FILEBROWSER') 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): class ABC3D_PT_LoadFontPanel(bpy.types.Panel):
@ -365,13 +368,16 @@ class ABC3D_PT_FontList(bpy.types.Panel):
abc3d_data = scene.abc3d_data abc3d_data = scene.abc3d_data
layout.label(text="Available Fonts") 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: if abc3d_data.active_font_index >= 0:
available_font = 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 font_name = available_font.font_name
face_name = available_font.face_name face_name = available_font.face_name
available_glyphs = sorted(Font.fonts[font_name].faces[face_name].glyphs_in_fontfile) available_glyphs = sorted(
loaded_glyphs = sorted(Font.fonts[font_name].faces[face_name].loaded_glyphs) 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 = layout.box()
box.row().label(text=f"Font Name: {font_name}") box.row().label(text=f"Font Name: {font_name}")
box.row().label(text=f"Face Name: {face_name}") box.row().label(text=f"Face Name: {face_name}")
@ -380,20 +386,26 @@ class ABC3D_PT_FontList(bpy.types.Panel):
box.row().label(text=f"Glyphs:") box.row().label(text=f"Glyphs:")
subbox = box.box() subbox = box.box()
for i in range(0, n_rows + 1): 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]) text = ''.join([f"{u}" for ui, u in enumerate(
available_glyphs) if ui < (i+1) * n and ui >= i * n])
scale_y = 0.5 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) row.label(text=text)
n_rows = int(len(loaded_glyphs) / n) n_rows = int(len(loaded_glyphs) / n)
box.row().label(text=f"Loaded/Used Glyphs:") box.row().label(text=f"Loaded/Used Glyphs:")
subbox = box.box() subbox = box.box()
for i in range(0, n_rows + 1): 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]) text = ''.join([f"{u}" for ui, u in enumerate(
loaded_glyphs) if ui < (i+1) * n and ui >= i * n])
scale_y = 0.5 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.label(text=text)
row = layout.row() 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.font_name = font_name
oper.face_name = face_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="Cannot place Text.")
layout.label(text="Select a curve as active object.") layout.label(text="Select a curve as active object.")
class ABC3D_PT_TextManagement(bpy.types.Panel): class ABC3D_PT_TextManagement(bpy.types.Panel):
bl_label = "Text Management" bl_label = "Text Management"
bl_parent_id = "ABC3D_PT_Panel" bl_parent_id = "ABC3D_PT_Panel"
@ -443,6 +456,7 @@ class ABC3D_PT_TextManagement(bpy.types.Panel):
scene = context.scene scene = context.scene
abc3d_data = scene.abc3d_data abc3d_data = scene.abc3d_data
# TODO: update available_texts # TODO: update available_texts
def update(): def update():
if bpy.context.screen.is_animation_playing: if bpy.context.screen.is_animation_playing:
return return
@ -461,7 +475,8 @@ class ABC3D_PT_TextManagement(bpy.types.Panel):
# these might be there in t.glyphs, but linked to removed objects # these might be there in t.glyphs, but linked to removed objects
# or they might be lost # or they might be lost
if type(next((g for g in t.glyphs if type(g.glyph_object) == type(None)), None)) == type(None): 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: # for g in t.glyphs:
# if type(g) == type(None): # if type(g) == type(None):
# print("IS NONE") # print("IS NONE")
@ -478,17 +493,18 @@ class ABC3D_PT_TextManagement(bpy.types.Panel):
for i in remove_list: for i in remove_list:
if type(abc3d_data.available_texts[i].text_object) != type(None): if type(abc3d_data.available_texts[i].text_object) != type(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()}_linked_textobject")
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")
abc3d_data.available_texts.remove(i) abc3d_data.available_texts.remove(i)
for i, t in enumerate(abc3d_data.available_texts): 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 abc3d_data = scene.abc3d_data
layout.label(text="Text Objects") layout.label(text="Text Objects")
layout.template_list("ABC3D_UL_texts", "", abc3d_data, "available_texts", abc3d_data, "active_text_index") layout.template_list("ABC3D_UL_texts", "", abc3d_data,
layout.row().operator(f"{__name__}.remove_text", text="Remove Textobject") "available_texts", abc3d_data, "active_text_index")
layout.row().operator(
f"{__name__}.remove_text", text="Remove Textobject")
class ABC3D_PT_FontCreation(bpy.types.Panel): class ABC3D_PT_FontCreation(bpy.types.Panel):
bl_label = "Font Creation" bl_label = "Font Creation"
@ -531,22 +550,29 @@ class ABC3D_PT_FontCreation(bpy.types.Panel):
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')
box = layout.box() box = layout.box()
box.row().label(text="Exporting a fontfile") box.row().label(text="Exporting a fontfile")
box.row().label(text="1. Select export directory:") box.row().label(text="1. Select export directory:")
box.prop(abc3d_data, 'export_dir') box.prop(abc3d_data, 'export_dir')
box.row().label(text="2. More options and export:") box.row().label(text="2. More options and export:")
box.row().operator(f"{__name__}.save_font_to_file", text='Export Font To File') box.row().operator(f"{__name__}.save_font_to_file",
layout.row().operator(f"{__name__}.toggle_abc3d_collection", text='Toggle Collection') text='Export Font To File')
layout.row().operator(
f"{__name__}.toggle_abc3d_collection", text='Toggle Collection')
box = layout.box() box = layout.box()
box.label(text="metrics") 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__}.remove_metrics", text='Remove Metrics')
box.row().operator(f"{__name__}.align_metrics", text='Align 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') box.row().operator(
layout.row().operator(f"{__name__}.temporaryhelper", text='Debug Function Do Not Use') 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): class ABC3D_PT_TextPropertiesPanel(bpy.types.Panel):
bl_label = "Text Properties" bl_label = "Text Properties"
@ -556,7 +582,8 @@ class ABC3D_PT_TextPropertiesPanel(bpy.types.Panel):
bl_region_type = "UI" bl_region_type = "UI"
def get_active_text_properties(self): 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: for t in bpy.context.scene.abc3d_data.available_texts:
if bpy.context.active_object == t.text_object: if bpy.context.active_object == t.text_object:
return t return t
@ -592,7 +619,7 @@ class ABC3D_PT_TextPropertiesPanel(bpy.types.Panel):
# ) # )
@classmethod @classmethod
def poll(self,context): def poll(self, context):
return type(self.get_active_text_properties(self)) != type(None) return type(self.get_active_text_properties(self)) != type(None)
def draw(self, context): def draw(self, context):
@ -620,6 +647,7 @@ class ABC3D_PT_TextPropertiesPanel(bpy.types.Panel):
layout.column().prop(props, "translation") layout.column().prop(props, "translation")
layout.column().prop(props, "orientation") layout.column().prop(props, "orientation")
class ABC3D_OT_InstallFont(bpy.types.Operator): class ABC3D_OT_InstallFont(bpy.types.Operator):
"""Install or load Fontfile from path above. """Install or load Fontfile from path above.
(Format must be *.glb or *.gltf)""" (Format must be *.glb or *.gltf)"""
@ -659,7 +687,8 @@ class ABC3D_OT_InstallFont(bpy.types.Operator):
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,")
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.label(text="the fontfile should not be moved.")
layout.row().prop(self, "load_into_memory") layout.row().prop(self, "load_into_memory")
if self.load_into_memory: if self.load_into_memory:
@ -719,6 +748,7 @@ class ABC3D_OT_InstallFont(bpy.types.Operator):
return {'FINISHED'} return {'FINISHED'}
class ABC3D_OT_OpenAssetDirectory(bpy.types.Operator): class ABC3D_OT_OpenAssetDirectory(bpy.types.Operator):
"""Open Asset Directory""" """Open Asset Directory"""
bl_idname = f"{__name__}.open_asset_directory" bl_idname = f"{__name__}.open_asset_directory"
@ -781,6 +811,7 @@ class ABC3D_OT_LoadInstalledFonts(bpy.types.Operator):
return {'FINISHED'} return {'FINISHED'}
class ABC3D_OT_LoadFont(bpy.types.Operator): 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.""" """Load all glyphs from a specific font in memory.\nThis can take a while and slow down Blender."""
bl_idname = f"{__name__}.load_font" bl_idname = f"{__name__}.load_font"
@ -796,6 +827,7 @@ class ABC3D_OT_LoadFont(bpy.types.Operator):
butils.load_font_from_filepath(f) butils.load_font_from_filepath(f)
return {'FINISHED'} return {'FINISHED'}
class ABC3D_OT_AddDefaultMetrics(bpy.types.Operator): class ABC3D_OT_AddDefaultMetrics(bpy.types.Operator):
"""Add default metrics to selected objects""" """Add default metrics to selected objects"""
bl_idname = f"{__name__}.add_default_metrics" 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) butils.add_default_metrics_to_objects(objects)
return {'FINISHED'} return {'FINISHED'}
class ABC3D_OT_RemoveMetrics(bpy.types.Operator): class ABC3D_OT_RemoveMetrics(bpy.types.Operator):
"""Remove metrics from selected objects""" """Remove metrics from selected objects"""
bl_idname = f"{__name__}.remove_metrics" bl_idname = f"{__name__}.remove_metrics"
@ -818,6 +851,7 @@ class ABC3D_OT_RemoveMetrics(bpy.types.Operator):
butils.remove_metrics_from_objects(objects) butils.remove_metrics_from_objects(objects)
return {'FINISHED'} return {'FINISHED'}
class ABC3D_OT_AlignMetricsToActiveObject(bpy.types.Operator): class ABC3D_OT_AlignMetricsToActiveObject(bpy.types.Operator):
"""Align metrics of selected objects to metrics of active object""" """Align metrics of selected objects to metrics of active object"""
bl_idname = f"{__name__}.align_metrics_to_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) butils.align_metrics_of_objects_to_active_object(objects)
return {'FINISHED'} return {'FINISHED'}
class ABC3D_OT_AlignMetrics(bpy.types.Operator): class ABC3D_OT_AlignMetrics(bpy.types.Operator):
"""Align metrics of selected objects to each other""" """Align metrics of selected objects to each other"""
bl_idname = f"{__name__}.align_metrics" bl_idname = f"{__name__}.align_metrics"
@ -840,6 +875,7 @@ class ABC3D_OT_AlignMetrics(bpy.types.Operator):
butils.align_metrics_of_objects(objects) butils.align_metrics_of_objects(objects)
return {'FINISHED'} return {'FINISHED'}
class ABC3D_OT_TemporaryHelper(bpy.types.Operator): 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.""" """Temporary Helper ABC3D\nThis could do anything.\nIt's just there to make random functions available for testing."""
bl_idname = f"{__name__}.temporaryhelper" bl_idname = f"{__name__}.temporaryhelper"
@ -867,6 +903,7 @@ class ABC3D_OT_TemporaryHelper(bpy.types.Operator):
return {'FINISHED'} return {'FINISHED'}
class ABC3D_OT_RemoveText(bpy.types.Operator): class ABC3D_OT_RemoveText(bpy.types.Operator):
"""Remove Text 3D""" """Remove Text 3D"""
bl_idname = f"{__name__}.remove_text" bl_idname = f"{__name__}.remove_text"
@ -894,17 +931,18 @@ class ABC3D_OT_RemoveText(bpy.types.Operator):
i = abc3d_data.active_text_index i = abc3d_data.active_text_index
if type(abc3d_data.available_texts[i].text_object) != type(None): if type(abc3d_data.available_texts[i].text_object) != type(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()}_linked_textobject")
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:
@ -1040,6 +1078,7 @@ class ABC3D_OT_PlaceText(bpy.types.Operator):
return {'FINISHED'} return {'FINISHED'}
class ABC3D_OT_ToggleABC3DCollection(bpy.types.Operator): class ABC3D_OT_ToggleABC3DCollection(bpy.types.Operator):
"""Toggle ABC3D Collection""" """Toggle ABC3D Collection"""
bl_idname = f"{__name__}.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") fontcollection = bpy.data.collections.get("ABC3D")
if fontcollection is None: 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: elif scene.collection.children.find(fontcollection.name) < 0:
scene.collection.children.link(fontcollection) scene.collection.children.link(fontcollection)
self.report({'INFO'}, f"{bl_info['name']}: show collection") self.report({'INFO'}, f"{bl_info['name']}: show collection")
@ -1073,27 +1113,32 @@ class ABC3D_OT_SaveFontToFile(bpy.types.Operator):
preferences = getPreferences(context) preferences = getPreferences(context)
abc3d_data = context.scene.abc3d_data abc3d_data = context.scene.abc3d_data
if abc3d_data.export_dir == "": 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) return wm.invoke_props_dialog(self)
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.label(text="Available Fonts") 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] available_font = abc3d_data.available_fonts[abc3d_data.active_font_index]
font_name = available_font.font_name font_name = available_font.font_name
face_name = available_font.face_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 = 16
n_rows = int(len(loaded_glyphs) / n) n_rows = int(len(loaded_glyphs) / n)
box = layout.box() box = layout.box()
box.row().label(text=f"Glyphs to be exported:") box.row().label(text=f"Glyphs to be exported:")
subbox = box.box() subbox = box.box()
for i in range(0, n_rows + 1): 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]) text = ''.join([f"{u}" for ui, u in enumerate(
loaded_glyphs) if ui < (i+1) * n and ui >= i * n])
scale_y = 0.5 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.label(text=text)
layout.prop(abc3d_data, 'export_dir') layout.prop(abc3d_data, 'export_dir')
@ -1110,15 +1155,18 @@ class ABC3D_OT_SaveFontToFile(bpy.types.Operator):
return {'CANCELLED'} return {'CANCELLED'}
if abc3d_data.active_font_index < 0: 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'} return {'CANCELLED'}
if len(abc3d_data.available_fonts) <= abc3d_data.active_font_index: 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'} return {'CANCELLED'}
# save state to restore later # 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 = [] was_selection = []
for obj in bpy.context.selected_objects: for obj in bpy.context.selected_objects:
was_selection.append(obj) 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] selected_font = abc3d_data.available_fonts[abc3d_data.active_font_index]
# print(selected_font.font_name) # 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) preferences = getPreferences(context)
print(f"assets folder: {preferences.assets_dir}") print(f"assets folder: {preferences.assets_dir}")
@ -1169,12 +1218,14 @@ class ABC3D_OT_SaveFontToFile(bpy.types.Operator):
bpy.ops.export_scene.gltf( bpy.ops.export_scene.gltf(
filepath=filepath, filepath=filepath,
check_existing=False, 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, export_extras=True,
use_selection=True, use_selection=True,
use_active_scene=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() # bpy.ops.scene.delete()
# restore() # restore()
@ -1229,29 +1280,42 @@ class ABC3D_OT_CreateFontFromObjects(bpy.types.Operator):
row.prop(self, 'autodetect_names') row.prop(self, 'autodetect_names')
if self.autodetect_names: if self.autodetect_names:
scale_y = 0.5 scale_y = 0.5
row = layout.row(); row.scale_y = scale_y row = layout.row()
row.label(text="Watch out, follow convention in naming your meshes:") 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="'<glyph id>_<font name>_<face name>'") row.label(text="'<glyph id>_<font name>_<face name>'")
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.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.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.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.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.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.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.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.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.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'") row.label(text="- 'colon_NM_Origin_Tender_2'")
box = layout.box() box = layout.box()
box.enabled = not self.autodetect_names box.enabled = not self.autodetect_names
@ -1264,8 +1328,10 @@ class ABC3D_OT_CreateFontFromObjects(bpy.types.Operator):
character = "" character = ""
if Font.known_misspellings[k] in Font.name_to_glyph_d: if Font.known_misspellings[k] in Font.name_to_glyph_d:
character = f" ({Font.name_to_glyph_d[Font.known_misspellings[k]]})" character = f" ({Font.name_to_glyph_d[Font.known_misspellings[k]]})"
row = layout.row(); row.scale_y = 0.5 row = layout.row()
row.label(text=f"{k}{Font.known_misspellings[k]}{character}") row.scale_y = 0.5
row.label(
text=f"{k}{Font.known_misspellings[k]}{character}")
def execute(self, context): def execute(self, context):
print(f"executing {self.bl_idname}") print(f"executing {self.bl_idname}")
@ -1300,7 +1366,8 @@ class ABC3D_OT_CreateFontFromObjects(bpy.types.Operator):
if self.autodetect_names: if self.autodetect_names:
ifxsplit = o.name.split('_') ifxsplit = o.name.split('_')
if len(ifxsplit) < 4: 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 continue
font_name = f"{ifxsplit[1]}_{ifxsplit[2]}" font_name = f"{ifxsplit[1]}_{ifxsplit[2]}"
face_name = ifxsplit[3] face_name = ifxsplit[3]
@ -1314,7 +1381,7 @@ class ABC3D_OT_CreateFontFromObjects(bpy.types.Operator):
name = o.name.split('_')[0] name = o.name.split('_')[0]
glyph_id = Font.name_to_glyph(name) glyph_id = Font.name_to_glyph(name)
if type(glyph_id )!= type(None): if type(glyph_id) != type(None):
o["glyph"] = glyph_id o["glyph"] = glyph_id
o["font_name"] = font_name o["font_name"] = font_name
o["face_name"] = face_name o["face_name"] = face_name
@ -1328,7 +1395,7 @@ class ABC3D_OT_CreateFontFromObjects(bpy.types.Operator):
glyph_id, glyph_id,
o) 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 found = False
for f in abc3d_data.available_fonts.values(): for f in abc3d_data.available_fonts.values():
if (f.font_name == font_name if (f.font_name == font_name
@ -1341,11 +1408,14 @@ class ABC3D_OT_CreateFontFromObjects(bpy.types.Operator):
f.face_name = face_name f.face_name = face_name
else: else:
print(f"import warning: did not understand glyph {name}") print(
self.report({'INFO'}, f"did not understand glyph {name}") f"import warning: did not understand glyph {name}")
self.report(
{'INFO'}, f"did not understand glyph {name}")
return {'FINISHED'} return {'FINISHED'}
class ABC3D_PT_RightPropertiesPanel(bpy.types.Panel): class ABC3D_PT_RightPropertiesPanel(bpy.types.Panel):
"""Creates a Panel in the Object properties window""" """Creates a Panel in the Object properties window"""
bl_label = f"{bl_info['name']}" bl_label = f"{bl_info['name']}"
@ -1355,10 +1425,12 @@ class ABC3D_PT_RightPropertiesPanel(bpy.types.Panel):
bl_context = "object" bl_context = "object"
@classmethod @classmethod
def poll(self,context): def poll(self, context):
# only show the panel, if it's a textobject or a glyph # 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_text = type(next((t for t in context.scene.abc3d_data.available_texts if t.text_object ==
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) 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 return is_text or is_glyph
def draw(self, context): def draw(self, context):
@ -1370,6 +1442,7 @@ class ABC3D_PT_RightPropertiesPanel(bpy.types.Panel):
def is_it_text(): 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) 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(): 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) 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,6 +1474,7 @@ class ABC3D_PT_RightPropertiesPanel(bpy.types.Panel):
if is_glyph: if is_glyph:
layout.row().label(text="Glyph Properties:") layout.row().label(text="Glyph Properties:")
class ABC3D_OT_Reporter(bpy.types.Operator): class ABC3D_OT_Reporter(bpy.types.Operator):
bl_idname = f"{__name__}.reporter" bl_idname = f"{__name__}.reporter"
bl_label = "Report" bl_label = "Report"
@ -1415,12 +1489,13 @@ class ABC3D_OT_Reporter(bpy.types.Operator):
) )
def execute(self, context): def execute(self, context):
#this is where I send the message # this is where I send the message
self.report({'INFO'}, 'whatever') self.report({'INFO'}, 'whatever')
for i in range(0,10): for i in range(0, 10):
butils.ShowMessageBox('whatever','INFO','INFO') butils.ShowMessageBox('whatever', 'INFO', 'INFO')
return {'FINISHED'} return {'FINISHED'}
classes = ( classes = (
bimport.ImportGLTF2, bimport.ImportGLTF2,
bimport.GetFontFacesInFile, bimport.GetFontFacesInFile,
@ -1454,7 +1529,8 @@ classes = (
ABC3D_OT_CreateFontFromObjects, ABC3D_OT_CreateFontFromObjects,
ABC3D_PT_RightPropertiesPanel, ABC3D_PT_RightPropertiesPanel,
ABC3D_OT_Reporter, ABC3D_OT_Reporter,
) )
def compare_text_object_with_object(t, o, strict=False): def compare_text_object_with_object(t, o, strict=False):
for k in o.keys(): for k in o.keys():
@ -1462,7 +1538,7 @@ def compare_text_object_with_object(t, o, strict=False):
if o[k] != "textobject": if o[k] != "textobject":
return False return False
elif k.startswith(f"{utils.prefix()}_"): elif k.startswith(f"{utils.prefix()}_"):
p = k.replace(f"{utils.prefix()}_","") p = k.replace(f"{utils.prefix()}_", "")
if p in t.keys(): if p in t.keys():
if t[p] != o[k]: if t[p] != o[k]:
return False return False
@ -1474,6 +1550,7 @@ def compare_text_object_with_object(t, o, strict=False):
# if # if
return True return True
def detect_text(): def detect_text():
scene = bpy.context.scene scene = bpy.context.scene
abc3d_data = scene.abc3d_data abc3d_data = scene.abc3d_data
@ -1483,9 +1560,11 @@ def detect_text():
if len(abc3d_data.available_texts) > linked_textobject \ if len(abc3d_data.available_texts) > linked_textobject \
and abc3d_data.available_texts[linked_textobject].text_object == o: and abc3d_data.available_texts[linked_textobject].text_object == o:
t = abc3d_data.available_texts[linked_textobject] 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) butils.transfer_blender_object_to_text_properties(o, t)
def load_used_glyphs(): def load_used_glyphs():
print("LOAD USED GLYPHS") print("LOAD USED GLYPHS")
scene = bpy.context.scene 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(bpy.ops.abc3d.load_installed_fonts)
butils.run_in_main_thread(load_used_glyphs) butils.run_in_main_thread(load_used_glyphs)
def load_handler_unload(): def load_handler_unload():
if bpy.app.timers.is_registered(butils.execute_queued_functions): if bpy.app.timers.is_registered(butils.execute_queued_functions):
bpy.app.timers.unregister(butils.execute_queued_functions) bpy.app.timers.unregister(butils.execute_queued_functions)
@persistent @persistent
def on_frame_changed(self, dummy): def on_frame_changed(self, dummy):
for t in bpy.context.scene.abc3d_data.available_texts: for t in bpy.context.scene.abc3d_data.available_texts:
# 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: for u in depsgraph.updates:
@ -1538,7 +1620,8 @@ def on_depsgraph_update(scene, depsgraph):
linked_textobject = u.id[f"{utils.prefix()}_linked_textobject"] 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: 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 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(): elif "prevent_recursion" in u.id.keys():
del u.id["prevent_recursion"] del u.id["prevent_recursion"]
@ -1574,6 +1657,7 @@ def register():
Font.name_to_glyph_d = Font.generate_name_to_glyph_d() Font.name_to_glyph_d = Font.generate_name_to_glyph_d()
def unregister(): def unregister():
addon_updater_ops.unregister() addon_updater_ops.unregister()
@ -1592,6 +1676,6 @@ def unregister():
del bpy.types.Scene.abc3d_data del bpy.types.Scene.abc3d_data
print(f"UNREGISTER {bl_info['name']}") print(f"UNREGISTER {bl_info['name']}")
if __name__ == '__main__': if __name__ == '__main__':
register() register()