# Is there a generic custom data layer?

Is there such a thing as a generic custom data layer in Blender that holds Strings, Booleans, and Enums? I'm trying to create a text box in edit mode that holds a user input note on a given mesh. Unfortunately, it seems that the note doesn't stay with the given mesh. When another mesh is in edit mode, the same note from the previous mesh is there. Is there another way to do this other than a custom layer? Is this because the text is registered?

import bpy
from bpy.props import *
import bmesh

# ---
# String Properties
# ---

def initSceneProperties():

bpy.types.Scene.StringType1 = StringProperty(
name = "String1")

# ---
# Layout
# ---

class LayoutPanel(bpy.types.Panel):
bl_label = "Test Text"
bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"
bl_context = "mesh_edit"

def draw(self, context):
scn = bpy.context.scene
layout = self.layout

row = layout.row(align=True)
col = row.column()
col.prop(scn, 'StringType1', text="")

# ---
# Registers
# ---

def register():
bpy.utils.register_module(__name__)

initSceneProperties()

def unregister():

bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
register()


D. Skarn, I came up with something like this as far as to how it should operate. If you start Blender fresh, run the script and add a cube (named "Cube"), then add text to the text box, it will hold that data. If you create a second item (Cube), put it into edit mode, the text box will be blank and text can be entered. You can switch between both items and each object will hold it's text data. I just don't know how to make it so that it is more elegant and doesn't require actually naming the object explicitly. So I guess somehow detecting a new object and instancing the property data? Will property groups do that?

import bpy
from bpy.props import *

# ---
# String Properties
# ---

def initSceneProperties():
bpy.types.Scene.naming = StringProperty(name = "String1")
bpy.types.Scene.naming1 = StringProperty(name = "String1")

# ---
# Layout
# ---

class LayoutPanel(bpy.types.Panel):
bl_label = "Test Text"
bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"
bl_context = "mesh_edit"

def draw(self, context):
scn = bpy.context.scene
layout = self.layout
obj = bpy.context.edit_object
objectOut = obj.name

row = layout.row(align=True)
col = row.column()
if (objectOut == "Cube"):
col.prop(scn, 'naming', text="")
print(scn.naming)
else:
col.prop(scn, 'naming1', text="")
print(scn.naming1)
# ---
# Registers
# ---

def register():
bpy.utils.register_module(__name__)

initSceneProperties()

def unregister():

bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
register()

• Add the custom property to the object not the scene. Use context.active_object to get the text to display. – sambler Feb 28 '17 at 5:56
• Hi Sambler, I'm sorry, were you referring to the original posted code? That displays fine. Or were you referring to D. Skarns code which I was having trouble displaying? – ACopeLan Feb 28 '17 at 12:24
• The pieces of code you have here add a property to the scene - that is why you see the same text for every object. – sambler Feb 28 '17 at 18:07

Here is a little panel I took from my project. As far as I understood, that's what you need.

class WowWMOGroupPanel(bpy.types.Panel):
bl_space_type = "PROPERTIES" # This defines where our panel should appear
bl_region_type = "WINDOW"
bl_context = "object" # This defines the mode in which it appears. In our case, it is object. However, could be "edit" or any other mode.and
bl_label = "Wow WMO group" # Label and property ID name
bl_options = {'DEFAULT_CLOSED'}

layout = self.layout
self.layout.prop(context.object.WowWMOGroup, "Enabled") # This makes the panel toggleable.

def draw(self, context):
layout = self.layout
row = layout.row()
self.layout.prop(context.object.WowWMOGroup, "GroupName") # This is our text input property

layout.enabled = context.object.WowWMOGroup.Enabled # Enables everything in layout if checkbox is enabled

@classmethod
def poll(cls, context):
# check if it is object and mesh
return (context.object is not None and context.object.data is not None and isinstance(context.object.data,bpy.types.Mesh))

class WowWMOGroupPropertyGroup(bpy.types.PropertyGroup):
Enabled = bpy.props.BoolProperty(name="", description="Enable wow WMO group properties")
GroupName = bpy.props.StringProperty() # our string input!

