0
$\begingroup$

Hey I need help adding materials to a UIList, I have used this answer as a guide: https://blender.stackexchange.com/a/30446/51645

Here is the functionality I need, I need to be able to click the add button and create a material, apply it and store it in the UIList. I also need to be able to rename the material in the list and have it rename the actual material name. In the same way I need to access and change the material diffuse_color in the UIList. I have tried with a prop_search, it works but I can't edit the material name.

I have commented the sections I have tried to get working.

import bpy
from bpy.props import IntProperty, CollectionProperty
from bpy.types import Panel, UIList

# create material
def add_material():

    material = bpy.data.materials.new("cg_")
    material.diffuse_color = (1, 0, 0)
    stored_selection = bpy.context.selected_objects
    for obj in stored_selection:
        obj.data.materials.clear()
        obj.data.materials.append(material)

    return material.name


class Uilist_actions(bpy.types.Operator):
    bl_idname = "custom.list_action"
    bl_label = "List Action"

    action = bpy.props.EnumProperty(
        items=(
            ('UP', "Up", ""),
            ('DOWN', "Down", ""),
            ('REMOVE', "Remove", ""),
            ('ADD', "Add", ""),
        )
    )

    def invoke(self, context, event):

        scn = context.scene
        idx = scn.custom_index

        try:
            item = scn.custom[idx]
        except IndexError:
            pass

        else:
            if self.action == 'DOWN' and idx < len(scn.custom) - 1:
                item_next = scn.custom[idx+1].name
                scn.custom.move(idx, idx + 1)
                scn.custom_index += 1
                info = 'Item %d selected' % (scn.custom_index + 1)
                self.report({'INFO'}, info)

            elif self.action == 'UP' and idx >= 1:
                item_prev = scn.custom[idx-1].name
                scn.custom.move(idx, idx-1)
                scn.custom_index -= 1
                info = 'Item %d selected' % (scn.custom_index + 1)
                self.report({'INFO'}, info)

            elif self.action == 'REMOVE':
                info = 'Item %s removed from list' % (scn.custom[scn.custom_index].name)
                scn.custom_index -= 1
                self.report({'INFO'}, info)
                scn.custom.remove(idx)

        if self.action == 'ADD':
            item = scn.custom.add()
            item.id = len(scn.custom)

            # assign material reference by name
            item.material_ref = add_material()

            scn.custom_index = (len(scn.custom)-1)
            info = '%s added to list' % (item.name)
            self.report({'INFO'}, info)

        return {"FINISHED"}


class UL_items(UIList):

    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):

        split = layout.split(0.5)

        # material name
        split.prop(item, "material_ref", text="", emboss=False, translate=False, icon='BORDER_RECT')
        # material prop search
        split.prop_search(item, "material_ref", bpy.data, "materials", text = "")


    def invoke(self, context, event):
        pass


class UIListPanelExample(Panel):
    """Creates a Panel in the Object properties window"""
    bl_idname = 'OBJECT_PT_my_panel'
    bl_space_type = "TEXT_EDITOR"
    bl_region_type = "UI"
    bl_label = "Custom Object List"

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

        rows = 2
        row = layout.row()
        row.template_list("UL_items", "", scn, "custom", scn, "custom_index", rows=rows)

        col = row.column(align=True)
        col.operator("custom.list_action", icon='ZOOMIN', text="").action = 'ADD'
        col.operator("custom.list_action", icon='ZOOMOUT', text="").action = 'REMOVE'
        col.separator()
        col.operator("custom.list_action", icon='TRIA_UP', text="").action = 'UP'
        col.operator("custom.list_action", icon='TRIA_DOWN', text="").action = 'DOWN'



class CustomProp(bpy.types.PropertyGroup):
    '''name = StringProperty() '''
    # add material_ref
    material_ref = bpy.props.StringProperty()
    id = IntProperty()


def register():
    bpy.utils.register_module(__name__)
    bpy.types.Scene.custom = CollectionProperty(type=CustomProp)
    bpy.types.Scene.custom_index = IntProperty()

def unregister():
    bpy.utils.unregister_module(__name__)
    del bpy.types.Scene.custom
    del bpy.types.Scene.custom_index

if __name__ == "__main__":
    register()

Thank you so much to anyone who helps.

$\endgroup$

1 Answer 1

1
$\begingroup$

That's actually pretty simple. Just add a PointerProperty to the PropertyGroup and assign the new material:

Property Group

    ...
    id = IntProperty()
    material = bpy.props.PointerProperty(
        name="Material",
        type=bpy.types.Material,
    )

Actions

       ...
            elif self.action == 'REMOVE':
                item = scn.custom[scn.custom_index]
                info = 'Item %s removed from list' % (item.name)
                scn.custom_index -= 1
                self.report({'INFO'}, info)
                scn.custom.remove(idx)
                mat = item.material
                rem_mat = bpy.data.materials.get(mat.name, None)
                if rem_mat:
                    bpy.data.materials.remove(rem_mat, True)

        if self.action == 'ADD':
            item = scn.custom.add()
            item.id = len(scn.custom)
            item.material = bpy.data.materials.new(name="Material")
            item.name = item.material.name
            scn.custom_index = (len(scn.custom)-1)
            info = '%s added to list' % (item.name)
            self.report({'INFO'}, info)

      ...

Drawing

    ...
    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
        mat = item.material
        split = layout.split(0.23)
        split.label("Index: %d" % (index))
        split2 = split.split(0.8)
        split2.prop(mat, "name", text="", emboss=False, translate=False, icon='SMOOTH')
        split2.prop(mat, "diffuse_color", text="")
    ...
$\endgroup$
3
  • $\begingroup$ Thank you so much, works amazingly. I got thrown off by another post saying I couldn't use a pointerProperty in a UIList. Again thank you so much. $\endgroup$
    – Way2Close
    Jul 14, 2018 at 11:56
  • $\begingroup$ Just for completion's sake, in the remove, the material needs to be deleted before the index otherwise rem_mat is NONE. $\endgroup$
    – Way2Close
    Jul 14, 2018 at 13:44
  • 1
    $\begingroup$ Yep, there was a typo. Sorry @Way2Close, see my latest revision. $\endgroup$
    – brockmann
    Jul 16, 2018 at 8:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .