[Bf-blender-cvs] [9d9c879f4bd] master: Cleanup: Move UI list template code to own file (C++)

Julian Eisel noreply at git.blender.org
Thu Jul 15 19:09:53 CEST 2021


Commit: 9d9c879f4bdf05c92826023131e7eb2a57c06102
Author: Julian Eisel
Date:   Thu Jul 15 16:56:18 2021 +0200
Branches: master
https://developer.blender.org/rB9d9c879f4bdf05c92826023131e7eb2a57c06102

Cleanup: Move UI list template code to own file (C++)

This move was already prepared with 788d38046032 and 26b098c04fbe. The
template is quite big already, better to give it its own file. Plus it
could use some C++ features like RAII and maybe some more object
oriented code. I plan further refactoring there.

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

M	source/blender/editors/interface/interface_template_list.cc
M	source/blender/editors/interface/interface_templates.c

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

diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc
index 334fc7ff057..dfbf64b79af 100644
--- a/source/blender/editors/interface/interface_template_list.cc
+++ b/source/blender/editors/interface/interface_template_list.cc
@@ -16,17 +16,1296 @@
 
 /** \file
  * \ingroup edinterface
- *
- * TODO: The UI list template implementation should be moved here.
  */
 
-#include "WM_api.h"
+#include <cstdlib>
+#include <cstring>
+
+#include "BLI_fnmatch.h"
+#include "BLI_listbase.h"
+#include "BLI_math_base.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_screen.h"
+
+#include "BLT_translation.h"
+
+#include "ED_screen.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
 
 #include "UI_interface.h"
+#include "UI_view2d.h"
+
+#include "WM_api.h"
 
 #include "interface_intern.h"
 
