[Bf-blender-cvs] [7c633686e99] master: Property Search: Find results in all tabs

Hans Goudey noreply at git.blender.org
Tue Oct 13 20:11:08 CEST 2020


Commit: 7c633686e99512d33391f30e4602213ed3890802
Author: Hans Goudey
Date:   Tue Oct 13 13:10:41 2020 -0500
Branches: master
https://developer.blender.org/rB7c633686e99512d33391f30e4602213ed3890802

Property Search: Find results in all tabs

This patch enables property search for all tabs in the property editor.
To make interaction faster, if the editor's current tab doesn't have a
result, the current tab changes to the next tab that has a match.

This patch implements basic code that only searches panels.
While we could run the existing "single tab" property search for every
tab, that would also do everything else related to the layout pass,
which would be less efficient, and maybe more complicated to maintain.

The search match status for every current tab of the property editor is
stored in a runtime bitfield and them displayed later by dimming icons
in the tab selector panel to the left. Using `BLI_bitmap` properly in
the runtime struct required moving it to `buttons_intern.h` and
adding a small API to access the search filter instead.

To make sure the editor isn't influenced by anything that happens while
building the layout for other tabs, most of the context is duplicated
and the new search is run in the duplicated editor.

Note that the tool settings tab works slightly different than the other
tabs, so I've disabled searching it for this commit. That would be a
relatively simple improvement, but would just require a bit of
refactoring of existing code.

Differential Revision: https://developer.blender.org/D8859

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

M	release/scripts/startup/bl_ui/space_properties.py
M	source/blender/editors/include/ED_buttons.h
M	source/blender/editors/include/ED_screen.h
M	source/blender/editors/include/UI_interface.h
M	source/blender/editors/interface/interface_layout.c
M	source/blender/editors/screen/area.c
M	source/blender/editors/space_buttons/buttons_intern.h
M	source/blender/editors/space_buttons/space_buttons.c
M	source/blender/makesdna/DNA_space_types.h
M	source/blender/makesrna/intern/rna_space.c

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

diff --git a/release/scripts/startup/bl_ui/space_properties.py b/release/scripts/startup/bl_ui/space_properties.py
index ff25b8cd2fa..fe5057bed5d 100644
--- a/release/scripts/startup/bl_ui/space_properties.py
+++ b/release/scripts/startup/bl_ui/space_properties.py
@@ -53,7 +53,11 @@ class PROPERTIES_PT_navigation_bar(Panel):
 
         layout.scale_x = 1.4
         layout.scale_y = 1.4
-        layout.prop_tabs_enum(view, "context", icon_only=True)
+        if view.search_filter:
+            layout.prop_tabs_enum(view, "context", data_highlight=view,
+                property_highlight="tab_search_results", icon_only=True)
+        else:
+            layout.prop_tabs_enum(view, "context", icon_only=True)
 
 
 classes = (
diff --git a/source/blender/editors/include/ED_buttons.h b/source/blender/editors/include/ED_buttons.h
index a4cd2525af3..5d153757900 100644
--- a/source/blender/editors/include/ED_buttons.h
+++ b/source/blender/editors/include/ED_buttons.h
@@ -29,6 +29,11 @@ extern "C" {
 struct SpaceProperties;
 
 int ED_buttons_tabs_list(struct SpaceProperties *sbuts, short *context_tabs_array);
+bool ED_buttons_tab_has_search_result(struct SpaceProperties *sbuts, const int index);
+
+void ED_buttons_search_string_set(struct SpaceProperties *sbuts, const char *value);
+int ED_buttons_search_string_length(struct SpaceProperties *sbuts);
+const char *ED_buttons_search_string_get(struct SpaceProperties *sbuts);
 
 #ifdef __cplusplus
 }
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 53554e3f34c..b8500ba0c37 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -92,6 +92,11 @@ void ED_region_panels_layout_ex(const struct bContext *C,
                                 struct ListBase *paneltypes,
                                 const char *contexts[],
                                 const char *category_override);
+bool ED_region_property_search(const struct bContext *C,
+                               struct ARegion *region,
+                               struct ListBase *paneltypes,
+                               const char *contexts[],
+                               const char *category_override);
 
 void ED_region_panels_layout(const struct bContext *C, struct ARegion *region);
 void ED_region_panels_draw(const struct bContext *C, struct ARegion *region);
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 94095d04271..2c8518de700 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -1874,6 +1874,7 @@ uiLayout *UI_block_layout(uiBlock *block,
                           const struct uiStyle *style);
 void UI_block_layout_set_current(uiBlock *block, uiLayout *layout);
 void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y);
+void UI_block_layout_free(uiBlock *block);
 
 bool UI_block_apply_search_filter(uiBlock *block, const char *search_filter);
 
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 98b1c020d95..3e276a69277 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -5600,6 +5600,19 @@ void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv)
   layout->root->argv = argv;
 }
 
