1import bpy
2
3
4class MATERIAL_UL_matslots_example(bpy.types.UIList):
5    # The draw_item function is called for each item of the collection that is visible in the list.
6    #   data is the RNA object containing the collection,
7    #   item is the current drawn item of the collection,
8    #   icon is the "computed" icon for the item (as an integer, because some objects like materials or textures
9    #   have custom icons ID, which are not available as enum items).
10    #   active_data is the RNA object containing the active property for the collection (i.e. integer pointing to the
11    #   active item of the collection).
12    #   active_propname is the name of the active property (use 'getattr(active_data, active_propname)').
13    #   index is index of the current item in the collection.
14    #   flt_flag is the result of the filtering process for this item.
15    #   Note: as index and flt_flag are optional arguments, you do not have to use/declare them here if you don't
16    #         need them.
17    def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
18        ob = data
19        slot = item
20        ma = slot.material
21        # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.
22        if self.layout_type in {'DEFAULT', 'COMPACT'}:
23            # You should always start your row layout by a label (icon + text), or a non-embossed text field,
24            # this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
25            # We use icon_value of label, as our given icon is an integer value, not an enum ID.
26            # Note "data" names should never be translated!
27            if ma:
28                layout.prop(ma, "name", text="", emboss=False, icon_value=icon)
29            else:
30                layout.label(text="", translate=False, icon_value=icon)
31        # 'GRID' layout type should be as compact as possible (typically a single icon!).
32        elif self.layout_type in {'GRID'}:
33            layout.alignment = 'CENTER'
34            layout.label(text="", icon_value=icon)
35
36
37# And now we can use this list everywhere in Blender. Here is a small example panel.
38class UIListPanelExample(bpy.types.Panel):
39    """Creates a Panel in the Object properties window"""
40    bl_label = "UIList Panel"
41    bl_idname = "OBJECT_PT_ui_list_example"
42    bl_space_type = 'PROPERTIES'
43    bl_region_type = 'WINDOW'
44    bl_context = "object"
45
46    def draw(self, context):
47        layout = self.layout
48
49        obj = context.object
50
51        # template_list now takes two new args.
52        # The first one is the identifier of the registered UIList to use (if you want only the default list,
53        # with no custom draw code, use "UI_UL_list").
54        layout.template_list("MATERIAL_UL_matslots_example", "", obj, "material_slots", obj, "active_material_index")
55
56        # The second one can usually be left as an empty string.
57        # It's an additional ID used to distinguish lists in case you
58        # use the same list several times in a given area.
59        layout.template_list("MATERIAL_UL_matslots_example", "compact", obj, "material_slots",
60                             obj, "active_material_index", type='COMPACT')
61
62
63def register():
64    bpy.utils.register_class(MATERIAL_UL_matslots_example)
65    bpy.utils.register_class(UIListPanelExample)
66
67
68def unregister():
69    bpy.utils.unregister_class(MATERIAL_UL_matslots_example)
70    bpy.utils.unregister_class(UIListPanelExample)
71
72
73if __name__ == "__main__":
74    register()
75