0

Say I want to add a list of the UVLayers on a selected object in my UI Panel. Noted that PointerProperty only supports types with an ID or PropertyGroup subclass.

I tried instead passing the list of UV Layers as an EnumProperty in this way:

class PropGroup(PropertyGroup):
    def get_uvs(self):
        uvs = []
        for uvMap in self.seed_object.data.uv_layers:
            uvs.append(uvMap)
        return uvs
seed_object: PointerProperty(
    name="Base Object",
    description="Object to duplicate",
    type=bpy.types.Object
)

seed_object_uvs: EnumProperty(
    name="Uvs",
    items=get_uvs()
)
...

But I am getting an error that get_uvs is missing the parameter 'self'. When I pass 'self' literally in the line items=getuvs(self) it assumes this is a named argument. Declaring the function outside the class fixes the above issue of needing 'self', but throws an error where the seed_object parameter isn't defined. I understand this is because seed_object is being referenced before it is actually assigned, but still leaves me without a solution.

The clear workaround is to not declare the UVs as a property, and in the necessary operator(s) use something like object.uv_layers.active(), or whatever to get the layer. In general though, I'd like to know if there is a way to store this sort of object data in a Property Group or at least through the UI.

Rug
  • 833
  • 9
  • 26
  • 2
    Goal is to replicate the regular UV layer list on a custom panel? If so, have a look into properties_data_mesh.py, there is a DATA_PT_uv_texture class calling: col.template_list("MESH_UL_uvmaps", "uvmaps", me, "uv_layers", me.uv_layers, "active_index", rows=2) to display the layers in a list. – brockmann Sep 24 '21 at 06:19
  • Oh is that a template? Good catch, thanks! Il check that out – Rug Sep 24 '21 at 17:33

1 Answers1

2

Have a look into the UI source code (RMB on the UV layers > Edit Source). There is a DATA_PT_uv_texture class in properties_data_mesh.py calling UILayout.template_list() to display the UV layers (line 438).

In order to display the same list on a custom panel, just pass the actual mesh data C.object.data as me variable:

col.template_list("MESH_UL_uvmaps", "uvmaps", me, "uv_layers", me.uv_layers, "active_index", rows=2)

Demo based on the layout code from How to create a custom UI?

bl_info = {
    "name": "Add-on Template",
    "description": "",
    "author": "p2or",
    "version": (0, 0, 3),
    "blender": (2, 80, 0),
    "location": "3D View > Tools",
    "warning": "", # used for warning icon and text in addons panel
    "wiki_url": "",
    "tracker_url": "",
    "category": "Development"
}

import bpy from bpy.types import Panel, Operator

------------------------------------------------------------------------

Operators

------------------------------------------------------------------------

class WM_OT_HelloWorld(Operator): bl_label = "Print Values Operator" bl_idname = "wm.hello_world"

def execute(self, context):
    print (context.object.data.uv_layers.active)
    return {'FINISHED'}

------------------------------------------------------------------------

Panel in Object Mode

------------------------------------------------------------------------

class OBJECT_PT_CustomPanel(Panel): bl_label = "My Panel" bl_idname = "OBJECT_PT_custom_panel" bl_space_type = "VIEW_3D"
bl_region_type = "UI" bl_category = "Tools" #bl_context = "objectmode"

@classmethod
def poll(self,context):
    return context.object is not None and context.object.type == 'MESH'

def draw(self, context):
    layout = self.layout
    scene = context.scene
    me = context.object.data

    row = layout.row()
    row.template_list("MESH_UL_uvmaps", "uvmaps", me, "uv_layers", me.uv_layers, "active_index", rows=2)

    layout.operator(WM_OT_HelloWorld.bl_idname)
    layout.separator()

------------------------------------------------------------------------

Registration

------------------------------------------------------------------------

classes = ( WM_OT_HelloWorld, OBJECT_PT_CustomPanel )

def register(): from bpy.utils import register_class for cls in classes: register_class(cls)

def unregister(): from bpy.utils import unregister_class for cls in reversed(classes): unregister_class(cls)

if name == "main": register()

brockmann
  • 12,613
  • 4
  • 50
  • 93