[Bf-blender-cvs] [a34c25046b6] property-search-ui: Property Search: Refactor / simplify, and better layout

Hans Goudey noreply at git.blender.org
Sat Jun 13 04:02:07 CEST 2020


Commit: a34c25046b662ee0e178ac534bbf89bc205835f5
Author: Hans Goudey
Date:   Fri Jun 12 21:59:07 2020 -0400
Branches: property-search-ui
https://developer.blender.org/rBa34c25046b662ee0e178ac534bbf89bc205835f5

Property Search: Refactor / simplify, and better layout

The single column layout works much better now, as most of the code that
dealt with trying to remove empty layouts has been rewritten. The search
filter code is not a completely separate pass for the sake of simplicity.

Also, toggle buttons have their text replaced with the rna property name.

There branch is far from stable, and there's a tricky memory leak still to
track down as well.

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

M	source/blender/editors/include/UI_interface.h
M	source/blender/editors/interface/interface_intern.h
M	source/blender/editors/interface/interface_layout.c
M	source/blender/editors/screen/area.c

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

diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 8979ce1b6f1..8b3831596ca 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -1895,6 +1895,7 @@ void uiLayoutSetUnitsY(uiLayout *layout, float unit);
 void uiLayoutSetEmboss(uiLayout *layout, char emboss);
 void uiLayoutSetPropSep(uiLayout *layout, bool is_sep);
 void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep);
+void uiLayoutSetPropSearch(uiLayout *layout, bool is_searchable);
 int uiLayoutGetLocalDir(const uiLayout *layout);
 
 int uiLayoutGetOperatorContext(uiLayout *layout);
@@ -1914,6 +1915,7 @@ float uiLayoutGetUnitsY(uiLayout *layout);
 int uiLayoutGetEmboss(uiLayout *layout);
 bool uiLayoutGetPropSep(uiLayout *layout);
 bool uiLayoutGetPropDecorate(uiLayout *layout);
