diff --git a/__init__.py b/__init__.py index 3226671..a8c4faf 100644 --- a/__init__.py +++ b/__init__.py @@ -32,6 +32,7 @@ else: import bpy import math +import mathutils import io import functools from bpy.types import Panel @@ -41,6 +42,7 @@ from random import uniform import time import datetime +import os import re @@ -50,9 +52,55 @@ class SharedVariables(): def __init__(self, **kv): self.__dict__.update(kv) +def getPreferences(context): + preferences = context.preferences + return preferences.addons[__name__].preferences shared = SharedVariables() +class FONT3D_addonPreferences(bpy.types.AddonPreferences): + """Font3D Addon Preferences + + These are the preferences at Edit/Preferences/Add-ons""" + + bl_idname = __name__ + + def get_default_assets_dir(): + return bpy.utils.user_resource( + '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.")) + 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.")) + else: + shared.paths["assets"] = self.assets_dir + + 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, + ) + + def draw(self, context): + layout = self.layout + layout.label(text="Directory for storage of fonts and other assets:") + layout.prop(self, "assets_dir") + class FONT3D_OT_Font3D(bpy.types.Operator): """Font 3D""" @@ -84,6 +132,11 @@ class FONT3D_settings(bpy.types.PropertyGroup): default="_NM_", maxlen=1024, ) + test_text: bpy.props.StringProperty(name="Test Text", + description="the text to test with", + default="Hello", + maxlen=1024, + ) class FONT3D_available_font(bpy.types.PropertyGroup): @@ -127,9 +180,13 @@ class FONT3D_PT_panel(bpy.types.Panel): layout.label(text="Available Fonts") layout.template_list("FONT3D_UL_fonts", "", font3d_data, "available_fonts", font3d_data, "active_font_index") layout.label(text='DEBUG') + layout.row().prop(font3d, "test_text") layout.row().operator('font3d.testfont', text='Test Font') + layout.label(text="font creation") layout.row().prop(font3d, "import_infix") layout.row().operator('font3d.create_font_from_objects', text='Create Font') + layout.row().separator() + layout.row().operator('font3d.save_font_to_file', text='Save Font To File') layout.row().operator('font3d.toggle_font3d_collection', text='Toggle Collection') layout.label(text='DEBUG END') @@ -145,6 +202,13 @@ class FONT3D_OT_LoadFont(bpy.types.Operator): scene = bpy.context.scene # print(f"loading da font at path {scene.font3d.font_path}") + if not os.path.exists(scene.font3d.font_path): + butils.ShowMessageBox( + title=f"{__name__} Warning", + icon="ERROR", + message=f"We believe the font path ({scene.font3d.font_path}) does not exist.", + ) + return {'CANCELLED'} currentObjects = [] for ob in bpy.data.objects: @@ -180,6 +244,7 @@ class FONT3D_OT_LoadFont(bpy.types.Operator): return {'FINISHED'} + class FONT3D_OT_TestFont(bpy.types.Operator): """Test Font 3D""" bl_idname = "font3d.testfont" @@ -190,14 +255,40 @@ class FONT3D_OT_TestFont(bpy.types.Operator): global shared scene = bpy.context.scene - selected = bpy.context.view_layer.objects.active - glyph = Font.get_glyph("NM_Origin", "Tender", "A").data - ob = bpy.data.objects.new('Duplicate_Linked', glyph) - ob.location = selected.location - ob.scale = (0.01, 0.01, 0.01) - selected.users_collection[0].objects.link(ob) + if selected: + font_name = "NM_Origin" + font_face = "Tender" + offset = mathutils.Vector((0.0, 0.0, 0.0)) + advance = 0 + for i, c in enumerate(scene.font3d.test_text): + glyph_id = c + glyph = Font.get_glyph(font_name, font_face, glyph_id) + + if glyph == None: + self.report({'ERROR'}, f"Glyph not found for {font_name} {font_face} {glyph_id}") + continue + elif glyph.type == "CURVE": + print("is curve") + + glyph_advance = (-1 * glyph.bound_box[0][0] + glyph.bound_box[4][0]) * 0.01 + offset.x = advance + + ob = bpy.data.objects.new(f"{glyph_id}", glyph.data) + ob.location = selected.location + offset + ob.scale = (0.01, 0.01, 0.01) + selected.users_collection[0].objects.link(ob) + ob.parent = selected + advance = advance + glyph_advance + else: + butils.ShowMessageBox( + title="No object selected", + message=( + "Please select an object.", + "It will be used to put the type on.", + "You little piece of shit :)"), + icon='GHOST_ENABLED') return {'FINISHED'} @@ -223,6 +314,31 @@ class FONT3D_OT_ToggleFont3DCollection(bpy.types.Operator): return {'FINISHED'} +class FONT3D_OT_SaveFontToFile(bpy.types.Operator): + """Save font to file""" + bl_idname = f"{__name__}.save_font_to_file" + bl_label = "Save Font" + bl_options = {'REGISTER', 'UNDO'} + + file_path = "whoopwhoop" + + def execute(self, context): + global shared + scene = bpy.context.scene + font3d_data = scene.font3d_data + font3d = scene.font3d + + selected_font = font3d_data.available_fonts[font3d_data.active_font_index] + + print(selected_font.font_name) + + if selected_font == "": + butils.ShowMessageBox("Warning", 'ERROR', "no font selected") + return {'CANCELLED'} + + return {'FINISHED'} + + class FONT3D_OT_CreateFontFromObjects(bpy.types.Operator): """Create Font from open objects""" bl_idname = "font3d.create_font_from_objects" @@ -247,6 +363,7 @@ class FONT3D_OT_CreateFontFromObjects(bpy.types.Operator): added_font = False font3d_data.available_fonts.clear() + Font.fonts = {} currentObjects = [] for o in bpy.data.objects: @@ -289,7 +406,9 @@ class FONT3D_OT_CreateFontFromObjects(bpy.types.Operator): return {'FINISHED'} + classes = ( + FONT3D_addonPreferences, FONT3D_OT_Font3D, FONT3D_available_font, FONT3D_data, @@ -299,6 +418,7 @@ classes = ( FONT3D_OT_TestFont, FONT3D_OT_LoadFont, FONT3D_OT_ToggleFont3DCollection, + FONT3D_OT_SaveFontToFile, FONT3D_OT_CreateFontFromObjects, ) @@ -309,8 +429,6 @@ def register(): bpy.types.Scene.font3d_data = bpy.props.PointerProperty(type=FONT3D_data) print(f"REGISTER {bl_info['name']}") - print(utils.get_timestamp()) - print(shared.fonts) # would love to properly auto start this, but IT DOES NOT WORK # if load_handler not in bpy.app.handlers.load_post: # bpy.app.handlers.load_post.append(load_handler) diff --git a/butils.py b/butils.py index 18130dc..d3054b9 100644 --- a/butils.py +++ b/butils.py @@ -23,10 +23,46 @@ def move_in_fontcollection(obj, fontcollection, scene): scene.collection.objects.unlink(obj) if fontcollection.objects.find(obj.name) < 0: fontcollection.objects.link(obj) - if fontcollection.objects.find("glyphs") < 0: - empty = bpy.data.objects.new("glyphs", None) - empty.empty_display_type = 'PLAIN_AXES' - fontcollection.objects.link(empty) - glyphs = fontcollection.objects.get("glyphs") - if obj.parent != glyphs: - obj.parent = glyphs + # TODO: move in glyphs + # if fontcollection.objects.find("glyphs") < 0: + # empty = bpy.data.objects.new("glyphs", None) + # empty.empty_display_type = 'PLAIN_AXES' + # fontcollection.objects.link(empty) + # glyphs = fontcollection.objects.get("glyphs") + # if obj.parent != glyphs: + # obj.parent = glyphs + +def ShowMessageBox(title = "Message Box", icon = 'INFO', message=""): + + """Show a simple message box + + taken from `Link here `_ + + :param title: The title shown in the message top bar + :type title: str + :param icon: The icon to be shown in the message top bar + :type icon: str + :param message: lines of text to display, a.k.a. the message + :type message: str or (str, str, ..) + + TIP: Check `Link blender icons `_ for icons you can use + TIP: Or even better, check `Link this addons `_ to also see the icons. + + usage: + .. code-block:: python + myLines=("line 1","line 2","line 3") + butils.ShowMessageBox(message=myLines) + + or: + .. code-block:: python + butils.ShowMessageBox(title="",message=("AAAAAH","NOOOOO"),icon=) + + """ + myLines=message + def draw(self, context): + if isinstance(myLines, str): + self.layout.label(text=myLines) + elif hasattr(myLines, "__iter__"): + for n in myLines: + self.layout.label(text=n) + bpy.context.window_manager.popup_menu(draw, title = title, icon = icon) diff --git a/common/Font.py b/common/Font.py index e99079c..24e20fc 100644 --- a/common/Font.py +++ b/common/Font.py @@ -114,5 +114,8 @@ def get_glyph(font_name, face_name, glyph_id): return fonts[font_name].faces[face_name].glyphs.get(glyph_id)[0] +def get_loaded_fonts(): + return fonts.keys() + # holds all fonts fonts = {}