0
$\begingroup$

I make that script (Copy a piece from template UIList) Now i can draw My box with inside the active object material but i want to populate that with all material in scene, i not undertand , how to. Part of my script:

class MATERIAL_UL_extreme_matslot(bpy.types.UIList):

    def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
        ob = data
        slot = item
        ma = slot.material

        if self.layout_type in {'DEFAULT', 'COMPACT'}:
            if ma:               
                layout.prop(ma, "name", text= "", emboss=False, icon_value=icon)
            else:               
                layout.label(text="", translate=False, icon_value=icon)
                elif self.layout_type in {'GRID'}:

                    layout.alignment = 'CENTER'
                    layout.label(text="", icon_value=icon)

Then for draw in panel:

class MY_PT_Panel(bpy.types.Panel):

    bl_label = "My label"
    bl_idname = "MY_ID_NAME"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = "My Category"
    def draw(self, context):

    def draw(self, context):

        obj = context.object  
        layout = self.layout
        row = layout.row()
        row.template_list("MATERIAL_UL_extreme_matslot", "", obj, "material_slots", obj, "active_material_index")

Im not sure if that is the best solution because i want to select material slot from that UIList panel.

$\endgroup$
1
$\begingroup$

Scene.material_slots

enter image description here

If I understand question you want to display all the materials used by all the objects in the scene. Every bpy.types.Object has a material slots collection, a scene does not.

Added a material slots collection to the scene. Used an old fashioned python property to populate Scene.materials from the non None materials on the objects in the scene.

def get_scene_materials(self):    
    return set(s.material for o in self.objects 
            for s in o.material_slots if s.material
            )
bpy.types.Scene.materials = property(get_scene_materials)

To use a UIList AFAIK need the list to be a collection, the index to be an int property.

The scene material slots is not populated automatically. If the set of materials in scene, does not match those in material slots a toggle button appears to repopulate the slots. There are a couple of ways to make this automatic, but AFAIC are not worth the overhead.

The property Scene.materials will always return a set of all materials on all objects in scene.

import bpy

from bpy.types import PropertyGroup

from bpy.props import (
        CollectionProperty, 
        IntProperty,
        BoolProperty,
        StringProperty,
        PointerProperty,
        )

def update_scene_materials(self, context):
    self.material_slots.clear()
    for m in self.materials:
        s = self.material_slots.add()
        s.name = m.name
        s.material = m    

def get_scene_materials(self):    
    return set(s.material for o in self.objects 
            for s in o.material_slots if s.material
            )


class MaterialSlot(PropertyGroup):
    def get_name(self):
        return getattr(self.material, "name", "")
    material : PointerProperty(type=bpy.types.Material)
    #name : StringProperty(get=get_name)

class MATERIAL_UL_extreme_matslot(bpy.types.UIList):

    def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
        ob = data
        slot = item
        ma = slot.material

        if self.layout_type in {'DEFAULT', 'COMPACT'}:
            if ma:               
                layout.prop(ma, "name", text= "", emboss=False, icon_value=layout.icon(ma))


class SCENE_PT_materials(bpy.types.Panel):

    bl_label = "My label"
    bl_idname = "SCENE_PT_materials"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = "My Category"

    def draw(self, context):

        scn = context.scene          
        layout = self.layout
        col = layout.column()
        if set(s.material for s in scn.material_slots).symmetric_difference(scn.materials):
            col.prop(scn, "update_materials", toggle=True, icon='FILE_REFRESH')
        col.template_list(
                "MATERIAL_UL_extreme_matslot", 
                "", 
                scn, 
                "material_slots", 
                scn, 
                "active_material_index")

classes = (MaterialSlot,     
        MATERIAL_UL_extreme_matslot,
        SCENE_PT_materials)

def register():  
    for cls in classes:
        bpy.utils.register_class(cls)
    bpy.types.Scene.materials = property(get_scene_materials)
    bpy.types.Scene.update_materials = BoolProperty(
            update=update_scene_materials,
            name="Update Scene Materials")
    bpy.types.Scene.active_material_index = IntProperty()     
    bpy.types.Scene.material_slots = CollectionProperty(
        type=MaterialSlot)

def unregister():
    # fill this in.
    pass

if __name__ == "__main__":
    register()

Related: Your layout code was nuffed, see @p2or's fabulous answer to

Create an interface which is similar to the material list box

Notes:

Not sure how would correlate scene material index vs active object material index. Rather than using the list UI a more basic UI, with labels

enter image description here

    for m in scn.materials:
        col.label(text=m.name, icon_value=layout.icon(m))

or with operators could be considered.

$\endgroup$
  • $\begingroup$ This solution is fantastic ,I still find it hard to understand how it works, I suppose I can list anything like objects, modifiers, etc. ? $\endgroup$ – Pastrokkio May 24 at 3:42
  • 1
    $\begingroup$ objects, materials are ideal since they need unique names. Modifers not so. btw I like where this is going in conjunction with recent rgb answer... If you need help with something in particular comment and I will elaborate. Always try and answer with a running code snippet, which I think speaks for itself rather than filling with comments. Comment over-bloat like # import the bpy module is.... $\endgroup$ – batFINGER May 24 at 10:52
  • $\begingroup$ Ty bat, is possible store bpy.types (In that script you put in register) but i think, i have a pointerproperty with Class propertygroup, but you use .self.materials etc. I didn't want to create too much confusion in the register, since I've already registered a Pointerproperty $\endgroup$ – Pastrokkio May 24 at 14:33

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.