+bool uiLayoutGetPropSearch(uiLayout *layout);
 
 /* layout specifiers */
 uiLayout *uiLayoutRow(uiLayout *layout, bool align);
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index d80fb0ff51d..a5a471678e6 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -361,7 +361,7 @@ struct uiBlock {
 
   ListBase butstore; /* UI_butstore_* runtime function */
 
-  ListBase layouts;
+  ListBase layouts; /* Note: Should be called layout_roots. */
   struct uiLayout *curlayout;
 
   ListBase contexts;
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 92b1b21c207..d808af9f141 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -140,7 +140,7 @@ enum {
    * Enabled by default, depends on 'UI_ITEM_PROP_SEP'. */
   UI_ITEM_PROP_DECORATE = 1 << 5,
   UI_ITEM_PROP_DECORATE_NO_PAD = 1 << 6,
-  UI_ITEM_USE_SEARCH_FILTER = 1 << 7,
+  UI_ITEM_USE_SEARCH_FILTER = 1 << 7, /* HANS-TODO: Expose to RNA, comment. */
 };
 
 typedef struct uiButtonItem {
@@ -4985,6 +4985,16 @@ void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
   SET_FLAG_FROM_TEST(layout->item.flag, is_sep, UI_ITEM_PROP_DECORATE);
 }
 
+bool uiLayoutGetPropSearch(uiLayout *layout)
+{
+  return (layout->item.flag & UI_ITEM_USE_SEARCH_FILTER) != 0;
+}
+
+void uiLayoutSetPropSearch(uiLayout *layout, bool is_searchable)
+{
+  SET_FLAG_FROM_TEST(layout->item.flag, is_searchable, UI_ITEM_USE_SEARCH_FILTER);
+}
+
 bool uiLayoutGetActive(uiLayout *layout)
 {
   return layout->active;
@@ -5057,6 +5067,305 @@ int uiLayoutGetEmboss(uiLayout *layout)
 
 /** \} */
 
+/* -------------------------------------------------------------------- */
+/** \name Block Layout Search Filtering
+ * \{ */
+
+static void ui_layout_free(uiLayout *layout);
+
+/* Keep order the same as enum above. */
+const char *item_type_names[12] = {
+    "Button",      /* ITEM_BUTTON */
+    "Row",         /* ITEM_LAYOUT_ROW */
+    "Column",      /* ITEM_LAYOUT_COLUMN */
+    "Column Flow", /* ITEM_LAYOUT_COLUMN_FLOW */
+    "Row Flow",    /* ITEM_LAYOUT_ROW_FLOW */
+    "Grid Flow",   /* ITEM_LAYOUT_GRID_FLOW */
+    "Box",         /* ITEM_LAYOUT_BOX */
+    "Absolute",    /* ITEM_LAYOUT_ABSOLUTE */
+    "Split",       /* ITEM_LAYOUT_SPLIT */
+    "Overlap",     /* ITEM_LAYOUT_OVERLAP */
+    "Radial",      /* ITEM_LAYOUT_RADIAL */
+    "Root",        /* ITEM_LAYOUT_ROOT */
+};
+
+static void debug_print_button_item(uiButtonItem *button_item)
+{
+  uiBut *but = button_item->but;
+
+  if (but == NULL) {
+    printf("NULL BUT");
+  }
+  else if (but->str && but->str[0]) {
+    printf(but->str);
+  }
+  else if (!RNA_pointer_is_null(&but->rnapoin)) {
+    printf(RNA_property_ui_name(but->rnaprop));
+  }
+  else if (but->type == UI_BTYPE_SEPR) {
+    printf("(Padding)");
+  }
+  else {
+    printf("NOSTR");
+  }
+}
+
+static void debug_print_layout(uiItem *item, int depth)
+{
+  uiItemType type = item->type;
+
+  for (int i = 0; i < depth; i++) {
+    printf("| ");
+  }
+
+  printf("%s: ", item_type_names[item->type]);
+
+  if (type == ITEM_BUTTON) {
+    uiButtonItem *button_item = (uiButtonItem *)item;
+
+    debug_print_button_item(button_item);
+    printf("\n");
+  }
+  else {
+    uiLayout *layout = (uiLayout *)item;
+
+    if (layout->property_search_layout_temp_debug) {
+      printf(" (search layout)");
+    }
+    printf("\n");
+
+    if (layout->child_items_layout != NULL) {
+      debug_print_layout((uiItem *)layout->child_items_layout, depth + 2);
+    }
+    LISTBASE_FOREACH (uiItem *, child_item, &layout->items) {
+      debug_print_layout(child_item, depth + 1);
+    }
+  }
+}
+
+/**
+ * Free all layouts except if a child layout has a
+ *
+ * \return True if the layout was filtered.
+ */
+// static bool ui_layout_free_filtered(uiLayout *layout)
+// {
+//   bool children_filtered = true;
+//   bool filter_layout = layout->item.flag & UI_ITEM_USE_SEARCH_FILTER;
+//   LISTBASE_FOREACH_MUTABLE (uiItem *, item, &layout->items) {
+//     if (filter_layout && item->type == ITEM_BUTTON) {
+//       MEM_freeN(item);
+//     }
+//     else {
+//       children_filtered &= ui_layout_free_filtered((uiLayout *)item);
+//     }
+//   }
+
+//   filter_layout &= children_filtered;
+
+//   if (filter_layout) {
+//     MEM_freeN(layout);
+//   }
+
+//   return filter_layout;
+// }
+
+/**
+ * \return True if all buttons were tagged for removal.
+ */
+static bool ui_block_search_filter_tag_buttons(uiBlock *block)
+{
+  bool empty = true;
+  LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
+    /* Flag all buttons with no RNA property. This is probably too strict. */
+    if (but->rnaprop == NULL) {
+      but->flag |= UI_FILTERED;
+      continue;
+    }
+
+    /* Flag all label buttons, we don't want to re-display them. */
+    if (but->type == UI_BTYPE_LABEL) {
+      but->flag |= UI_FILTERED;
+    }
+
+    /* Do the shorter check first, in case the check returns true. */
+    if (BLI_strcasestr(but->str, block->search_filter) ||
+        BLI_strcasestr(RNA_property_ui_name(but->rnaprop), block->search_filter) ||
+        BLI_strcasestr(RNA_property_description(but->rnaprop), block->search_filter)) {
+      continue;
+    }
+
+    but->flag |= UI_FILTERED;
+    empty = false;
+  }
+  return empty;
+}
+
+static void move_button_to_search_filter_layout(uiItem *item,
+                                                uiLayout *source_layout,
+                                                uiLayout *labels,
+                                                uiLayout *properties)
+{
+  BLI_assert(item->type == ITEM_BUTTON);
+  uiButtonItem *button_item = (uiButtonItem *)item;
+
+  /* Move the item. */
+  BLI_remlink(&source_layout->items, item);
+  BLI_addtail(&properties->items, item);
+
+  /* Add a label if the text isn't contained in the button. */
+  if (button_item->but->rnaprop) {
+    char name[MAX_NAME];
+    strcpy(name, RNA_property_ui_name(button_item->but->rnaprop));
+    if (ELEM(button_item->but->type,
+             UI_BTYPE_CHECKBOX,
+             UI_BTYPE_TOGGLE_N,
+             UI_BTYPE_ICON_TOGGLE_N,
+             UI_BTYPE_CHECKBOX_N,
+             UI_BTYPE_LABEL)) {
+      /* Toggle buttons with no outside label and have their text changed to the RNA name. */
+      uiItemL(labels, "", ICON_NONE);
+      strcpy(button_item->but->str, name);
+    }
+    else {
+      uiItemL(labels, name, ICON_NONE);
+      /* Add a decorator for animatable properties. */
+      if (/* RNA_property_animateable(...) */ 1) {
+        // uiItemL(decorators, "", ICON_NONE);
+      }
+    }
+  }
+  else {
+    uiItemL(labels, "BUTTON NO RNA PROP", ICON_NONE);
+  }
+}
+
+static bool ui_search_layout_fill(uiLayout *labels, uiLayout *properties, uiLayout *layout)
+{
+  // printf("UI_LAYOUT_SEARCH_FILTER_CLEAN\n");
+  BLI_assert(layout->item.type != ITEM_BUTTON);
+
+  /* Don't affect the search layouts. */
+  if (ELEM(layout, labels, properties)) {
+    return true;
+  }
+
+  if ((layout->item.flag & UI_ITEM_USE_SEARCH_FILTER) == 0) {
+    return false;
+  }
+
+  bool empty = true;
+
+  /* Remove filtered button items. */
+  LISTBASE_FOREACH_MUTABLE (uiItem *, item, &layout->items) {
+    if (item->type == ITEM_BUTTON) {
+      uiButtonItem *button_item = (uiButtonItem *)item;
+
+      /* Free item and the button if it has been filtered. */
+      if (button_item->but->flag & UI_FILTERED) {
+        // ui_but_free(NULL, button_item->but);
+        button_item->but->flag |= UI_HIDDEN;
+        BLI_remlink(&layout->items, item);
+      }
+      else {
+        move_button_to_search_filter_layout(item, layout, labels, properties);
+        empty = false;
+      }
+    }
+    else {
+      /* If this item isn't a button it may contain other items, so recursively search them. */
+      uiLayout *child_layout = (uiLayout *)item;
+      empty &= ui_search_layout_fill(labels, properties, child_layout);
+    }
+  }
+
+  /* Also filter buttons in the #child_items_layout. */
+  if (layout->child_items_layout != NULL) {
+    empty &= ui_search_layout_fill(labels, properties, layout->child_items_layout);
+  }
+
+  return empty;
+}
+
+/**
+ * \return Whether the block was emptied by property search and should be removed.
+ */
+static bool ui_block_search_layout(uiBlock *block)
+{
+  /* Only continue if the block has the search filter set. */
+  if (!(block->search_filter && block->search_filter[0])) {
+    return false;
+  }
+
+  /* Apply search filter. */
+  ui_block_search_filter_tag_buttons(block);
+
+  bool all_roots_empty = true;
+  LISTBASE_FOREACH_MUTABLE (uiLayoutRoot *, root, &block->layouts) {
+    /* Find exceptions to search layout. */
+    if (root->type == UI_LAYOUT_HEADER) {
+      continue;
+    }
+
+    /* Build property search results layout. */
+    uiLayoutSetPropSep(root->layout, false);
+    uiLayout *split = uiLayoutSplit(root->layout, UI_ITEM_PROP_SEP_DIVIDE, false);
+    uiLayout *labels = uiLayoutColumn(split, false);
+    labels->property_search_layout_temp_debug = true;
+    uiLayoutSetAlignment(labels, UI_LAYOUT_ALIGN_RIGHT);
+    uiLayout *properties = uiLayoutColumn(split, false);
+    properties->pr

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list