text on line
This commit is contained in:
parent
d06bf038b0
commit
7534699fb5
3 changed files with 172 additions and 15 deletions
130
__init__.py
130
__init__.py
|
@ -32,6 +32,7 @@ else:
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import math
|
import math
|
||||||
|
import mathutils
|
||||||
import io
|
import io
|
||||||
import functools
|
import functools
|
||||||
from bpy.types import Panel
|
from bpy.types import Panel
|
||||||
|
@ -41,6 +42,7 @@ from random import uniform
|
||||||
import time
|
import time
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,9 +52,55 @@ class SharedVariables():
|
||||||
def __init__(self, **kv):
|
def __init__(self, **kv):
|
||||||
self.__dict__.update(kv)
|
self.__dict__.update(kv)
|
||||||
|
|
||||||
|
def getPreferences(context):
|
||||||
|
preferences = context.preferences
|
||||||
|
return preferences.addons[__name__].preferences
|
||||||
|
|
||||||
shared = SharedVariables()
|
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):
|
class FONT3D_OT_Font3D(bpy.types.Operator):
|
||||||
"""Font 3D"""
|
"""Font 3D"""
|
||||||
|
@ -84,6 +132,11 @@ class FONT3D_settings(bpy.types.PropertyGroup):
|
||||||
default="_NM_",
|
default="_NM_",
|
||||||
maxlen=1024,
|
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):
|
class FONT3D_available_font(bpy.types.PropertyGroup):
|
||||||
|
@ -127,9 +180,13 @@ class FONT3D_PT_panel(bpy.types.Panel):
|
||||||
layout.label(text="Available Fonts")
|
layout.label(text="Available Fonts")
|
||||||
layout.template_list("FONT3D_UL_fonts", "", font3d_data, "available_fonts", font3d_data, "active_font_index")
|
layout.template_list("FONT3D_UL_fonts", "", font3d_data, "available_fonts", font3d_data, "active_font_index")
|
||||||
layout.label(text='DEBUG')
|
layout.label(text='DEBUG')
|
||||||
|
layout.row().prop(font3d, "test_text")
|
||||||
layout.row().operator('font3d.testfont', text='Test Font')
|
layout.row().operator('font3d.testfont', text='Test Font')
|
||||||
|
layout.label(text="font creation")
|
||||||
layout.row().prop(font3d, "import_infix")
|
layout.row().prop(font3d, "import_infix")
|
||||||
layout.row().operator('font3d.create_font_from_objects', text='Create Font')
|
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.row().operator('font3d.toggle_font3d_collection', text='Toggle Collection')
|
||||||
layout.label(text='DEBUG END')
|
layout.label(text='DEBUG END')
|
||||||
|
|
||||||
|
@ -145,6 +202,13 @@ class FONT3D_OT_LoadFont(bpy.types.Operator):
|
||||||
scene = bpy.context.scene
|
scene = bpy.context.scene
|
||||||
|
|
||||||
# print(f"loading da font at path {scene.font3d.font_path}")
|
# 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 = []
|
currentObjects = []
|
||||||
for ob in bpy.data.objects:
|
for ob in bpy.data.objects:
|
||||||
|
@ -180,6 +244,7 @@ class FONT3D_OT_LoadFont(bpy.types.Operator):
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
class FONT3D_OT_TestFont(bpy.types.Operator):
|
class FONT3D_OT_TestFont(bpy.types.Operator):
|
||||||
"""Test Font 3D"""
|
"""Test Font 3D"""
|
||||||
bl_idname = "font3d.testfont"
|
bl_idname = "font3d.testfont"
|
||||||
|
@ -190,14 +255,40 @@ class FONT3D_OT_TestFont(bpy.types.Operator):
|
||||||
global shared
|
global shared
|
||||||
scene = bpy.context.scene
|
scene = bpy.context.scene
|
||||||
|
|
||||||
|
|
||||||
selected = bpy.context.view_layer.objects.active
|
selected = bpy.context.view_layer.objects.active
|
||||||
|
|
||||||
glyph = Font.get_glyph("NM_Origin", "Tender", "A").data
|
if selected:
|
||||||
ob = bpy.data.objects.new('Duplicate_Linked', glyph)
|
font_name = "NM_Origin"
|
||||||
ob.location = selected.location
|
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)
|
ob.scale = (0.01, 0.01, 0.01)
|
||||||
selected.users_collection[0].objects.link(ob)
|
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'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
@ -223,6 +314,31 @@ class FONT3D_OT_ToggleFont3DCollection(bpy.types.Operator):
|
||||||
return {'FINISHED'}
|
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):
|
class FONT3D_OT_CreateFontFromObjects(bpy.types.Operator):
|
||||||
"""Create Font from open objects"""
|
"""Create Font from open objects"""
|
||||||
bl_idname = "font3d.create_font_from_objects"
|
bl_idname = "font3d.create_font_from_objects"
|
||||||
|
@ -247,6 +363,7 @@ class FONT3D_OT_CreateFontFromObjects(bpy.types.Operator):
|
||||||
added_font = False
|
added_font = False
|
||||||
|
|
||||||
font3d_data.available_fonts.clear()
|
font3d_data.available_fonts.clear()
|
||||||
|
Font.fonts = {}
|
||||||
|
|
||||||
currentObjects = []
|
currentObjects = []
|
||||||
for o in bpy.data.objects:
|
for o in bpy.data.objects:
|
||||||
|
@ -289,7 +406,9 @@ class FONT3D_OT_CreateFontFromObjects(bpy.types.Operator):
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
|
FONT3D_addonPreferences,
|
||||||
FONT3D_OT_Font3D,
|
FONT3D_OT_Font3D,
|
||||||
FONT3D_available_font,
|
FONT3D_available_font,
|
||||||
FONT3D_data,
|
FONT3D_data,
|
||||||
|
@ -299,6 +418,7 @@ classes = (
|
||||||
FONT3D_OT_TestFont,
|
FONT3D_OT_TestFont,
|
||||||
FONT3D_OT_LoadFont,
|
FONT3D_OT_LoadFont,
|
||||||
FONT3D_OT_ToggleFont3DCollection,
|
FONT3D_OT_ToggleFont3DCollection,
|
||||||
|
FONT3D_OT_SaveFontToFile,
|
||||||
FONT3D_OT_CreateFontFromObjects,
|
FONT3D_OT_CreateFontFromObjects,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -309,8 +429,6 @@ def register():
|
||||||
bpy.types.Scene.font3d_data = bpy.props.PointerProperty(type=FONT3D_data)
|
bpy.types.Scene.font3d_data = bpy.props.PointerProperty(type=FONT3D_data)
|
||||||
print(f"REGISTER {bl_info['name']}")
|
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
|
# would love to properly auto start this, but IT DOES NOT WORK
|
||||||
# if load_handler not in bpy.app.handlers.load_post:
|
# if load_handler not in bpy.app.handlers.load_post:
|
||||||
# bpy.app.handlers.load_post.append(load_handler)
|
# bpy.app.handlers.load_post.append(load_handler)
|
||||||
|
|
50
butils.py
50
butils.py
|
@ -23,10 +23,46 @@ def move_in_fontcollection(obj, fontcollection, scene):
|
||||||
scene.collection.objects.unlink(obj)
|
scene.collection.objects.unlink(obj)
|
||||||
if fontcollection.objects.find(obj.name) < 0:
|
if fontcollection.objects.find(obj.name) < 0:
|
||||||
fontcollection.objects.link(obj)
|
fontcollection.objects.link(obj)
|
||||||
if fontcollection.objects.find("glyphs") < 0:
|
# TODO: move in glyphs
|
||||||
empty = bpy.data.objects.new("glyphs", None)
|
# if fontcollection.objects.find("glyphs") < 0:
|
||||||
empty.empty_display_type = 'PLAIN_AXES'
|
# empty = bpy.data.objects.new("glyphs", None)
|
||||||
fontcollection.objects.link(empty)
|
# empty.empty_display_type = 'PLAIN_AXES'
|
||||||
glyphs = fontcollection.objects.get("glyphs")
|
# fontcollection.objects.link(empty)
|
||||||
if obj.parent != glyphs:
|
# glyphs = fontcollection.objects.get("glyphs")
|
||||||
obj.parent = 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 <https://blender.stackexchange.com/questions/169844/multi-line-text-box-with-popup-menu>`_
|
||||||
|
|
||||||
|
: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 <https://docs.blender.org/api/current/bpy_types_enum_items/icon_items.html>`_ for icons you can use
|
||||||
|
TIP: Or even better, check `Link this addons <https://docs.blender.org/manual/en/latest/addons/development/icon_viewer.html>`_ 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)
|
||||||
|
|
|
@ -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]
|
return fonts[font_name].faces[face_name].glyphs.get(glyph_id)[0]
|
||||||
|
|
||||||
|
def get_loaded_fonts():
|
||||||
|
return fonts.keys()
|
||||||
|
|
||||||
# holds all fonts
|
# holds all fonts
|
||||||
fonts = {}
|
fonts = {}
|
||||||
|
|
Loading…
Reference in a new issue