[Bf-blender-cvs] [4a4e36ff9bb] property-search-ui-v2: Property Search: All tabs

Hans Goudey noreply at git.blender.org
Wed Sep 9 21:03:18 CEST 2020


Commit: 4a4e36ff9bbc330f859b0e35d7b81029f0b59083
Author: Hans Goudey
Date:   Wed Sep 9 13:45:43 2020 -0500
Branches: property-search-ui-v2
https://developer.blender.org/rB4a4e36ff9bbc330f859b0e35d7b81029f0b59083

Property Search: All tabs

This patch enables property search for all tabs in the property editor.
This is definitely the most "crazy" of the changes in terms of code, but
it's also where the new functionality gets good.

There is one piece of funcionality that wasn't obvious when I began the
implementation. In order to make interaction faster, if the editor's
current tab doesn't have a result, the search moves you to the next panel
that does. That way you can just press `ctrl-F`, search, and have the
result appear.

In order to keep the searching safe, to make sure the editor isn't influenced
by anything that happens while building the layout for the other tabs,
the space is duplicated and the new search is run in the duplicated
editor. This also helps isolate this code, which could be fairly invasive
otherwise. Only the layout pass is done in the other tabs, and it works
by just running the regular single tab property search  (D8856) and
checking if any of the active panels in the tab match the search filter.

The search match status for every current tab of the property editor is
stored in a runtime field and them displayed later by dimming icons in
the tab selector panel to the left. The functionality for that dimming is
in D8858.

Note that there are currently some issues with the tool tab, where some
context variables end up being `None`. I'm curious if reviewers have any
advice if they encounter this.

**Future Improvements**
This patch does not addresss the performance aspects of searching every
tab. This shouldn't be too bad, but it would be good to make some changes
to improve this, ideally in separate patches. I have done some initial profiling,
and it looks like a significant portion of time is spent doing string comparisons,
so that may be the best place to start. Here are some ideas:
1. Use ghash instead of string lookups for panel types
2. Possibly only search in other tabs while editing search string. I would like
   to avoid this though.
3. Look into using ED_region_tag_redraw_no_rebuild for some interactions
   like panel dragging.

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

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

