1
$\begingroup$

I have an UIList drawing a collection of items.

When those items have a property (bool) draw_in_ui set to False, I would like to avoid it from drawing in draw_item() function:

I thought about returning the draw_item function:

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

    if item.draw_in_ui == False:
        # I tried all that but dont work
        # layout.scale_y =0
        # layout.ui_units_y =0
        # layout = None
        return

But it still appears as a blank space: https://i.imgur.com/c7UtvPe.png

I would like that item to be omited from drawing. Is it possible? How can I do it?

Thank you so much for the help, much appreciated.


Code to test: (Add some random materials to object to test. I would like to ignore drawing a material with the name "Material" (default name), but draw others).

import bpy


class MATERIAL_UL_matslots_example(bpy.types.UIList):
    # The draw_item function is called for each item of the collection that is visible in the list.
    #   data is the RNA object containing the collection,
    #   item is the current drawn item of the collection,
    #   icon is the "computed" icon for the item (as an integer, because some objects like materials or textures
    #   have custom icons ID, which are not available as enum items).
    #   active_data is the RNA object containing the active property for the collection (i.e. integer pointing to the
    #   active item of the collection).
    #   active_propname is the name of the active property (use 'getattr(active_data, active_propname)').
    #   index is index of the current item in the collection.
    #   flt_flag is the result of the filtering process for this item.
    #   Note: as index and flt_flag are optional arguments, you do not have to use/declare them here if you don't
    #         need them.
    def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
        ob = data
        slot = item
        ma = slot.material
        print(item.name)
        # HERE
        # HERE
        # HERE (If he name is "Material", dont draw that item)
        if item.name == "Material":
            return
        
        # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.
        if self.layout_type in {'DEFAULT', 'COMPACT'}:
            # You should always start your row layout by a label (icon + text), or a non-embossed text field,
            # this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
            # We use icon_value of label, as our given icon is an integer value, not an enum ID.
            # Note "data" names should never be translated!
            if ma:
                layout.prop(ma, "name", text="", emboss=False, icon_value=icon)
            else:
                layout.label(text="", translate=False, icon_value=icon)
        # 'GRID' layout type should be as compact as possible (typically a single icon!).
        elif self.layout_type == 'GRID':
            layout.alignment = 'CENTER'
            layout.label(text="", icon_value=icon)


