0

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.

Noob Cat
  • 1,222
  • 3
  • 20
  • 61

1 Answers1

5

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.

bl_info = {
    "name": "Scene Materials",
    "author": "batFINGER",
    "version": (1, 0),
    "blender": (2, 80, 0),
    "location": "View3D > UI > Scene",
    "description": "List All Materials in Scene",
    "warning": "",
    "doc_url": "https://blender.stackexchange.com/a/141207/15543",
    "category": "Materials",
}

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

def get_update_materials(self):

update = set(s.material for s in self.material_slots).symmetric_difference(self.materials)
if update:
    set_update_materials(self, True)
return False


def set_update_materials(self, value): if value: self.material_slots.clear() # update (or get) instead? 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 SceneMaterialSlot(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 SceneMaterialsPanel(bpy.types.Panel):

bl_label = bl_info["name"]
bl_idname = "SCENE_PT_materials"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "Scene"

def draw(self, context):

    scn = context.scene
    layout = self.layout
    col = layout.column()
    if scn.update_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 = (SceneMaterialSlot, MATERIAL_UL_extreme_matslot, SceneMaterialsPanel)

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( get=get_update_materials, set=set_update_materials, name="Update Scene Materials") bpy.types.Scene.active_material_index = IntProperty() bpy.types.Scene.material_slots = CollectionProperty( type=SceneMaterialSlot)

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

del bpy.types.Scene.active_material_index
del bpy.types.Scene.material_slots


if name == "main": register()

Edit.

Updated code to make it installable as an addon. (Add a filters to show only materials of selected / visible / etc objects in scene)

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.

batFINGER
  • 84,216
  • 10
  • 108
  • 233
  • This solution is fantastic ,I still find it hard to understand how it works, I suppose I can list anything like objects, modifiers, etc. ? – Noob Cat May 24 '19 at 03:42
  • 1
    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.... – batFINGER May 24 '19 at 10:52
  • 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 – Noob Cat May 24 '19 at 14:33