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
$\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$
  • $\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 '18 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 '18 at 13:44
  • 1
    $\begingroup$ Yep, there was a typo. Sorry @Way2Close, see my latest revision. $\endgroup$ – brockmann Jul 16 '18 at 8:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.