Fix #108078: Crash when inverting results in pose library sidebar

a958ae36e8 introduced support for UI lists to reference items that would
never be shown, regardless of filter settings. This was to skip assets
in the asset view template that were not of the requested type. UI list
sorting code wasn't updated to account for such items that should be
entirely ignored.

Pull Request: https://projects.blender.org/blender/blender/pulls/109157
This commit is contained in:
Julian Eisel 2024-03-22 12:25:39 +01:00
parent 365f5f8823
commit 303014bfac
6 changed files with 38 additions and 18 deletions

View File

@ -136,8 +136,9 @@ class MESH_UL_vgroups_slow(bpy.types.UIList):
def filter_items(self, context, data, propname):
# This function gets the collection property (as the usual tuple (data, propname)), and must return two lists:
# * The first one is for filtering, it must contain 32bit integers were self.bitflag_filter_item marks the
# matching item as filtered (i.e. to be shown), and 31 other bits are free for custom needs. Here we use the
# first one to mark VGROUP_EMPTY.
# matching item as filtered (i.e. to be shown). The upper 16 bits (including self.bitflag_filter_item) are
# reserved for internal use, the lower 16 bits are free for custom use. Here we use the first bit to mark
# VGROUP_EMPTY.
# * The second one is for reordering, it must return a list containing the new indices of the items (which
# gives us a mapping org_idx -> new_idx).
# Please note that the default UI_UL_list defines helper functions for common tasks (see its doc for more info).

View File

@ -30,8 +30,9 @@ class MESH_UL_mylist(bpy.types.UIList):
def filter_items(self, context, data, propname):
# This function gets the collection property (as the usual tuple (data, propname)), and must return two lists:
# * The first one is for filtering, it must contain 32bit integers were self.bitflag_filter_item marks the
# matching item as filtered (i.e. to be shown), and 31 other bits are free for custom needs. Here we use the
# first one to mark VGROUP_EMPTY.
# matching item as filtered (i.e. to be shown). The upper 16 bits (including self.bitflag_filter_item) are
# reseverd for internal use, the lower 16 bits are free for custom use. Here we use the first bit to mark
# VGROUP_EMPTY.
# * The second one is for reordering, it must return a list containing the new indices of the items (which
# gives us a mapping org_idx -> new_idx).
# Please note that the default UI_UL_list defines helper functions for common tasks (see its doc for more info).

View File