+/**
+ * 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. */
+} TemplateListVisualInfo;
+
+static void uilist_draw_item_default(struct uiList *ui_list,
+                                     struct bContext *UNUSED(C),
+                                     struct uiLayout *layout,
+                                     struct PointerRNA *UNUSED(dataptr),
+                                     struct PointerRNA *itemptr,
+                                     int icon,
+                                     struct PointerRNA *UNUSED(active_dataptr),
+                                     const char *UNUSED(active_propname),
+                                     int UNUSED(index),
+                                     int UNUSED(flt_flag))
+{
+  PropertyRNA *nameprop = RNA_struct_name_property(itemptr->type);
+
+  /* Simplest one! */
+  switch (ui_list->layout_type) {
+    case UILST_LAYOUT_GRID:
+      uiItemL(layout, "", icon);
+      break;
+    case UILST_LAYOUT_DEFAULT:
+    case UILST_LAYOUT_COMPACT:
+    default:
+      if (nameprop) {
+        uiItemFullR(layout, itemptr, nameprop, RNA_NO_INDEX, 0, UI_ITEM_R_NO_BG, "", icon);
+      }
+      else {
+        uiItemL(layout, "", icon);
+      }
+      break;
+  }
+}
+
+static void uilist_draw_filter_default(struct uiList *ui_list,
+                                       struct bContext *UNUSED(C),
+                                       struct uiLayout *layout)
+{
+  PointerRNA listptr;
+  RNA_pointer_create(NULL, &RNA_UIList, ui_list, &listptr);
+
+  uiLayout *row = uiLayoutRow(layout, false);
+
+  uiLayout *subrow = uiLayoutRow(row, true);
+  uiItemR(subrow, &listptr, "filter_name", 0, "", ICON_NONE);
+  uiItemR(subrow,
+          &listptr,
+          "use_filter_invert",
+          UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY,
+          "",
+          ICON_ARROW_LEFTRIGHT);
+
+  if ((ui_list->filter_sort_flag & UILST_FLT_SORT_LOCK) == 0) {
+    subrow = uiLayoutRow(row, true);
+    uiItemR(subrow,
+            &listptr,
+            "use_filter_sort_alpha",
+            UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY,
+            "",
+            ICON_NONE);
+    uiItemR(subrow,
+            &listptr,
+            "use_filter_sort_reverse",
+            UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY,
+            "",
+            (ui_list->filter_sort_flag & UILST_FLT_SORT_REVERSE) ? ICON_SORT_DESC : ICON_SORT_ASC);
+  }
+}
+
+typedef struct {
+  char name[MAX_IDPROP_NAME];
+  int org_idx;
+} StringCmp;
+
+static int cmpstringp(const void *p1, const void *p2)
+{
+  /* Case-insensitive comparison. */
+  return BLI_strcasecmp(((StringCmp *)p1)->name, ((StringCmp *)p2)->name);
+}
+
+static void uilist_filter_items_default(struct uiList *ui_list,
+                                        struct bContext *UNUSED(C),
+                                        struct PointerRNA *dataptr,
+                                        const char *propname)
+{
+  uiListDyn *dyn_data = ui_list->dyn_data;
+  PropertyRNA *prop = RNA_struct_find_property(dataptr, propname);
+
+  const char *filter_raw = ui_list->filter_byname;
+  char *filter = (char *)filter_raw, filter_buff[32], *filter_dyn = NULL;
+  const bool filter_exclude = (ui_list->filter_flag & UILST_FLT_EXCLUDE) != 0;
+  const bool order_by_name = (ui_list->filter_sort_flag & UILST_FLT_SORT_MASK) ==
+                             UILST_FLT_SORT_ALPHA;
+  const int len = RNA_property_collection_length(dataptr, prop);
+
+  dyn_data->items_shown = dyn_data->items_len = len;
+
+  if (len && (order_by_name || filter_raw[0])) {
+    StringCmp *names = NULL;
+    int order_idx = 0, i = 0;
+
+    if (order_by_name) {
+      names = static_cast<StringCmp *>(MEM_callocN(sizeof(StringCmp) * len, "StringCmp"));
+    }
+    if (filter_raw[0]) {
+      const size_t slen = strlen(filter_raw);
+
+      dyn_data->items_filter_flags = static_cast<int *>(
+          MEM_callocN(sizeof(int) * len, "items_filter_flags"));
+      dyn_data->items_shown = 0;
+
+      /* Implicitly add heading/trailing wildcards if needed. */
+      if (slen + 3 <= sizeof(filter_buff)) {
+        filter = filter_buff;
+      }
+      else {
+        filter = filter_dyn = static_cast<char *>(
+            MEM_mallocN((slen + 3) * sizeof(char), "filter_dyn"));
+      }
+      BLI_strncpy_ensure_pad(filter, filter_raw, '*', slen + 3);
+    }
+
+    RNA_PROP_BEGIN (dataptr, itemptr, prop) {
+      bool do_order = false;
+
+      char *namebuf = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL);
+      const char *name = namebuf ? namebuf : "";
+
+      if (filter[0]) {
+        /* Case-insensitive! */
+        if (fnmatch(filter, name, FNM_CASEFOLD) == 0) {
+          dyn_data->items_filter_flags[i] = UILST_FLT_ITEM;
+          if (!filter_exclude) {
+            dyn_data->items_shown++;
+            do_order = order_by_name;
+          }
+          // printf("%s: '%s' matches '%s'\n", __func__, name, filter);
+        }
+        else if (filter_exclude) {
+          dyn_data->items_shown++;
+          do_order = order_by_name;
+        }
+      }
+      else {
+        do_order = order_by_name;
+      }
+
+      if (do_order) {
+        names[order_idx].org_idx = order_idx;
+        BLI_strncpy(names[order_idx++].name, name, MAX_IDPROP_NAME);
+      }
+
+      /* free name */
+      if (namebuf) {
+        MEM_freeN(namebuf);
+      }
+      i++;
+    }
+    RNA_PROP_END;
+
+    if (order_by_name) {
+      int new_idx;
+      /* NOTE: order_idx equals either to ui_list->items_len if no filtering done,
+       *       or to ui_list->items_shown if filter is enabled,
+       *       or to (ui_list->items_len - ui_list->items_shown) if filtered items are excluded.
+       *       This way, we only sort items we actually intend to draw!
+       */
+      qsort(names, order_idx, sizeof(StringCmp), cmpstringp);
+
+      dyn_data->items_filter_neworder = static_cast<int *>(
+          MEM_mallocN(sizeof(int) * order_idx, "items_filter_neworder"));
+      for (new_idx = 0; new_idx < order_idx; new_idx++) {
+        dyn_data->items_filter_neworder[names[new_idx].org_idx] = new_idx;
+      }
+    }
+
+    if (filter_dyn) {
+      MEM_freeN(filter_dyn);
+    }
+    if (names) {
+      MEM_freeN(names);
+    }
+  }
+}
+
+static void uilist_free_dyn_data(uiList *ui_list)
+{
+  uiListDyn *dyn_data = ui_list->dyn_data;
+  if (!dyn_data) {
+    return;
+  }
+
+  if (dyn_data->custom_activate_opptr) {
+    WM_operator_properties_free(dyn_data->custom_activate_opptr);
+    MEM_freeN(dyn_data->custom_activate_opptr);
+  }
+  if (dyn_data->custom_drag_opptr) {
+    WM_operator_properties_free(dyn_data->custom_drag_opptr);
+    MEM_freeN(dyn_data->custom_drag_opptr);
+  }
+
+  MEM_SAFE_FREE(dyn_data->items_filter_flags);
+  MEM_SAFE_FREE(dyn_data->items_filter_neworder);
+  MEM_SAFE_FREE(dyn_data->customdata);
+}
+
+/**
+ * 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 li

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list