M	release/scripts/startup/bl_ui/space_properties.py
M	source/blender/editors/include/UI_interface.h
M	source/blender/editors/interface/interface_panel.c
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 891f73434e0..07298082f4c 100644
--- a/release/scripts/startup/bl_ui/space_properties.py
+++ b/release/scripts/startup/bl_ui/space_properties.py
@@ -51,7 +51,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="context_search_filter_active", icon_only=True)
+        else:
+            layout.prop_tabs_enum(view, "context", icon_only=True)
 
 
 classes = (
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 25adcfbb5a2..4c08a36c609 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -1692,6 +1692,7 @@ int UI_panel_size_y(const struct Panel *panel);
 bool UI_panel_is_dragging(const struct Panel *panel);
 bool UI_panel_matches_search_filter(const struct Panel *panel);
 void UI_panel_set_expansion_from_seach_filter(const struct bContext *C, struct Panel *panel);
+bool UI_panel_is_active(const struct Panel *panel);
 
 bool UI_panel_category_is_visible(const struct ARegion *region);
 void UI_panel_category_add(struct ARegion *region, const char *name);
@@ -1717,6 +1718,8 @@ struct PointerRNA *UI_region_panel_custom_data_under_cursor(const struct bContex
                                                             const struct wmEvent *event);
 void UI_panel_custom_data_set(struct Panel *panel, struct PointerRNA *custom_data);
 
+void UI_region_panels_remove_handlers(const struct bContext *C, struct ARegion *region);
+
 /* Polyinstantiated panels for representing a list of data. */
 struct Panel *UI_panel_add_instanced(struct ARegion *region,
                                      struct ListBase *panels,
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 4e33bc4f8bd..d54bf9e5d07 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -832,6 +832,14 @@ bool UI_panel_matches_search_filter(const Panel *panel)
   return search_filter_matches;
 }
 
+/**
+ * Returns whether a panel is currently active (displayed).
+ */
+bool UI_panel_is_active(const Panel *panel)
+{
+  return panel->runtime_flag & PNL_ACTIVE;
+}
+
 /**
  * Uses the panel's search filter flag to set its expansion,
  * activating animation if it was closed or opened.
@@ -2622,6 +2630,13 @@ static void ui_handler_remove_panel(bContext *C, void *userdata)
   panel_activate_state(C, panel, PANEL_STATE_EXIT);
 }
 
+void UI_region_panels_remove_handlers(const bContext *C, ARegion *region)
+{
+  LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+    panel_activate_state(C, panel, PANEL_STATE_EXIT);
+  }
+}
+
 static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state)
 {
   uiHandlePanelData *data = panel->activedata;
@@ -2649,11 +2664,13 @@ static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelS
   }
 
   if (state == PANEL_STATE_EXIT) {
-    MEM_freeN(data);
-    panel->activedata = NULL;
+    if (data != NULL) {
+      MEM_freeN(data);
+      panel->activedata = NULL;
 
-    WM_event_remove_ui_handler(
-        &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, panel, false);
+      WM_event_remove_ui_handler(
+          &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, panel, false);
+    }
   }
   else {
     if (!data) {
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 4b439c16f3c..8fb3363207b 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -48,6 +48,7 @@
 #include "RNA_define.h"
 #include "RNA_enum_types.h"
 
+#include "UI_interface.h"
 #include "UI_resources.h"
 
 #include "buttons_intern.h" /* own include */
@@ -296,16 +297,125 @@ static void buttons_main_region_layout_properties(const bContext *C,
   ED_region_panels_layout_ex(C, region, &region->type->paneltypes, contexts, NULL);
 }
 
+static void main_region_layout_current_context(const bContext *C,
+                                               SpaceProperties *sbuts,
+                                               ARegion *region)
+{
+  if (sbuts->mainb == BCONTEXT_TOOL) {
+    ED_view3d_buttons_region_layout_ex(C, region, "Tool");
+  }
+  else {
+    buttons_main_region_layout_properties(C, sbuts, region);
+  }
+}
+
+static void property_search_move_to_next_tab_with_results(SpaceProperties *sbuts,
+                                                          const int *context_tabs_array,
+                                                          const int tabs_len)
+{
+  int current_tab_index = 0;
+  for (int i = 0; i < tabs_len; i++) {
+    if (sbuts->mainb == context_tabs_array[i]) {
+      current_tab_index = i;
+      break;
+    }
+  }
+
+  /* Try the tabs after the current tab. */
+  for (int i = current_tab_index; i < tabs_len; i++) {
+    if (sbuts->context_search_filter_active & (1 << i)) {
+      sbuts->mainbuser = context_tabs_array[i];
+      return;
+    }
+  }
+
+  /* Try the tabs before the current tab. */
+  for (int i = 0; i < current_tab_index; i++) {
+    if (sbuts->context_search_filter_active & (1 << i)) {
+      sbuts->mainbuser = context_tabs_array[i];
+      return;
+    }
+  }
+}
+
+static void property_search_all_tabs(const bContext *C,
+                                     SpaceProperties *sbuts,
+                                     ARegion *main_region)
+{
+  sbuts->context_search_filter_active = 0;
+
+  /* Duplicate space and region so we don't change any data for this space. */
+  ScrArea *area_copy = MEM_dupallocN(CTX_wm_area(C));
+  ARegion *region_copy = BKE_area_region_copy(CTX_wm_area(C)->type, main_region);
+  BKE_area_region_panels_free(&region_copy->panels);
+  bContext *C_copy = CTX_copy(C);
+  CTX_wm_area_set(C_copy, area_copy);
+  CTX_wm_region_set(C_copy, region_copy);
+  SpaceProperties *sbuts_copy = MEM_dupallocN(sbuts);
+
+  int context_tabs_array[32];
+  int tabs_tot = ED_buttons_tabs_list(sbuts, context_tabs_array);
+
+  bool current_tab_has_search_match = false;
+
+  /* Loop through the tabs added to the properties editor. */
+  for (int i = 0; i < tabs_tot; i++) {
+    if (context_tabs_array[i] == -1) {
+      continue;
+    }
+
+    /* Run the layout with this tab set active. */
+    sbuts_copy->mainb = sbuts->mainbo = sbuts_copy->mainbuser = context_tabs_array[i];
+
+    /* Run the layout for the actual region if the tab matches to avoid doing it again later on. */
+    const bool use_actual_region = sbuts->mainb == sbuts_copy->mainb;
+    if (use_actual_region) {
+      main_region_layout_current_context(C, sbuts, main_region);
+    }
+    else {
+      main_region_layout_current_context(C_copy, sbuts_copy, region_copy);
+    }
+
+    /* Store whether this tab has any unfiltered panels left. */
+    bool tab_has_search_match = false;
+    LISTBASE_FOREACH (
+        Panel *, panel, use_actual_region ? &main_region->panels : &region_copy->panels) {
+      tab_has_search_match |= UI_panel_matches_search_filter(panel) && UI_panel_is_active(panel);
+    }
+    if (tab_has_search_match) {
+      sbuts->context_search_filter_active |= (1 << i);
+      if (use_actual_region) {
+        current_tab_has_search_match = tab_has_search_match;
+      }
+    }
+
+    /* Free data created during the layout process. */
+    UI_region_panels_remove_handlers(C_copy, region_copy);
+    BKE_area_region_panels_free(&region_copy->panels);
+    UI_blocklist_free(C_copy, &region_copy->uiblocks);
+  }
+
+  if (!current_tab_has_search_match && main_region->flag & RGN_FLAG_SEARCH_FILTER_UPDATE) {
+    property_search_move_to_next_tab_with_results(sbuts, context_tabs_array, tabs_tot);
+  }
+
+  BKE_area_region_free(CTX_wm_area(C_copy)->type, region_copy);
+  MEM_freeN(region_copy);
+  MEM_freeN(sbuts_copy);
+  MEM_freeN(area_copy);
+  MEM_freeN(C_copy);
+}
+
 static void buttons_main_region_layout(const bContext *C, ARegion *region)
 {
   /* draw entirely, view changes should be handled here */
   SpaceProperties *sbuts = CTX_wm_space_properties(C);
 
-  if (sbuts->mainb == BCONTEXT_TOOL) {
-    ED_view3d_buttons_region_layout_ex(C, region, "Tool");
+  if (region->flag & RGN_FLAG_SEARCH_FILTER_ACTIVE) {
+    property_search_all_tabs(C, sbuts, region);
   }
   else {
-    buttons_main_region_layout_properties(C, sbuts, region);
+    main_region_layout_current_context(C, sbuts, region);
   }
 
   sbuts->mainbo = sbuts->mainb;
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index c4706cace07..245f427354d 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -147,9 +147,12 @@ typedef struct SpaceProperties {
 
   /** Context tabs. */
   short mainb, mainbo, mainbuser;
+  /** Runtime. Bitfield flag (in the same order as the tabs) for whether each tab has properties
+   * that match the search filter. Only valid when #search_string is set. */
+  int context_search_filter_active;
   /** Preview is signal to refresh. */
   short preview;
-  char _pad[5];
+  char _pad[1];
   char flag;
 
   /** Runtime. */
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index b8615d22753..11b99c3c7ac 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -4484,6 +4484,15 @@ static void rna_def_space_properties(BlenderRNA *brna)
   RNA_def_property_ui_text(prop, "Pin ID", "Use the pinned context");
 
   /* Property search. */
+  prop = RNA_def_property(srna, "context_search_filter_active", PROP_ENUM, PROP_NONE);
+  RNA_def_property_enum_items(prop, buttons_context_items);
+  RNA_def_property_flag(prop, PROP_ENUM_FLAG);
+  RNA_def_property_enum_funcs(
+     

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list