# And now we can use this list everywhere in Blender. Here is a small example panel.
class UIListPanelExample(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "UIList Panel"
    bl_idname = "OBJECT_PT_ui_list_example"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

    def draw(self, context):
        layout = self.layout

        obj = context.object

        # template_list now takes two new args.
        # The first one is the identifier of the registered UIList to use (if you want only the default list,
        # with no custom draw code, use "UI_UL_list").
        layout.template_list("MATERIAL_UL_matslots_example", "", obj, "material_slots", obj, "active_material_index")

        # The second one can usually be left as an empty string.
        # It's an additional ID used to distinguish lists in case you
        # use the same list several times in a given area.
        layout.template_list("MATERIAL_UL_matslots_example", "compact", obj, "material_slots",
                             obj, "active_material_index", type='COMPACT')


def register():
    bpy.utils.register_class(MATERIAL_UL_matslots_example)
    bpy.utils.register_class(UIListPanelExample)


def unregister():
    bpy.utils.unregister_class(MATERIAL_UL_matslots_example)
    bpy.utils.unregister_class(UIListPanelExample)


if __name__ == "__main__":
    register()
$\endgroup$
4
  • $\begingroup$ i would recommend posting all your code or at least a runnable code so that we can help you. $\endgroup$
    – Chris
    Commented Jul 15, 2023 at 11:29
  • $\begingroup$ I tend to be concise just to not "bore" people reading, but maybe you are right. $\endgroup$
    – Ommadawn
    Commented Jul 15, 2023 at 20:17
  • $\begingroup$ i was assuming you have the uilist on a panel...and so if the list is empty, you just stop showing the uilist on the panel. that's why i asked for a runnable code snippet. $\endgroup$
    – Chris
    Commented Jul 16, 2023 at 5:40
  • $\begingroup$ @Chris Yes, the list is on a panel, but I meant not to draw a single item. I edited the question with code to test what I meant $\endgroup$
    – Ommadawn
    Commented Jul 16, 2023 at 20:59

1 Answer 1

1
$\begingroup$

here is an example (i just adapted the one from the doc), essentially you have to work with filters to achieve what you want:

import bpy


class MATERIAL_UL_matslots_example(bpy.types.UIList):
    # The draw_item function is called for each item of the collection that is visible in the list.
    #   data is the RNA object containing the collection,
    #   item is the current drawn item of the collection,
    #   icon is the "computed" icon for the item (as an integer, because some objects like materials or textures
    #   have custom icons ID, which are not available as enum items).
    #   active_data is the RNA object containing the active property for the collection (i.e. integer pointing to the
    #   active item of the collection).
    #   active_propname is the name of the active property (use 'getattr(active_data, active_propname)').
    #   index is index of the current item in the collection.
    #   flt_flag is the result of the filtering process for this item.
    #   Note: as index and flt_flag are optional arguments, you do not have to use/declare them here if you don't
    #         need them.
    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index, flt_flag):
        ob = data
        slot = item
        ma = slot.material
        print(item.name)
        # HERE
        # HERE
        # HERE (If he name is "Material", dont draw that item)
            
        # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.
        if self.layout_type in {'DEFAULT', 'COMPACT'}:
            # You should always start your row layout by a label (icon + text), or a non-embossed text field,
            # this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
            # We use icon_value of label, as our given icon is an integer value, not an enum ID.
            # Note "data" names should never be translated!
            if ma:
                layout.prop(ma, "name", text="", emboss=False, icon_value=icon)
            else:
                layout.label(text="", translate=False, icon_value=icon)
        # 'GRID' layout type should be as compact as possible (typically a single icon!).
        elif self.layout_type == 'GRID':
            layout.alignment = 'CENTER'
            layout.label(text="", icon_value=icon)

    def filter_items(self, context, data, propname):
        
        helper_funcs = bpy.types.UI_UL_list
        
        mats = getattr(data, propname)
        
        # Default return values.
        flt_flags = []
        flt_neworder = []
        
        flt_flags = [self.bitflag_filter_item] * len(mats)
             
        for idx, mat in enumerate(mats):
            
            if mat.name == "Material" :#or mat.name == "Material.002":
                flt_flags[idx] &= True
                
        flt_neworder = helper_funcs.sort_items_by_name(mats, "name")
        
        return flt_flags, flt_neworder

# And now we can use this list everywhere in Blender. Here is a small example panel.
class UIListPanelExample(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "UIList Panel"
    bl_idname = "OBJECT_PT_ui_list_example"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

    def draw(self, context):
        layout = self.layout

        obj = context.object

        # template_list now takes two new args.
        # The first one is the identifier of the registered UIList to use (if you want only the default list,
        # with no custom draw code, use "UI_UL_list").
        layout.template_list("MATERIAL_UL_matslots_example", "", obj, "material_slots", obj, "active_material_index")

        # The second one can usually be left as an empty string.
        # It's an additional ID used to distinguish lists in case you
        # use the same list several times in a given area.
        layout.template_list("MATERIAL_UL_matslots_example", "compact", obj, "material_slots",
                             obj, "active_material_index", type='COMPACT')


def register():
    bpy.utils.register_class(MATERIAL_UL_matslots_example)
    bpy.utils.register_class(UIListPanelExample)


def unregister():
    bpy.utils.unregister_class(MATERIAL_UL_matslots_example)
    bpy.utils.unregister_class(UIListPanelExample)


if __name__ == "__main__":
    register()

explanation here:

https://docs.blender.org/api/current/bpy.types.UIList.html

you filter your list by

def filter_items(self, context, data, propname):

important in your case is the return list flt_flags, which decides which lines will be shown

$\endgroup$
2
  • 1
    $\begingroup$ Thank you so much! Didn't know about the filter function! Works as charm, much appreciated friend :) $\endgroup$
    – Ommadawn
    Commented Jul 17, 2023 at 8:47
  • 1
    $\begingroup$ you are welcome $\endgroup$
    – Chris
    Commented Jul 17, 2023 at 9:02

You must log in to answer this question.

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