Using template_list() with invoke_props_dialog() #47657

Closed
opened 2016-03-02 13:17:36 +01:00 by Aleksandr Zinovev · 12 comments

System Information
Kubuntu 15.10
Nvidia GeForce 9600 GT (driver: 340.96)

Blender Version
Broken: 2.76b
Not reproducible in 2.77rc1 because of #47632.

Short description of error
An attempt to redraw property dialog that contains template_list() function crashes Blender:
list.png

import bpy

class MyItem(bpy.types.PropertyGroup):
    pass

class WM_UL_my_list(bpy.types.UIList):
    pass

class WM_OT_my_props_dialog(bpy.types.Operator):
    bl_idname = "wm.my_props_dialog"
    bl_label = "Props Dialog"

    collection = bpy.props.CollectionProperty(type=MyItem)
    collection_index = bpy.props.IntProperty()

    def check(self, context):
        return True

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

        layout.template_list(
            "WM_UL_my_list", "",
            self, "collection", self, "collection_index")

    def execute(self, context):
        return {'FINISHED'}

    def invoke(self, context, event):
        for i in range(0, 3):
            item = self.collection.add()
            item.name="Item %d" % i
        return context.window_manager.invoke_props_dialog(self)

bpy.utils.register_module(__name__)

bpy.ops.wm.my_props_dialog('INVOKE_DEFAULT')

Exact steps for others to reproduce the error

  1. Run the script in blender's text editor.
  2. Try to select the second item.
**System Information** Kubuntu 15.10 Nvidia GeForce 9600 GT (driver: 340.96) **Blender Version** Broken: 2.76b Not reproducible in 2.77rc1 because of #47632. **Short description of error** An attempt to redraw property dialog that contains [template_list() ](https://www.blender.org/api/blender_python_api_2_77_0/bpy.types.UILayout.html#bpy.types.UILayout.template_list) function crashes Blender: ![list.png](https://archive.blender.org/developer/F286651/list.png) ``` import bpy class MyItem(bpy.types.PropertyGroup): pass class WM_UL_my_list(bpy.types.UIList): pass class WM_OT_my_props_dialog(bpy.types.Operator): bl_idname = "wm.my_props_dialog" bl_label = "Props Dialog" collection = bpy.props.CollectionProperty(type=MyItem) collection_index = bpy.props.IntProperty() def check(self, context): return True def draw(self, context): layout = self.layout layout.template_list( "WM_UL_my_list", "", self, "collection", self, "collection_index") def execute(self, context): return {'FINISHED'} def invoke(self, context, event): for i in range(0, 3): item = self.collection.add() item.name="Item %d" % i return context.window_manager.invoke_props_dialog(self) bpy.utils.register_module(__name__) bpy.ops.wm.my_props_dialog('INVOKE_DEFAULT') ``` **Exact steps for others to reproduce the error** 1. Run the script in blender's text editor. 2. Try to select the second item.
Author
Member

Changed status to: 'Open'

Changed status to: 'Open'
Author
Member

Added subscriber: @AleksandrZinovev-2

Added subscriber: @AleksandrZinovev-2

Added subscribers: @JulianEisel, @ideasman42, @mont29

Added subscribers: @JulianEisel, @ideasman42, @mont29

Problem is, ui_list depends on a valid region available in context, and looks like context from popup do not have any region.

@JulianEisel, @ideasman42, do you know whether this is expected behavior? I'd assume we should get the temp popup region here?

Problem is, ui_list depends on a valid region available in context, and looks like context from popup do not have any region. @JulianEisel, @ideasman42, do you know whether this is expected behavior? I'd assume we should get the temp popup region here?

Adding current temp ARegion to context in draw code solves the issue, see e.g. this quick patch:

P330: #47657

diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 179677a..90366cc 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -1417,6 +1417,9 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData)
 	uiBlock *block;
 	uiLayout *layout;
 	uiStyle *style = UI_style_get();
+	ARegion *ctx_ar = CTX_wm_region(C);
+
+	CTX_wm_region_set(C, ar);
 
 	block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
 	UI_block_flag_disable(block, UI_BLOCK_LOOP);
@@ -1450,6 +1453,7 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData)
 	/* center around the mouse */
 	UI_block_bounds_set_popup(block, 4, data->width / -2, data->height / 2);
 
+	CTX_wm_region_set(C, ctx_ar);
 	return block;
 }
 