+/**
+ * Used for property search when the layout process needs to be cancelled in order to avoid
+ * computing the locations for buttons, but the layout items created while adding the buttons
+ * must still be freed.
+ */
+void UI_block_layout_free(uiBlock *block)
+{
+  LISTBASE_FOREACH_MUTABLE (uiLayoutRoot *, root, &block->layouts) {
+    ui_layout_free(root->layout);
+    MEM_freeN(root);
+  }
+}
+
 void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y)
 {
   BLI_assert(block->active);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 6fa9d203bba..fd94eea337f 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -48,6 +48,7 @@
 #include "WM_toolsystem.h"
 #include "WM_types.h"
 
+#include "ED_buttons.h"
 #include "ED_screen.h"
 #include "ED_screen_types.h"
 #include "ED_space_api.h"
@@ -765,7 +766,7 @@ const char *ED_area_region_search_filter_get(const ScrArea *area, const ARegion
   if (area->spacetype == SPACE_PROPERTIES) {
     SpaceProperties *sbuts = area->spacedata.first;
     if (region->regiontype == RGN_TYPE_WINDOW) {
-      return sbuts->runtime->search_string;
+      return ED_buttons_search_string_get(sbuts);
     }
   }
 
@@ -3074,6 +3075,149 @@ void ED_region_panels_init(wmWindowManager *wm, ARegion *region)
   WM_event_add_keymap_handler(&region->handlers, keymap);
 }
 
+/**
+ * Check whether any of the buttons generated by the \a panel_type's
+ * layout callbacks match the \a search_filter.
+ *
+ * \param panel: If non-NULL, use this instead of adding a new panel for the \a panel_type.
+ */
+static bool panel_property_search(const bContext *C,
+                                  ARegion *region,
+                                  const uiStyle *style,
+                                  Panel *panel,
+                                  PanelType *panel_type,
+                                  const char *search_filter)
+{
+  uiBlock *block = UI_block_begin(C, region, panel_type->idname, UI_EMBOSS);
+  UI_block_set_search_only(block, true);
+
+  if (panel == NULL) {
+    bool open; /* Dummy variable. */
+    panel = UI_panel_begin(region, &region->panels, block, panel_type, panel, &open);
+  }
+
+  /* Build the layouts. Because they are only used for search,
+   * they don't need any of the proper style or layout information. */
+  if (panel->type->draw_header_preset != NULL) {
+    panel->layout = UI_block_layout(
+        block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, 0, 0, 0, 0, 0, style);
+    panel_type->draw_header_preset(C, panel);
+  }
+  if (panel->type->draw_header != NULL) {
+    panel->layout = UI_block_layout(
+        block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, 0, 0, 0, 0, 0, style);
+    panel_type->draw_header(C, panel);
+  }
+  if (LIKELY(panel->type->draw != NULL)) {
+    panel->layout = UI_block_layout(
+        block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, 0, 0, 0, style);
+    panel_type->draw(C, panel);
+  }
+
+  UI_block_layout_free(block);
+
+  /* We could check after each layout to increase the likelyhood of returning early,
+   * but that probably wouldn't make much of a difference anyway. */
+  if (UI_block_apply_search_filter(block, search_filter)) {
+    return true;
+  }
+
+  LISTBASE_FOREACH (LinkData *, link, &panel_type->children) {
+    PanelType *panel_type_child = link->data;
+    if (!panel_type_child->poll || panel_type_child->poll(C, panel_type_child)) {
+      /* Search for the existing child panel here because it might be an instanced
+       * child panel with a custom data field that will be needed to build the layout. */
+      Panel *child_panel = UI_panel_find_by_type(&panel->children, panel_type_child);
+      if (panel_property_search(C, region, style, child_panel, panel_type_child, search_filter)) {
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+/**
+ * Build the same panel list as #ED_region_panels_layout_ex and checks whether any
+ * of the panels contain a search result based on the area / region's search filter.
+ */
+bool ED_region_property_search(const bContext *C,
+                               ARegion *region,
+                               ListBase *paneltypes,
+                               const char *contexts[],
+                               const char *category_override)
+{
+  ScrArea *area = CTX_wm_area(C);
+  WorkSpace *workspace = CTX_wm_workspace(C);
+  const uiStyle *style = UI_style_get_dpi();
+  const char *search_filter = ED_area_region_search_filter_get(area, region);
+
+  LinkNode *panel_types_stack = NULL;
+  LISTBASE_FOREACH_BACKWARD (PanelType *, pt, paneltypes) {
+    if (panel_add_check(C, workspace, contexts, category_override, pt)) {
+      BLI_linklist_prepend_alloca(&panel_types_stack, pt);
+    }
+  }
+
+  const char *category = NULL;
+  bool use_category_tabs = (category_override == NULL) && region_uses_category_tabs(area, region);
+  if (use_category_tabs) {
+    category = region_panels_collect_categories(region, panel_types_stack, &use_category_tabs);
+  }
+
+  /* Run property search for each panel, stopping if a result is found. */
+  bool has_result = true;
+  bool has_instanced_panel = false;
+  for (LinkNode *pt_link = panel_types_stack; pt_link; pt_link = pt_link->next) {
+    PanelType *panel_type = pt_link->link;
+    /* Note that these checks are duplicated from #ED_region_panels_layout_ex. */
+    if (panel_type->flag & PNL_INSTANCED) {
+      has_instanced_panel = true;
+      continue;
+    }
+
+    if (use_category_tabs) {
+      if (panel_type->category[0] && !STREQ(category, panel_type->category)) {
+        continue;
+      }
+    }
+
+    /* We start property search with an empty panel list, so there's
+     * no point in trying to find an existing panel with this type. */
+    has_result = panel_property_search(C, region, style, NULL, panel_type, search_filter);
+    if (has_result) {
+      break;
+    }
+  }
+
+  /* Run property search for instanced panels (created in the layout calls of previous panels). */
+  if (!has_result && has_instanced_panel) {
+    LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+      /* Note that these checks are duplicated from #ED_region_panels_layout_ex. */
+      if (panel->type == NULL || !(panel->type->flag & PNL_INSTANCED)) {
+        continue;
+      }
+      if (use_category_tabs) {
+        if (panel->type->category[0] && !STREQ(category, panel->type->category)) {
+          continue;
+        }
+      }
+
+      has_result = panel_property_search(C, region, style, panel, panel->type, search_filter);
+      if (has_result) {
+        break;
+      }
+    }
+  }
+
+  /* Free the panels and blocks, as they are only used for search. */
+  UI_blocklist_free(C, &region

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list