def RegisterWowWMOGroupProperties():
bpy.types.Object.WowWMOGroup = bpy.props.PointerProperty(type=WowWMOGroupPropertyGroup)

def UnregisterWowWMOGroupProperties():
bpy.types.Object.WowWMOGroup = None

# After doing this you can adress your property as bpy.context.scene.objects[some_id_or_name].WowWMOGroup.GroupName

• Hi. Please edit your answer to give an explanation of what this code does and how it answers the question. Just providing a block of code does not, in itself, constitute an answer (at least, not a good one). – Ray Mairlot Feb 26 '17 at 12:17
• Hi D. Skarn, can you give a functioning example in addition. I think I understand whats happening, but I want to be sure. – ACopeLan Feb 26 '17 at 18:37
• What do you mean by functioning example? A picture? i.imgur.com/qPFH4kE.png Just a text input. I gave you a proper runnable code, so you try to run it and play around with it. There is also a bunch of other properties you can use. – D. Skarn Feb 26 '17 at 19:08
• I ran the code and realized that it was missing import bpy. But afterwards, I still don't get a text box, is there something else I'm missing? – ACopeLan Feb 26 '17 at 22:11
• probably bpy.props? Show what error it gives you. – D. Skarn Feb 27 '17 at 16:48

OK I think I got it with the help of D Skarn's direction. Simply adding Property Groups seems to do the trick of allowing object's properties to be set in edit mode, but for them to have different settings per each object. I came up with this working example. Let me know if this doesn't run for anyone...

import bpy
from bpy.props import *

# ---
# Group Properties that include Float, Integer, and String
# ---

class MyPropertyGroup(bpy.types.PropertyGroup):
custom_1 = bpy.props.FloatProperty(name="My Float")
custom_2 = bpy.props.IntProperty(name="My Int")
custom_3 = bpy.props.StringProperty(name ="StringType1")

# ---
# Layout
# ---

class LayoutPanel(bpy.types.Panel):
bl_label = "Test Text"
bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"
bl_context = "mesh_edit"

def draw(self, context):
scn = bpy.context.object
layout = self.layout

row = layout.row(align=True)
col = row.column()
col.prop(scn.my_prop_grp, 'custom_3', text="")
col.prop(scn.my_prop_grp, 'custom_2', text="")
col.prop(scn.my_prop_grp, 'custom_1', text="")

# ---
# Registers
# ---

def register():
bpy.utils.register_class(MyPropertyGroup)
bpy.utils.register_class(LayoutPanel)
bpy.types.Object.my_prop_grp = bpy.props.PointerProperty(type=MyPropertyGroup)

def unregister():

bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
register()


So this is how it works according to: https://docs.blender.org/api/2.78b/bpy.types.PropertyGroup.html#bpy.types.PropertyGroup

We register the Property Group which contains any property that you want to set (int, float, string).

def register():
bpy.utils.register_class(MyPropertyGroup) # Property Group to be set.
bpy.utils.register_class(LayoutPanel)
bpy.types.Object.my_prop_grp = bpy.props.PointerProperty(type=MyPropertyGroup)


We set the variables under that class (class MyPropertiesGroup / variable: custom_1, custom_2, custom_3)

class MyPropertyGroup(bpy.types.PropertyGroup): # Property Group to be set.
custom_1 = bpy.props.FloatProperty(name="My Float") # variable custom_1
custom_2 = bpy.props.IntProperty(name="My Int") # variable custom_2
custom_3 = bpy.props.StringProperty(name ="StringType1") # variable custom_3


The Property Group is then pointed to an object for layout to use (my_prop_grp):

bpy.types.Object.my_prop_grp = bpy.props.PointerProperty(type=MyPropertyGroup)


And then the properties are implemented in layout:

    col.prop(scn.my_prop_grp, 'custom_3', text="") # String Text Box
col.prop(scn.my_prop_grp, 'custom_2', text="") # Integer Box
col.prop(scn.my_prop_grp, 'custom_1', text="") # Float Box


At least that's how I understand it in a basic way. Someone will have to fill in the blanks as far as to detailed operation...