@@ -1460,6 +1464,9 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *ar, void *userData)
 	uiBlock *block;
 	uiLayout *layout;
 	uiStyle *style = UI_style_get();
+	ARegion *ctx_ar = CTX_wm_region(C);
+
+	CTX_wm_region_set(C, ar);
 
 	block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
 	UI_block_flag_disable(block, UI_BLOCK_LOOP);
@@ -1472,6 +1479,7 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *ar, void *userData)
 
 	UI_block_bounds_set_popup(block, 4, 0, 0);
 
+	CTX_wm_region_set(C, ctx_ar);
 	return block;
 }
 

Adding current temp `ARegion` to context in draw code solves the issue, see e.g. this quick patch: [P330: #47657](https://archive.blender.org/developer/P330.txt) ```diff diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 179677a..90366cc 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1417,6 +1417,9 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData) uiBlock *block; uiLayout *layout; uiStyle *style = UI_style_get(); + ARegion *ctx_ar = CTX_wm_region(C); + + CTX_wm_region_set(C, ar); block = UI_block_begin(C, ar, __func__, UI_EMBOSS); UI_block_flag_disable(block, UI_BLOCK_LOOP); @@ -1450,6 +1453,7 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData) /* center around the mouse */ UI_block_bounds_set_popup(block, 4, data->width / -2, data->height / 2); + CTX_wm_region_set(C, ctx_ar); return block; } @@ -1460,6 +1464,9 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *ar, void *userData) uiBlock *block; uiLayout *layout; uiStyle *style = UI_style_get(); + ARegion *ctx_ar = CTX_wm_region(C); + + CTX_wm_region_set(C, ar); block = UI_block_begin(C, ar, __func__, UI_EMBOSS); UI_block_flag_disable(block, UI_BLOCK_LOOP); @@ -1472,6 +1479,7 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *ar, void *userData) UI_block_bounds_set_popup(block, 4, 0, 0); + CTX_wm_region_set(C, ctx_ar); return block; } ```
Member

Although it's pretty annoying, afaik it's intended behavior. Not 100% sure but I think CTX_wm_menu can be used to avoid this.

Although it's pretty annoying, afaik it's intended behavior. Not 100% sure but I think `CTX_wm_menu` can be used to avoid this.

Yes indeed, falling back to CTX_wm_menu in case CTX_wm_region returns NULL works in this case… Seems a bit odd to me though. :/

Yes indeed, falling back to `CTX_wm_menu` in case `CTX_wm_region` returns NULL works in this case… Seems a bit odd to me though. :/
Member

Would do the other way around, falling back to CTX_wm_region when CTX_wm_menu fails. UI_block_draw does this.

Would do the other way around, falling back to `CTX_wm_region` when `CTX_wm_menu` fails. `UI_block_draw` does this.
Author
Member

I wish I could help with this bug but unfortunately I don't know c/cpp.

In #47657#361558, @mont29 wrote:
Problem is, ui_list depends on a valid region available in context, and looks like context from popup do not have any region.

I noticed that when blender redraws dialogs it uses empty context object (region is None, space_data is None, etc). That behavior could cause other issues for context sensitive dialogs. Is it possible to "remember" context object that was used in invoke method and use it for redrawing?

I wish I could help with this bug but unfortunately I don't know c/cpp. > In #47657#361558, @mont29 wrote: > Problem is, ui_list depends on a valid region available in context, and looks like context from popup do not have any region. I noticed that when blender redraws dialogs it uses empty context object (region is None, space_data is None, etc). That behavior could cause other issues for context sensitive dialogs. Is it possible to "remember" context object that was used in invoke method and use it for redrawing?

Will commit that CTX_wm_menu 'hack' for now, but note that uilist remains a bit flacky in such usage (e.g. resize handle does not work that nice), would consider that a TODO though. Popups are not really meant to support such advanced UI items...

Will commit that CTX_wm_menu 'hack' for now, but note that uilist remains a bit flacky in such usage (e.g. resize handle does not work that nice), would consider that a TODO though. Popups are not really meant to support such advanced UI items...

This issue was referenced by blender/blender@bd335f13fe

This issue was referenced by blender/blender@bd335f13fe3d25e8e6bb472acb9c727d1629e582

Changed status from 'Open' to: 'Resolved'

Changed status from 'Open' to: 'Resolved'
Sign in to join this conversation.
No Milestone
No project
No Assignees
4 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender-addons#47657
No description provided.