Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2020-09-15 19:25:49 +0300
committerHans Goudey <h.goudey@me.com>2020-09-15 19:25:49 +0300
commit8bcdcab659fb688d976a50d892dcb4285ff2a180 (patch)
treed85178a6bda0ca80bc62ae6d85428d6f0ed12c5a /source/blender/editors
parent7a0a60dde8b4bf120ab7977e476bf5c82b2a63ad (diff)
UI: Single tab property search
This adds a search bar to the properties editor. The full search for every tab isn't included in this patch, but the interaction with panels, searching behavior, UI, region level, and DNA changes are included here. The block-level search works by iterating over the block's button groups and checking whether they match the search. If they do, they are tagged with a flag, and the block's panel is tagged too. For every update (text edit), the panel's expansion is set to whether the panel has a result or not. The search also checks for matching strings inside enums and in panel labels. One complication to this that isn't immediately apparent is that closed panel's subpanels have to be searched too. This adds some complexity to the area-level panel layout code. Possible Future Improvements: - Use the new fuzzy search in BLI - Reset panels to their expansion before the search started if the user escape out of the text box. - Open all child panels of a panel with expansion. Differential Revision: https://developer.blender.org/D8856
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/include/ED_screen.h4
-rw-r--r--source/blender/editors/include/UI_interface.h11
-rw-r--r--source/blender/editors/interface/interface.c27
-rw-r--r--source/blender/editors/interface/interface_intern.h15
-rw-r--r--source/blender/editors/interface/interface_layout.c215
-rw-r--r--source/blender/editors/interface/interface_panel.c121
-rw-r--r--source/blender/editors/screen/area.c82
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c13
8 files changed, 458 insertions, 30 deletions
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index d9c7128c2ee..53554e3f34c 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -80,6 +80,10 @@ void ED_region_tag_redraw_no_rebuild(struct ARegion *region);
void ED_region_tag_refresh_ui(struct ARegion *region);
void ED_region_tag_redraw_editor_overlays(struct ARegion *region);
+void ED_region_search_filter_update(const struct ScrArea *area, struct ARegion *region);
+const char *ED_area_region_search_filter_get(const struct ScrArea *area,
+ const struct ARegion *region);
+
void ED_region_panels_init(struct wmWindowManager *wm, struct ARegion *region);
void ED_region_panels_ex(const struct bContext *C, struct ARegion *region, const char *contexts[]);
void ED_region_panels(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 d5d489b1742..6a0b643fb84 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -157,6 +157,9 @@ enum {
UI_BLOCK_POPOVER_ONCE = 1 << 22,
/** Always show keymaps, even for non-menus. */
UI_BLOCK_SHOW_SHORTCUT_ALWAYS = 1 << 23,
+ /** The block is only used during the search process and will not be drawn.
+ * Currently just for the case of a closed panel's subpanel (and its subpanels). */
+ UI_BLOCK_SEARCH_ONLY = 1 << 25,
};
/** #uiPopupBlockHandle.menuretval */
@@ -671,6 +674,9 @@ enum {
void UI_block_theme_style_set(uiBlock *block, char theme_style);
char UI_block_emboss_get(uiBlock *block);
void UI_block_emboss_set(uiBlock *block, char emboss);
+bool UI_block_is_search_only(const uiBlock *block);
+void UI_block_set_search_only(uiBlock *block, bool search_only);
+void UI_block_set_search_filter(uiBlock *block, const char *search_filter);
void UI_block_free(const struct bContext *C, uiBlock *block);
void UI_blocklist_free(const struct bContext *C, struct ListBase *lb);
@@ -1684,6 +1690,8 @@ void UI_panels_scale(struct ARegion *region, float new_width);
void UI_panel_label_offset(struct uiBlock *block, int *r_x, int *r_y);
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_panels_set_expansion_from_seach_filter(const struct bContext *C, struct ARegion *region);
bool UI_panel_category_is_visible(const struct ARegion *region);
void UI_panel_category_add(struct ARegion *region, const char *name);
@@ -1862,6 +1870,8 @@ uiLayout *UI_block_layout(uiBlock *block,
void UI_block_layout_set_current(uiBlock *block, uiLayout *layout);
void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y);
+bool UI_block_apply_search_filter(uiBlock *block);
+
void UI_region_message_subscribe(struct ARegion *region, struct wmMsgBus *mbus);
uiBlock *uiLayoutGetBlock(uiLayout *layout);
@@ -1914,6 +1924,7 @@ float uiLayoutGetUnitsY(uiLayout *layout);
int uiLayoutGetEmboss(uiLayout *layout);
bool uiLayoutGetPropSep(uiLayout *layout);
bool uiLayoutGetPropDecorate(uiLayout *layout);
+void uiLayoutRootSetSearchOnly(uiLayout *layout, bool search_only);
/* layout specifiers */
uiLayout *uiLayoutRow(uiLayout *layout, bool align);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index b9a001a9571..5d20846c528 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -1995,8 +1995,12 @@ void UI_block_draw(const bContext *C, uiBlock *block)
}
}
}
- ui_draw_aligned_panel(
- &style, block, &rect, UI_panel_category_is_visible(region), show_background);
+ ui_draw_aligned_panel(&style,
+ block,
+ &rect,
+ UI_panel_category_is_visible(region),
+ show_background,
+ region->flag & RGN_FLAG_SEARCH_FILTER_ACTIVE);
}
BLF_batch_draw_begin();
@@ -3541,6 +3545,25 @@ void UI_block_theme_style_set(uiBlock *block, char theme_style)
block->theme_style = theme_style;
}
+bool UI_block_is_search_only(const uiBlock *block)
+{
+ return block->flag & UI_BLOCK_SEARCH_ONLY;
+}
+
+/**
+ * Use when a block must be searched to give accurate results
+ * for the whole region but shouldn't be displayed.
+ */
+void UI_block_set_search_only(uiBlock *block, bool search_only)
+{
+ SET_FLAG_FROM_TEST(block->flag, search_only, UI_BLOCK_SEARCH_ONLY);
+}
+
+void UI_block_set_search_filter(uiBlock *block, const char *search_filter)
+{
+ block->search_filter = search_filter;
+}
+
static void ui_but_build_drawstr_float(uiBut *but, double value)
{
size_t slen = 0;
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index edaadd880d7..d62b8a0258a 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -81,6 +81,11 @@ enum {
UI_HAS_ICON = (1 << 3),
UI_HIDDEN = (1 << 4),
UI_SELECT_DRAW = (1 << 5), /* Display selected, doesn't impact interaction. */
+ /**
+ * The button matches the search filter. When property search is active, this
+ * is used to determine which items to keep enabled and which to disable.
+ */
+ UI_SEARCH_FILTER_MATCHES = (1 << 12),
/* warn: rest of uiBut->flag in UI_interface.h */
};
@@ -517,6 +522,12 @@ struct uiBlock {
*/
char display_device[64];
+ /**
+ * Pointer to the space's property search string.
+ * The block doesn't allocate this or change it.
+ */
+ const char *search_filter;
+
struct PieMenuData pie_data;
};
@@ -805,7 +816,9 @@ extern void ui_draw_aligned_panel(const struct uiStyle *style,
const uiBlock *block,
const rcti *rect,
const bool show_pin,
- const bool show_background);
+ const bool show_background,
+ const bool region_search_filter_active);
+void ui_panel_set_search_filter_match(struct Panel *panel, const bool value);
/* interface_draw.c */
extern void ui_draw_dropshadow(
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index c3bcaff0d0c..38f2a2fb3c0 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -97,6 +97,13 @@ typedef struct uiLayoutRoot {
int type;
int opcontext;
+ /**
+ * If true, the root will be removed as part of the property search process.
+ * Necessary for cases like searching the contents of closed panels, where the
+ * block-level tag isn't enough, as there might be visible buttons in the header.
+ */
+ bool search_only;
+
ListBase button_groups; /* #uiButtonGroup. */
int emw, emh;
@@ -5132,6 +5139,208 @@ int uiLayoutGetEmboss(uiLayout *layout)
return layout->emboss;
}
+/**
+ * Tags the layout root as search only, meaning the search process will run, but not the rest of
+ * the layout process. Use in situations where part of the block's contents normally wouldn't be
+ * drawn, but must be searched anyway, like the contents of closed panels with headers.
+ */
+void uiLayoutRootSetSearchOnly(uiLayout *layout, bool search_only)
+{
+ layout->root->search_only = search_only;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Block Layout Search Filtering
+ * \{ */
+
+/* Disabled for performance reasons, but this could be turned on in the future. */
+// #define PROPERTY_SEARCH_USE_TOOLTIPS
+
+static bool block_search_panel_label_matches(const uiBlock *block)
+{
+ if ((block->panel != NULL) && (block->panel->type != NULL)) {
+ if (BLI_strcasestr(block->panel->type->label, block->search_filter)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Buttons for search only layouts (closed panel subpanels) have still been added from the
+ * layout functions, but they need to be hidden. Theoretically they could be removed too.
+ */
+static void layout_free_and_hide_buttons(uiLayout *layout)
+{
+ LISTBASE_FOREACH_MUTABLE (uiItem *, item, &layout->items) {
+ if (item->type == ITEM_BUTTON) {
+ uiButtonItem *button_item = (uiButtonItem *)item;
+ BLI_assert(button_item->but != NULL);
+ button_item->but->flag |= UI_HIDDEN;
+ MEM_freeN(item);
+ }
+ else {
+ layout_free_and_hide_buttons((uiLayout *)item);
+ }
+ }
+
+ MEM_freeN(layout);
+}
+
+/* Prototype of function below. */
+static void layout_root_free(uiLayoutRoot *root);
+
+/**
+ * Remove layouts used only for search and hide their buttons.
+ * (See comment for #uiLayoutRootSetSearchOnly and in #uiLayoutRoot).
+ */
+static void block_search_remove_search_only_roots(uiBlock *block)
+{
+ LISTBASE_FOREACH_MUTABLE (uiLayoutRoot *, root, &block->layouts) {
+ if (root->search_only) {
+ layout_free_and_hide_buttons(root->layout);
+ BLI_remlink(&block->layouts, root);
+ layout_root_free(root);
+ }
+ }
+}
+
+/**
+ * Returns true if a button or the data / operator it represents matches the search filter.
+ */
+static bool button_matches_search_filter(uiBut *but, const char *search_filter)
+{
+ /* Do the shorter checks first for better performance in case there is a match. */
+ if (BLI_strcasestr(but->str, search_filter)) {
+ return true;
+ }
+
+ if (but->optype != NULL) {
+ if (BLI_strcasestr(but->optype->name, search_filter)) {
+ return true;
+ }
+ }
+
+ if (but->rnaprop != NULL) {
+ if (BLI_strcasestr(RNA_property_ui_name(but->rnaprop), search_filter)) {
+ return true;
+ }
+#ifdef PROPERTY_SEARCH_USE_TOOLTIPS
+ if (BLI_strcasestr(RNA_property_description(but->rnaprop), search_filter)) {
+ return true;
+ }
+#endif
+
+ /* Search through labels of enum property items if they are in a dropdown menu.
+ * Unfortunately we have no #bContext here so we cannot search through RNA enums
+ * with dynamic entries (or "itemf" functions) which require context. */
+ if (but->type == UI_BTYPE_MENU) {
+ PointerRNA *ptr = &but->rnapoin;
+ PropertyRNA *enum_prop = but->rnaprop;
+
+ int items_len;
+ const EnumPropertyItem *items_array = NULL;
+ bool free;
+ RNA_property_enum_items_gettexted(NULL, ptr, enum_prop, &items_array, &items_len, &free);
+
+ if (items_array == NULL) {
+ return false;
+ }
+
+ for (int i = 0; i < items_len; i++) {
+ if (BLI_strcasestr(items_array[i].name, search_filter)) {
+ return true;
+ }
+ }
+ if (free) {
+ MEM_freeN((EnumPropertyItem *)items_array);
+ }
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Test for a search result within a specific button group.
+ */
+static bool button_group_has_search_match(uiButtonGroup *button_group, const char *search_filter)
+{
+ LISTBASE_FOREACH (LinkData *, link, &button_group->buttons) {
+ uiBut *but = link->data;
+ if (button_matches_search_filter(but, search_filter)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Apply the search filter, tagging all buttons with whether they match or not.
+ * Tag every button in the group as a result if any button in the group matches.
+ *
+ * \note It would be great to return early here if we found a match, but because
+ * the results may be visible we have to continue searching the entire block.
+ *
+ * \return True if the block has any search results.
+ */
+static bool block_search_filter_tag_buttons(uiBlock *block)
+{
+ bool has_result = false;
+ LISTBASE_FOREACH (uiLayoutRoot *, root, &block->layouts) {
+ LISTBASE_FOREACH (uiButtonGroup *, button_group, &root->button_groups) {
+ if (button_group_has_search_match(button_group, block->search_filter)) {
+ LISTBASE_FOREACH (LinkData *, link, &button_group->buttons) {
+ uiBut *but = link->data;
+ but->flag |= UI_SEARCH_FILTER_MATCHES;
+ }
+ has_result = true;
+ }
+ }
+ }
+ return has_result;
+}
+
+static void block_search_deactivate_buttons(uiBlock *block)
+{
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
+ if (!(but->flag & UI_SEARCH_FILTER_MATCHES)) {
+ but->flag |= UI_BUT_INACTIVE;
+ }
+ }
+}
+
+/**
+ * Apply property search behavior, setting panel flags and deactivating buttons that don't match.
+ *
+ * \note Must not be run after #UI_block_layout_resolve.
+ */
+bool UI_block_apply_search_filter(uiBlock *block)
+{
+ if (!(block->search_filter && block->search_filter[0])) {
+ return false;
+ }
+
+ const bool panel_label_matches = block_search_panel_label_matches(block);
+
+ const bool has_result = panel_label_matches ? true : block_search_filter_tag_buttons(block);
+
+ block_search_remove_search_only_roots(block);
+
+ if (block->panel != NULL) {
+ ui_panel_set_search_filter_match(block->panel, has_result);
+ }
+
+ if (!panel_label_matches) {
+ block_search_deactivate_buttons(block);
+ }
+
+ return has_result;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -5378,8 +5587,6 @@ static void ui_layout_free(uiLayout *layout)
static void layout_root_free(uiLayoutRoot *root)
{
- ui_layout_free(root->layout);
-
LISTBASE_FOREACH_MUTABLE (uiButtonGroup *, button_group, &root->button_groups) {
button_group_free(button_group);
}
@@ -5575,10 +5782,14 @@ void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y)
block->curlayout = NULL;
LISTBASE_FOREACH_MUTABLE (uiLayoutRoot *, root, &block->layouts) {
+ /* Seach only roots should be removed by #UI_block_apply_search_filter. */
+ BLI_assert(!root->search_only);
+
ui_layout_add_padding_button(root);
/* NULL in advance so we don't interfere when adding button */
ui_layout_end(block, root->layout, r_x, r_y);
+ ui_layout_free(root->layout);
layout_root_free(root);
}
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 6e2229ce3e3..c11e4397b4c 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -77,6 +77,7 @@
#define PNL_ANIM_ALIGN 8
#define PNL_NEW_ADDED 16
#define PNL_FIRST 32
+#define PNL_SEARCH_FILTER_MATCHES 64
/* the state of the mouse position relative to the panel */
typedef enum uiPanelMouseState {
@@ -125,16 +126,32 @@ static bool panel_type_context_poll(ARegion *region,
/** \name Local Functions
* \{ */
-static void panel_title_color_get(bool show_background, uchar color[4])
+static void panel_title_color_get(const Panel *panel,
+ const bool show_background,
+ const bool use_search_color,
+ const bool region_search_filter_active,
+ uchar r_color[4])
{
- if (show_background) {
- UI_GetThemeColor4ubv(TH_TITLE, color);
- }
- else {
+ if (!show_background) {
/* Use menu colors for floating panels. */
bTheme *btheme = UI_GetTheme();
const uiWidgetColors *wcol = &btheme->tui.wcol_menu_back;
- copy_v4_v4_uchar(color, (const uchar *)wcol->text);
+ copy_v4_v4_uchar(r_color, (const uchar *)wcol->text);
+ return;
+ }
+
+ const bool search_match = UI_panel_matches_search_filter(panel);
+
+ if (region_search_filter_active && use_search_color && search_match) {
+ UI_GetThemeColor4ubv(TH_MATCH, r_color);
+ }
+ else {
+ UI_GetThemeColor4ubv(TH_TITLE, r_color);
+ if (region_search_filter_active && !search_match) {
+ r_color[0] *= 0.5;
+ r_color[1] *= 0.5;
+ r_color[2] *= 0.5;
+ }
}
}
@@ -230,6 +247,7 @@ static Panel *UI_panel_add_instanced_ex(ARegion *region,
BLI_strncpy(panel->panelname, panel_type->idname, sizeof(panel->panelname));
panel->runtime.custom_data_ptr = custom_data;
+ panel->runtime_flag |= PNL_NEW_ADDED;
/* Add the panel's children too. Although they aren't instanced panels, we can still use this
* function to create them, as UI_panel_begin does other things we don't need to do. */
@@ -786,6 +804,65 @@ static void ui_offset_panel_block(uiBlock *block)
block->rect.xmin = block->rect.ymin = 0.0;
}
+void ui_panel_set_search_filter_match(struct Panel *panel, const bool value)
+{
+ SET_FLAG_FROM_TEST(panel->runtime_flag, value, PNL_SEARCH_FILTER_MATCHES);
+}
+
+static void panel_matches_search_filter_recursive(const Panel *panel, bool *filter_matches)
+{
+ *filter_matches |= panel->runtime_flag & PNL_SEARCH_FILTER_MATCHES;
+
+ /* If the panel has no match we need to make sure that its children are too. */
+ if (!*filter_matches) {
+ LISTBASE_FOREACH (const Panel *, child_panel, &panel->children) {
+ panel_matches_search_filter_recursive(child_panel, filter_matches);
+ }
+ }
+}
+
+/**
+ * Find whether a panel or any of its subpanels contain a property that matches the search filter,
+ * depending on the search process running in #UI_block_apply_search_filter earlier.
+ */
+bool UI_panel_matches_search_filter(const Panel *panel)
+{
+ bool search_filter_matches = false;
+ panel_matches_search_filter_recursive(panel, &search_filter_matches);
+ return search_filter_matches;
+}
+
+static void panel_set_expansion_from_seach_filter_recursive(const bContext *C, Panel *panel)
+{
+ short start_flag = panel->flag;
+ SET_FLAG_FROM_TEST(panel->flag, !UI_panel_matches_search_filter(panel), PNL_CLOSED);
+ if (start_flag != panel->flag) {
+ panel_activate_state(C, panel, PANEL_STATE_ANIMATION);
+ }
+
+ /* If the panel is filtered (removed) we need to check that its children are too. */
+ LISTBASE_FOREACH (Panel *, child_panel, &panel->children) {
+ if (panel->type == NULL || (panel->type->flag & PNL_NO_HEADER)) {
+ continue;
+ }
+ panel_set_expansion_from_seach_filter_recursive(C, child_panel);
+ }
+}
+
+/**
+ * Uses the panel's search filter flag to set its expansion, activating animation if it was closed
+ * or opened. Note that this can't be set too often, or manual interaction becomes impossible.
+ */
+void UI_panels_set_expansion_from_seach_filter(const bContext *C, ARegion *region)
+{
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ if (panel->type == NULL || (panel->type->flag & PNL_NO_HEADER)) {
+ continue;
+ }
+ panel_set_expansion_from_seach_filter_recursive(C, panel);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -829,7 +906,8 @@ void UI_panel_label_offset(uiBlock *block, int *r_x, int *r_y)
static void ui_draw_aligned_panel_header(const uiStyle *style,
const uiBlock *block,
const rcti *rect,
- const bool show_background)
+ const bool show_background,
+ const bool region_search_filter_active)
{
const Panel *panel = block->panel;
const bool is_subpanel = (panel->type && panel->type->parent);
@@ -840,7 +918,8 @@ static void ui_draw_aligned_panel_header(const uiStyle *style,
/* draw text label */
uchar col_title[4];
- panel_title_color_get(show_background, col_title);
+ panel_title_color_get(
+ panel, show_background, is_subpanel, region_search_filter_active, col_title);
col_title[3] = 255;
rcti hrect = *rect;
@@ -862,7 +941,8 @@ void ui_draw_aligned_panel(const uiStyle *style,
const uiBlock *block,
const rcti *rect,
const bool show_pin,
- const bool show_background)
+ const bool show_background,
+ const bool region_search_filter_active)
{
const Panel *panel = block->panel;
float color[4];
@@ -937,7 +1017,7 @@ void ui_draw_aligned_panel(const uiStyle *style,
GPU_blend(GPU_BLEND_ALPHA);
/* draw with background color */
- immUniformThemeColor(TH_PANEL_HEADER);
+ immUniformThemeColor(UI_panel_matches_search_filter(panel) ? TH_MATCH : TH_PANEL_HEADER);
immRectf(pos, minx, headrect.ymin, rect->xmax, y);
immBegin(GPU_PRIM_LINES, 4);
@@ -957,7 +1037,7 @@ void ui_draw_aligned_panel(const uiStyle *style,
/* draw optional pin icon */
if (show_pin && (block->panel->flag & PNL_PIN)) {
uchar col_title[4];
- panel_title_color_get(show_background, col_title);
+ panel_title_color_get(panel, show_background, false, region_search_filter_active, col_title);
GPU_blend(GPU_BLEND_ALPHA);
UI_icon_draw_ex(headrect.xmax - ((PNL_ICON * 2.2f) / block->aspect),
@@ -976,7 +1056,8 @@ void ui_draw_aligned_panel(const uiStyle *style,
if (is_subpanel) {
titlerect.xmin += (0.7f * UI_UNIT_X) / block->aspect + 0.001f;
}
- ui_draw_aligned_panel_header(style, block, &titlerect, show_background);
+ ui_draw_aligned_panel_header(
+ style, block, &titlerect, show_background, region_search_filter_active);
if (show_drag) {
/* Make `itemrect` smaller. */
@@ -1071,7 +1152,7 @@ void ui_draw_aligned_panel(const uiStyle *style,
BLI_rctf_scale(&itemrect, 0.25f);
uchar col_title[4];
- panel_title_color_get(show_background, col_title);
+ panel_title_color_get(panel, show_background, false, region_search_filter_active, col_title);
float tria_color[4];
rgb_uchar_to_float(tria_color, col_title);
tria_color[3] = 1.0f;
@@ -1853,19 +1934,23 @@ void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y)
ui_panels_size(region, r_x, r_y);
}
+/**
+ * Draw panels, selected (panels currently being dragged) on top.
+ */
void UI_panels_draw(const bContext *C, ARegion *region)
{
- /* Draw panels, selected on top. Also in reverse order, because
- * UI blocks are added in reverse order and we need child panels
- * to draw on top. */
+ /* Draw in reverse order, because #uiBlocks are added in reverse order
+ * and we need child panels to draw on top. */
LISTBASE_FOREACH_BACKWARD (uiBlock *, block, &region->uiblocks) {
- if (block->active && block->panel && !(block->panel->flag & PNL_SELECT)) {
+ if (block->active && block->panel && !(block->panel->flag & PNL_SELECT) &&
+ !UI_block_is_search_only(block)) {
UI_block_draw(C, block);
}
}
LISTBASE_FOREACH_BACKWARD (uiBlock *, block, &region->uiblocks) {
- if (block->active && block->panel && (block->panel->flag & PNL_SELECT)) {
+ if (block->active && block->panel && (block->panel->flag & PNL_SELECT) &&
+ !UI_block_is_search_only(block)) {
UI_block_draw(C, block);
}
}
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index e7f5f5646cb..f6c54e87410 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -492,6 +492,9 @@ void ED_region_do_layout(bContext *C, ARegion *region)
UI_SetTheme(area ? area->spacetype : 0, at->regionid);
at->layout(C, region);
+
+ /* Clear temporary update flag. */
+ region->flag &= ~RGN_FLAG_SEARCH_FILTER_UPDATE;
}
/* only exported for WM */
@@ -736,6 +739,37 @@ void ED_area_tag_refresh(ScrArea *area)
/* *************************************************************** */
+/**
+ * Returns the search string if the space type and region type support property search.
+ */
+const char *ED_area_region_search_filter_get(const ScrArea *area, const ARegion *region)
+{
+ /* Only the properties editor has a search string for now. */
+ if (area->spacetype == SPACE_PROPERTIES) {
+ SpaceProperties *sbuts = area->spacedata.first;
+ if (region->regiontype == RGN_TYPE_WINDOW) {
+ return sbuts->runtime->search_string;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Set the temporary update flag for property search.
+ */
+void ED_region_search_filter_update(const ScrArea *area, ARegion *region)
+{
+ region->flag |= RGN_FLAG_SEARCH_FILTER_UPDATE;
+
+ const char *search_filter = ED_area_region_search_filter_get(area, region);
+ SET_FLAG_FROM_TEST(region->flag,
+ region->regiontype == RGN_TYPE_WINDOW && search_filter[0] != '\0',
+ RGN_FLAG_SEARCH_FILTER_ACTIVE);
+}
+
+/* *************************************************************** */
+
/* use NULL to disable it */
void ED_area_status_text(ScrArea *area, const char *str)
{
@@ -2558,7 +2592,9 @@ static void ed_panel_draw(const bContext *C,
Panel *panel,
int w,
int em,
- char *unique_panel_str)
+ char *unique_panel_str,
+ const char *search_filter,
+ bool search_only)
{
const uiStyle *style = UI_style_get_dpi();
@@ -2571,10 +2607,14 @@ static void ed_panel_draw(const bContext *C,
strncat(block_name, unique_panel_str, INSTANCED_PANEL_UNIQUE_STR_LEN);
}
uiBlock *block = UI_block_begin(C, region, block_name, UI_EMBOSS);
+ UI_block_set_search_filter(block, search_filter);
+ UI_block_set_search_only(block, search_only);
bool open;
panel = UI_panel_begin(region, lb, block, pt, panel, &open);
+ const bool search_filter_active = search_filter != NULL && search_filter[0] != '\0';
+
/* bad fixed values */
int xco, yco, h = 0;
int headerend = w - UI_UNIT_X;
@@ -2590,9 +2630,11 @@ static void ed_panel_draw(const bContext *C,
1,
0,
style);
+ uiLayoutRootSetSearchOnly(panel->layout, search_only);
pt->draw_header_preset(C, panel);
+ UI_block_apply_search_filter(block);
UI_block_layout_resolve(block, &xco, &yco);
UI_block_translate(block, headerend - xco, 0);
panel->layout = NULL;
@@ -2620,9 +2662,11 @@ static void ed_panel_draw(const bContext *C,
panel->layout = UI_block_layout(
block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, labelx, labely, UI_UNIT_Y, 1, 0, style);
}
+ uiLayoutRootSetSearchOnly(panel->layout, search_only);
pt->draw_header(C, panel);
+ UI_block_apply_search_filter(block);
UI_block_layout_resolve(block, &xco, &yco);
panel->labelofs = xco - labelx;
panel->layout = NULL;
@@ -2631,7 +2675,7 @@ static void ed_panel_draw(const bContext *C,
panel->labelofs = 0;
}
- if (open) {
+ if (open || search_filter_active) {
short panelContext;
/* panel context can either be toolbar region or normal panels region */
@@ -2655,9 +2699,11 @@ static void ed_panel_draw(const bContext *C,
em,
0,
style);
+ uiLayoutRootSetSearchOnly(panel->layout, search_only || !open);
pt->draw(C, panel);
+ UI_block_apply_search_filter(block);
UI_block_layout_resolve(block, &xco, &yco);
panel->layout = NULL;
@@ -2669,13 +2715,22 @@ static void ed_panel_draw(const bContext *C,
UI_block_end(C, block);
/* Draw child panels. */
- if (open) {
+ if (open || search_filter_active) {
LISTBASE_FOREACH (LinkData *, link, &pt->children) {
PanelType *child_pt = link->data;
Panel *child_panel = UI_panel_find_by_type(&panel->children, child_pt);
if (child_pt->draw && (!child_pt->poll || child_pt->poll(C, child_pt))) {
- ed_panel_draw(C, region, &panel->children, child_pt, child_panel, w, em, unique_panel_str);
+ ed_panel_draw(C,
+ region,
+ &panel->children,
+ child_pt,
+ child_panel,
+ w,
+ em,
+ unique_panel_str,
+ search_filter,
+ !open);
}
}
}
@@ -2815,6 +2870,9 @@ void ED_region_panels_layout_ex(const bContext *C,
/* create panels */
UI_panels_begin(C, region);
+ /* Get search string for property search. */
+ const char *search_filter = ED_area_region_search_filter_get(area, region);
+
/* set view2d view matrix - UI_block_begin() stores it */
UI_view2d_view_ortho(v2d);
@@ -2846,7 +2904,9 @@ void ED_region_panels_layout_ex(const bContext *C,
panel,
(pt->flag & PNL_DRAW_BOX) ? w_box_panel : w,
em,
- NULL);
+ NULL,
+ search_filter,
+ false);
}
/* Draw "polyinstantaited" panels that don't have a 1 to 1 correspondence with their types. */
@@ -2879,7 +2939,17 @@ void ED_region_panels_layout_ex(const bContext *C,
panel,
(panel->type->flag & PNL_DRAW_BOX) ? w_box_panel : w,
em,
- unique_panel_str);
+ unique_panel_str,
+ search_filter,
+ false);
+ }
+ }
+
+ /* Update panel expansion based on property search results. */
+ if (region->flag & RGN_FLAG_SEARCH_FILTER_UPDATE) {
+ /* Don't use the last update from the deactivation, or all the panels will be left closed. */
+ if (region->flag & RGN_FLAG_SEARCH_FILTER_ACTIVE) {
+ UI_panels_set_expansion_from_seach_filter(C, region);
}
}
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 25f8fecbf26..59723fb1926 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -109,20 +109,31 @@ static void buttons_free(SpaceLink *sl)
BLI_freelistN(&ct->users);
MEM_freeN(ct);
}
+
+ MEM_SAFE_FREE(sbuts->runtime);
}
/* spacetype; init callback */
-static void buttons_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
+static void buttons_init(struct wmWindowManager *UNUSED(wm), ScrArea *area)
{
+ SpaceProperties *sbuts = (SpaceProperties *)area->spacedata.first;
+
+ if (sbuts->runtime == NULL) {
+ sbuts->runtime = MEM_mallocN(sizeof(SpaceProperties_Runtime), __func__);
+ sbuts->runtime->search_string[0] = '\0';
+ }
}
static SpaceLink *buttons_duplicate(SpaceLink *sl)
{
+ SpaceProperties *sfile_old = (SpaceProperties *)sl;
SpaceProperties *sbutsn = MEM_dupallocN(sl);
/* clear or remove stuff from old */
sbutsn->path = NULL;
sbutsn->texuser = NULL;
+ sbutsn->runtime = MEM_dupallocN(sfile_old->runtime);
+ sbutsn->runtime->search_string[0] = '\0';
return (SpaceLink *)sbutsn;
}