@ -9774,7 +9774,8 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *regi
for (int i = 0; i < len; i++) {
if (!dyn_data->items_filter_flags ||
((dyn_data->items_filter_flags[i] & UILST_FLT_ITEM) ^ filter_exclude))
(((dyn_data->items_filter_flags[i] & UILST_FLT_ITEM_NEVER_SHOW) == 0) &&
(dyn_data->items_filter_flags[i] & UILST_FLT_ITEM) ^ filter_exclude))
{
org_order[new_order ? new_order[++org_idx] : ++org_idx] = i;
if (i == value) {

View File

@ -250,7 +250,7 @@ void UI_list_filter_and_sort_items(uiList *ui_list,
const eUIListFilterResult filter_result = item_filter_fn(itemptr, name, i);
if (filter_result == UI_LIST_ITEM_NEVER_SHOW) {
/* Pass. */
dyn_data->items_filter_flags[i] = UILST_FLT_ITEM_NEVER_SHOW;
}
else if (filter_result == UI_LIST_ITEM_FILTER_MATCHES) {
dyn_data->items_filter_flags[i] = UILST_FLT_ITEM;
@ -431,7 +431,8 @@ static void ui_template_list_collect_items(PointerRNA *list_ptr,
RNA_PROP_BEGIN (list_ptr, itemptr, list_prop) {
if (!dyn_data->items_filter_flags ||
((dyn_data->items_filter_flags[i] & UILST_FLT_ITEM) ^ filter_exclude))
(((dyn_data->items_filter_flags[i] & UILST_FLT_ITEM_NEVER_SHOW) == 0) &&
((dyn_data->items_filter_flags[i] & UILST_FLT_ITEM) ^ filter_exclude)))
{
int new_order_idx;
if (dyn_data->items_filter_neworder) {

View File

@ -275,7 +275,9 @@ typedef struct uiListDyn {
void *customdata;
/* Filtering data. */
/** Items_len length. */
/** This bitfield is effectively exposed in Python, and scripts are explicitly allowed to assign
* any own meaning to the lower 16 ones.
* #items_len length. */
int *items_filter_flags;
/** Org_idx -> new_idx, items_len length. */
int *items_filter_neworder;
@ -626,10 +628,18 @@ enum {
/** Value (in number of items) we have to go below minimum shown items to enable auto size. */
#define UI_LIST_AUTO_SIZE_THRESHOLD 1
/* uiList filter flags (dyn_data) */
/* WARNING! Those values are used by integer RNA too, which does not handle well values > INT_MAX.
* So please do not use 32nd bit here. */
/** uiList filter flags (dyn_data)
*
* \warning Lower 16 bits are meant for custom use in Python, don't use them here! Only use the
* higher 16 bits.
* \warning Those values are used by integer RNA too, which does not handle well values > INT_MAX.
* So please do not use 32nd bit here.
*/
enum {
/* Don't use (1 << 0) to (1 << 15) here! See warning above. */
/* Filtering returned #UI_LIST_ITEM_NEVER_SHOW. */
UILST_FLT_ITEM_NEVER_SHOW = (1 << 16),
UILST_FLT_ITEM = 1 << 30, /* This item has passed the filter process successfully. */
};

View File

@ -625,7 +625,10 @@ static void uilist_filter_items(uiList *ui_list,
int t_idx, t_ni, prev_ni;
flt_data->items_shown = 0;
for (i = 0, shown_idx = 0; i < len; i++) {
if ((filter_flags[i] & UILST_FLT_ITEM) ^ filter_exclude) {
if (filter_flags[i] & UILST_FLT_ITEM_NEVER_SHOW) {
BLI_assert_msg(false, "Bit reserved for internal use");
}
else if ((filter_flags[i] & UILST_FLT_ITEM) ^ filter_exclude) {
filter_neworder[shown_idx++] = filter_neworder[i];
}
}
@ -653,7 +656,10 @@ static void uilist_filter_items(uiList *ui_list,
/* we still have to set flt_data->items_shown... */
flt_data->items_shown = 0;
for (i = 0; i < len; i++) {
if ((filter_flags[i] & UILST_FLT_ITEM) ^ filter_exclude) {
if (filter_flags[i] & UILST_FLT_ITEM_NEVER_SHOW) {
/* Pass. */
}
else if ((filter_flags[i] & UILST_FLT_ITEM) ^ filter_exclude) {
flt_data->items_shown++;
}
}
@ -2073,11 +2079,11 @@ static void rna_def_uilist(BlenderRNA *brna)
prop = RNA_def_property(func, "filter_flags", PROP_INT, PROP_UNSIGNED);
RNA_def_property_flag(prop, PropertyFlag(PARM_REQUIRED | PROP_DYNAMIC));
RNA_def_property_array(prop, 1); /* XXX Dummy value, default 0 does not work */
RNA_def_property_ui_text(
prop,
"",
"An array of filter flags, one for each item in the collection (NOTE: "
"FILTER_ITEM bit is reserved, it defines whether the item is shown or not)");
RNA_def_property_ui_text(prop,
"",
"An array of filter flags, one for each item in the collection (NOTE: "
"The upper 16 bits, including FILTER_ITEM, are reserved, only use the "
"lower 16 bits for custom usages).");
RNA_def_function_output(func, prop);
prop = RNA_def_property(func, "filter_neworder", PROP_INT, PROP_UNSIGNED);
RNA_def_property_flag(prop, PropertyFlag(PARM_REQUIRED | PROP_DYNAMIC));