2
$\begingroup$

I'm new to python and I encounter a problem with update callback function.

I have a UiList of items, and I'm looking for a way to display a popup window when user click on one of the items in the lists. Since it looks like i have to use CollectionProperty to use UiList, i have setup one and use an EnumProperty inside.

My problem is: I can't find a way to callback update from the CollectionProperty; and writing the update in the EnumProperty doesn't seem to do anything in this case.

class SCENE_OT_source_populate(Operator):
    bl_idname = "scene.source_populate"
    bl_label = "Populate source"
    
    def execute(self,context):
        context.scene.SMSL.collection.clear()
        preset = context.scene.StrewPresetDrop.StrewPresetDropdown
        AssetList = GetAssetList.Specie(self, context, preset)
        for Asset in AssetList:
            item = context.scene.SMSL.collection.add()
            Path = Asset.split(",")
            item.name = Path[1]
            item.description = Asset
        return {'FINISHED'}

class SMSAsset(PropertyGroup):
    type = EnumProperty(
        items=(
            ('A', "Option A", ""),
            ('B', "Option B", ""),
        )
    )
    #val = IntProperty()
    
class SMSList(PropertyGroup):
    collection : CollectionProperty(
        name = "SMSA",
        type = SMSAsset)
    active_user_index : IntProperty()
        
class SMS_UL_List(UIList):
    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
        if self.layout_type in {'DEFAULT', 'COMPACT'}:
            layout.prop(item, "name", text="", emboss=False)
            #layout.prop(item, "val", text="")
            #layout.prop(item, "type", text="")
        elif self.layout_type in {'GRID'}:
            layout.alignment = 'CENTER'
            layout.label(text="", icon_value=icon)

def register():
    bpy.util.register_class(SMS_UL_Lists)
    bpy.util.register_class(SCENE_OT_source_populate)
    bpy.types.Scene.SMSL = PointerProperty(type= SMSList)

I looked in the blender doc and CollectionProperty is the only one witouth a Update callback. Is there a way to work around this please?

$\endgroup$
0
2
$\begingroup$

On the active index.

enter image description here _Clicking on an item updates the index and calls splash which calls bpy.ops.wm.show_panel(...) to display the newly active item. Hovering over the "Hello World" throws up a panel popover which uses context pointer set in the draw_item method.

I'm looking for a way to display a popup window when user click on one of the items in the lists.

The list UI changes the property set for active index when another index is chosen. An update method on the index int property will be fired when list index changes.

Test with question code, draw method tacked onto Properties > Scene panel.

A panel is displayed by operator, and by popover. In hindsight the UI in popover may be best seen but disabled

import bpy
from bpy.types import Operator, PropertyGroup, UIList
from bpy.props import IntProperty, EnumProperty, CollectionProperty, PointerProperty

class HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"
    #bl_options = {'INSTANCED'}
        
    def draw(self, context):
        layout = self.layout
        smsl = context.scene.SMSL
        user = getattr(
                context,
                "active_smms_user", 
                smsl.collection[smsl.active_user_index]
                )
        col = layout.column()

        col.label(text=f" {user.name}", icon='WORLD_DATA')
        col.prop(user, "val")
        col.prop(user, "type")

class SCENE_OT_source_populate(Operator):
    bl_idname = "scene.source_populate"
    bl_label = "Populate source"
    
    def execute(self,context):
        context.scene.SMSL.collection.clear()
        # wtf (lol)>? 
        AssetList = ["Foo, foo", "Bar, bar"]
        for Asset in AssetList:
            item = context.scene.SMSL.collection.add()
            Path = Asset.split(",")
            item.name = Path[1]
            item.description = Asset
        return {'FINISHED'}

class SMSAsset(PropertyGroup):
    type : EnumProperty(
        items=(
            ('A', "Option A", ""),
            ('B', "Option B", ""),
        )
    )
    val : IntProperty()
    
def splash(self, context):
    # AFAICT context override does not get to panel
    bpy.ops.wm.call_panel(
            {"active_smms_user" : self.collection[self.active_user_index]},
            'INVOKE_DEFAULT',
            name="OBJECT_PT_hello",
            )
    return None
    
class SMSList(PropertyGroup):
    collection : CollectionProperty(
        name = "SMSA",
        type = SMSAsset)
    active_user_index : IntProperty(update=splash)
        
class SMS_UL_List(UIList):
    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): 
        layout.context_pointer_set("active_smms_user", item,)
        if self.layout_type in {'DEFAULT', 'COMPACT'}:
            layout.prop(item, "name", text="", emboss=False)
            layout.prop(item, "val", text="")
            layout.prop(item, "type", text="")
            if hasattr(bpy.types, "OBJECT_PT_hello"):
                
                layout.popover("OBJECT_PT_hello")
        elif self.layout_type in {'GRID'}:
            layout.alignment = 'CENTER'
            layout.label(text="", icon_value=icon)
def draw(self, context):
    layout = self.layout
    smsl = context.scene.SMSL
    layout.label(text="Test")
    layout.operator("scene.source_populate")
    layout.template_list(
            "SMS_UL_List", "",
             smsl, "collection", smsl, "active_user_index")
             
classes = (
        SMSAsset, 
        SMS_UL_List,
        SMSList,
        HelloWorldPanel,
        SCENE_OT_source_populate,
        )
        
def register():
    for cls in classes:
        bpy.utils.register_class(cls)

    bpy.types.Scene.SMSL = PointerProperty(type= SMSList)
    bpy.types.SCENE_PT_scene.append(draw)

if __name__ == "__main__":
    register()
$\endgroup$
4
  • $\begingroup$ It perfectly works. Thanks. $\endgroup$ – Asloric Feb 10 at 13:33
  • $\begingroup$ Hey, unrelated to the question, but would you know how to force the popover panel you created to be larger ? It expands vertically when I add items, but not horizontally and I can't find a way to enlarge said panel $\endgroup$ – Gorgious Feb 10 at 16:31
  • $\begingroup$ There are the ui_units_x and scale_x (and y) options in layout. docs.blender.org/api/current/… but only the y versions appear to do anything. Even long label texts get trunc'd $\endgroup$ – batFINGER Feb 10 at 17:09
  • $\begingroup$ Yeah that was my impression too... Thanks :) $\endgroup$ – Gorgious Feb 18 at 10:48

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.