-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLayer Manager.py
169 lines (138 loc) · 7.08 KB
/
Layer Manager.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# ============================================================
# ┌┬┐┌─┐┌┬┐┌─┐┬─┐┬ ┬
# ┌┬┐┌─┐┌┬┐┌─┐┬─┐┬ ┬
# │││├┤ ││││ │├┬┘└┬┘
# ┴ ┴└─┘┴ ┴└─┘┴└─ ┴
# ┴ ┴└─┘┴ ┴└─┘┴└─ ┴
# ============================================================
# May 11, 2023
#
# This code was generated by GPT-4, an AI model by OpenAI.
# But memory made it happen. If you add to this script please add your name.
#
# metatools - layer manager
# for drawing ui elements to visualize metadata
import bpy
import blf
from bpy_extras.view3d_utils import location_3d_to_region_2d
import textwrap
class DrawingClass:
def __init__(self, context):
self.handle = bpy.types.SpaceView3D.draw_handler_add(
self.draw_text_callback, (context,), 'WINDOW', 'POST_PIXEL')
def draw_text_callback(self, context):
font_id = 0
color = context.scene.my_tool.my_color
font_size = context.scene.my_tool.font_size
padding = context.scene.my_tool.padding
wrap_width = context.scene.my_tool.wrap_width
include_name = context.scene.my_tool.include_name
blf.color(font_id, color[0], color[1], color[2], color[3])
for obj in context.visible_objects:
if obj.type == 'MESH':
for i, layer in enumerate(context.scene.my_tool.layers):
if layer.name in obj and layer.enabled:
value = obj[layer.name]
loc = obj.matrix_world.to_translation()
region = context.region
rv3d = context.region_data
coord_2d = location_3d_to_region_2d(region, rv3d, loc)
if coord_2d is not None:
blf.position(font_id, coord_2d.x + layer.offset_x, coord_2d.y + layer.offset_y + padding - i * (font_size + 10), 0)
blf.size(font_id, font_size, 72)
text = f"{layer.name}: {value}" if include_name else f"{value}"
lines = textwrap.wrap(text, wrap_width)
for j, line in enumerate(lines):
blf.position(font_id, coord_2d.x + layer.offset_x, coord_2d.y + layer.offset_y + padding - i * (font_size + 10) - j * font_size, 0)
blf.draw(font_id, line)
def remove_handle(self):
bpy.types.SpaceView3D.draw_handler_remove(self.handle, 'WINDOW')
class MyLayerItem(bpy.types.PropertyGroup):
name: bpy.props.StringProperty(name="Layer Name", default="Unnamed")
enabled: bpy.props.BoolProperty(name="Enabled", default=True)
offset_x: bpy.props.IntProperty(name="Offset X", description="X offset", default=0, min=-100, max=100)
offset_y: bpy.props.IntProperty(name="Offset Y", description="Y offset", default=0, min=-100, max=100)
class MyProperties(bpy.types.PropertyGroup):
font_size: bpy.props.IntProperty(name="Font Size", description="Font Size", default=20, min=1, max=100)
my_color: bpy.props.FloatVectorProperty(name="My Color", description="Font Color", subtype='COLOR_GAMMA', size=4, min=0.0, max=1.0, default=(1.0, 1.0, 1.0, 1.0))
layers: bpy.props.CollectionProperty(type=MyLayerItem)
active_layer_index: bpy.props.IntProperty(name="Active Layer Index", default=0)
padding: bpy.props.IntProperty(name="Padding", description="Vertical padding between text layers", default=0, min=-100, max=100)
wrap_width: bpy.props.IntProperty(name="Wrap Width", description="Width at which text will wrap", default=50, min=1)
include_name: bpy.props.BoolProperty(name="Include Name", description="Include the name of the property in the text", default=True)
class OBJECT_OT_add_layer(bpy.types.Operator):
bl_idname = "object.add_layer"
bl_label = "Add Layer"
bl_options = {'REGISTER', 'UNDO'}
layer_name: bpy.props.StringProperty(name="Layer Name")
def execute(self, context):
my_tool = context.scene.my_tool
layer = my_tool.layers.add()
layer.name = self.layer_name
my_tool.active_layer_index = len(my_tool.layers) - 1
return {'FINISHED'}
def invoke(self, context, event):
return context.window_manager.invoke_props_dialog(self)
class OBJECT_OT_remove_layer(bpy.types.Operator):
bl_idname = "object.remove_layer"
bl_label = "Remove Layer"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return context.scene.my_tool.layers
def execute(self, context):
my_tool = context.scene.my_tool
my_tool.layers.remove(my_tool.active_layer_index)
my_tool.active_layer_index = min(max(0, my_tool.active_layer_index - 1), len(my_tool.layers) - 1)
return {'FINISHED'}
class OBJECT_PT_my_panel(bpy.types.Panel):
bl_idname = "OBJECT_PT_my_panel"
bl_label = "My Panel"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "My Panel"
def draw(self, context):
layout = self.layout
scene = context.scene
my_tool = scene.my_tool
layout.prop(my_tool, "font_size")
layout.prop(my_tool, "my_color")
layout.prop(my_tool, "padding")
layout.prop(my_tool, "wrap_width")
layout.prop(my_tool, "include_name")
layout.label(text="Custom Property Layers:")
for i, layer in enumerate(my_tool.layers):
box = layout.box()
row = box.row()
row.prop(layer, "name", text=f"Layer {i+1}")
row.prop(layer, "enabled", text="")
box.prop(layer, "offset_x")
box.prop(layer, "offset_y")
layout.operator(OBJECT_OT_add_layer.bl_idname)
layout.operator(OBJECT_OT_remove_layer.bl_idname)
def register():
bpy.utils.register_class(MyLayerItem)
bpy.utils.register_class(MyProperties)
bpy.utils.register_class(OBJECT_OT_add_layer)
bpy.utils.register_class(OBJECT_OT_remove_layer)
bpy.utils.register_class(OBJECT_PT_my_panel)
bpy.types.Scene.my_tool = bpy.props.PointerProperty(type=MyProperties)
# Find existing custom properties
my_tool = bpy.context.scene.my_tool
for obj in bpy.context.scene.objects:
if obj.type == 'MESH':
for key in obj.keys():
if key not in my_tool.layers and key not in {'_RNA_UI', 'cycles'}:
layer = my_tool.layers.add()
layer.name = key
context = bpy.context
dc = DrawingClass(context)
def unregister():
bpy.utils.unregister_class(MyLayerItem)
bpy.utils.unregister_class(MyProperties)
bpy.utils.unregister_class(OBJECT_OT_add_layer)
bpy.utils.unregister_class(OBJECT_OT_remove_layer)
bpy.utils.unregister_class(OBJECT_PT_my_panel)
del bpy.types.Scene.my_tool
if __name__ == "__main__":
register()