[Bf-blender-cvs] [788d3804603] master: UI: UI list refactor & preparations for asset view template

Julian Eisel noreply at git.blender.org
Thu Jul 15 16:14:25 CEST 2021


Commit: 788d38046032736531cb77507e397cbea7993549
Author: Julian Eisel
Date:   Wed Jul 14 16:01:53 2021 +0200
Branches: master
https://developer.blender.org/rB788d38046032736531cb77507e397cbea7993549

UI: UI list refactor & preparations for asset view template

This is more of a first-pass refactor for the UI list template. More
improvements could be done, but that's better done separately. Main
purpose of this is to make the UI list code more manageable and ready
for the asset view template.

No functional changes for users.

* Split the huge template function into more manageable functions, with
  clear names and a few structs with high coherency.
* Move runtime data management to the template code, with a free
  callback called from BKE. This is UI data and should be managed at
  that level.
* Replace boolean arguments with bit-flags (easily extendable and more
  readable from the caller).
* Allow passing custom-data to the UI list for callbacks to access.
* Make list grip button for resizing optional.
* Put logic for generating the internal UI list identifier (stored in
  .blends) into function. This is a quite important bit and a later
  commit adds a related function. Good to have a clear API for this.
* Improve naming, comments, etc.

As part of further cleanups I'd like to move this to an own file.

===================================================================

M	source/blender/blenkernel/intern/screen.c
M	source/blender/editors/include/UI_interface.h
M	source/blender/editors/interface/interface_templates.c
M	source/blender/editors/space_node/drawnode.cc
M	source/blender/makesdna/DNA_screen_types.h
M	source/blender/makesrna/intern/rna_ui_api.c
M	source/blender/windowmanager/WM_api.h
M	source/blender/windowmanager/intern/wm_uilist_type.c

===================================================================

diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 73658c3184e..c3885b5dcf7 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -682,19 +682,13 @@ void BKE_area_region_free(SpaceType *st, ARegion *region)
   BKE_area_region_panels_free(&region->panels);
 
   LISTBASE_FOREACH (uiList *, uilst, &region->ui_lists) {
-    if (uilst->dyn_data) {
-      uiListDyn *dyn_data = uilst->dyn_data;
-      if (dyn_data->items_filter_flags) {
-        MEM_freeN(dyn_data->items_filter_flags);
-      }
-      if (dyn_data->items_filter_neworder) {
-        MEM_freeN(dyn_data->items_filter_neworder);
-      }
-      MEM_freeN(dyn_data);
+    if (uilst->dyn_data && uilst->dyn_data->free_runtime_data_fn) {
+      uilst->dyn_data->free_runtime_data_fn(uilst);
     }
     if (uilst->properties) {
       IDP_FreeProperty(uilst->properties);
     }
+    MEM_SAFE_FREE(uilst->dyn_data);
   }
 
   if (region->gizmo_map != NULL) {
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 802c175492f..55d0c5c4342 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -25,6 +25,7 @@
 
 #include "BLI_compiler_attrs.h"
 #include "BLI_sys_types.h" /* size_t */
+#include "BLI_utildefines.h"
 #include "UI_interface_icons.h"
 
 #ifdef __cplusplus
@@ -2194,6 +2195,17 @@ void uiTemplateCacheFile(uiLayout *layout,
 
 /* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */
 #define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list"
+enum uiTemplateListFlags {
+  UI_TEMPLATE_LIST_FLAG_NONE = 0,
+  UI_TEMPLATE_LIST_SORT_REVERSE = (1 << 0),
+  UI_TEMPLATE_LIST_SORT_LOCK = (1 << 1),
+  /* Don't allow resizing the list, i.e. don't add the grip button. */
+  UI_TEMPLATE_LIST_NO_GRIP = (1 << 2),
+
+  UI_TEMPLATE_LIST_FLAGS_LAST
+};
+ENUM_OPERATORS(enum uiTemplateListFlags, UI_TEMPLATE_LIST_FLAGS_LAST);
+
 void uiTemplateList(uiLayout *layout,
                     struct bContext *C,
                     const char *listtype_name,
@@ -2207,8 +2219,23 @@ void uiTemplateList(uiLayout *layout,
                     int maxrows,
                     int layout_type,
                     int columns,
-                    bool sort_reverse,
-                    bool sort_lock);
+                    enum uiTemplateListFlags flags);
+struct uiList *uiTemplateList_ex(uiLayout *layout,
+                                 struct bContext *C,
+                                 const char *listtype_name,
+                                 const char *list_id,
+                                 struct PointerRNA *dataptr,
+                                 const char *propname,
+                                 struct PointerRNA *active_dataptr,
+                                 const char *active_propname,
+                                 const char *item_dyntip_propname,
+                                 int rows,
+                                 int maxrows,
+                                 int layout_type,
+                                 int columns,
+                                 enum uiTemplateListFlags flags,
+                                 void *customdata);
+
 void uiTemplateNodeLink(uiLayout *layout,
                         struct bContext *C,
                         struct bNodeTree *ntree,
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 9c17486aea4..30f72e75979 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -5828,36 +5828,283 @@ static void uilist_filter_items_default(struct uiList *ui_list,
   }
 }
 
+static void uilist_free_dyn_data(uiList *ui_list)
+{
+  uiListDyn *dyn_data = ui_list->dyn_data;
+  if (!dyn_data) {
+    return;
+  }
+
+  MEM_SAFE_FREE(dyn_data->items_filter_flags);
+  MEM_SAFE_FREE(dyn_data->items_filter_neworder);
+  MEM_SAFE_FREE(dyn_data->customdata);
+}
+
+/**
+ * The validated data that was passed to #uiTemplateList (typically through Python).
+ * Populated through #ui_template_list_data_retrieve().
+ */
+typedef struct {
+  PointerRNA dataptr;
+  PropertyRNA *prop;
+  PointerRNA active_dataptr;
+  PropertyRNA *activeprop;
+  const char *item_dyntip_propname;
+
+  /* Index as stored in the input property. I.e. the index before sorting. */
+  int active_item_idx;
+} TemplateListInputData;
+
+/**
+ * Internal wrapper for a single item in the list (well, actually stored as a vector).
+ */
 typedef struct {
   PointerRNA item;
   int org_idx;
   int flt_flag;
 } _uilist_item;
 
+/**
+ * Container for the item vector and additional info.
+ */
+typedef struct {
+  _uilist_item *item_vec;
+  /* Index of the active item following visual order. I.e. unlike
+   * TemplateListInputData.active_item_idx, this is the index after sorting. */
+  int active_item_idx;
+  int tot_items;
+} TemplateListItems;
+
+typedef struct {
+  uiListDrawItemFunc draw_item;
+  uiListDrawFilterFunc draw_filter;
+
+  int rows;
+  int maxrows;
+  int columns;
+} TemplateListLayoutDrawData;
+
 typedef struct {
   int visual_items; /* Visual number of items (i.e. number of items we have room to display). */
   int start_idx;    /* Index of first item to display. */
   int end_idx;      /* Index of last item to display + 1. */
-} uiListLayoutdata;
+} TemplateListVisualInfo;
+
+/**
+ * Validate input parameters and initialize \a r_data from that. Plus find the list-type and return
+ * it in \a r_list_type.
+ *
+ * \return false if the input data isn't valid. Will also raise an RNA warning in that case.
+ */
+static bool ui_template_list_data_retrieve(const char *listtype_name,
+                                           const char *list_id,
+                                           PointerRNA *dataptr,
+                                           const char *propname,
+                                           PointerRNA *active_dataptr,
+                                           const char *active_propname,
+                                           const char *item_dyntip_propname,
+                                           TemplateListInputData *r_input_data,
+                                           uiListType **r_list_type)
+{
+  memset(r_input_data, 0, sizeof(*r_input_data));
+
+  /* Forbid default UI_UL_DEFAULT_CLASS_NAME list class without a custom list_id! */
+  if (STREQ(UI_UL_DEFAULT_CLASS_NAME, listtype_name) && !(list_id && list_id[0])) {
+    RNA_warning("template_list using default '%s' UIList class must provide a custom list_id",
+                UI_UL_DEFAULT_CLASS_NAME);
+    return false;
+  }
+
+  if (!active_dataptr->data) {
+    RNA_warning("No active data");
+    return false;
+  }
+
+  r_input_data->dataptr = *dataptr;
+  if (dataptr->data) {
+    r_input_data->prop = RNA_struct_find_property(dataptr, propname);
+    if (!r_input_data->prop) {
+      RNA_warning("Property not found: %s.%s", RNA_struct_identifier(dataptr->type), propname);
+      return false;
+    }
+  }
+
+  r_input_data->active_dataptr = *active_dataptr;
+  r_input_data->activeprop = RNA_struct_find_property(active_dataptr, active_propname);
+  if (!r_input_data->activeprop) {
+    RNA_warning(
+        "Property not found: %s.%s", RNA_struct_identifier(active_dataptr->type), active_propname);
+    return false;
+  }
+
+  if (r_input_data->prop) {
+    const PropertyType type = RNA_property_type(r_input_data->prop);
+    if (type != PROP_COLLECTION) {
+      RNA_warning("Expected a collection data property");
+      return false;
+    }
+  }
+
+  const PropertyType activetype = RNA_property_type(r_input_data->activeprop);
+  if (activetype != PROP_INT) {
+    RNA_warning("Expected an integer active data property");
+    return false;
+  }
+
+  /* Find the uiList type. */
+  if (!(*r_list_type = WM_uilisttype_find(listtype_name, false))) {
+    RNA_warning("List type %s not found", listtype_name);
+    return false;
+  }
+
+  r_input_data->active_item_idx = RNA_property_int_get(&r_input_data->active_dataptr,
+                                                       r_input_data->activeprop);
+  r_input_data->item_dyntip_propname = item_dyntip_propname;
+
+  return true;
+}
+
+static void ui_template_list_collect_items(PointerRNA *list_ptr,
+                                           PropertyRNA *list_prop,
+                                           uiListDyn *dyn_data,
+                                           int filter_exclude,
+                                           bool order_reverse,
+                                           int activei,
+                                           TemplateListItems *r_items)
+{
+  int i = 0;
+  int reorder_i = 0;
+  bool activei_mapping_pending = true;
+
+  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)) {
+      int new_order_idx;
+      if (dyn_data->items_filter_neworder) {
+        new_order_idx = dyn_data->items_filter_neworder[reorder_i++];
+        new_order_idx = order_reverse ? dyn_data->items_shown - new_order_idx - 1 : new_order_idx;
+      }
+      else {
+        new_order_idx = order_reverse ? dyn_data->items_shown - ++reorder_i : reorder_i++;
+      }
+      // printf("%s: ii: %d\n", __func__, ii);
+      r_items->item_vec[new_order_idx].item = itemptr;
+      r_items->item_vec[new_order_idx].org_idx = i;
+      r_items->item_vec[new_order_idx].flt_flag = dyn_data->items_filter_flags ?
+                                                      dyn_data->items_filter_flags[i] :
+                                                      0;
+
+      if (activei_mapping_pending && activei == i) {
+        activei = new_order_idx;
+        /* So that we do not map again activei! */
+        activei_mapping_pending = false;
+      }
+#if 0 /* For now, do not alter active element, even if it will be hidden... */
+          else if (activei < i) {
+            /* We do not want an active but invisible item!
+             * Only exception is 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list