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:
-rw-r--r--release/scripts/startup/bl_ui/space_properties.py4
-rw-r--r--source/blender/blenloader/intern/readfile.c4
-rw-r--r--source/blender/editors/include/ED_screen.h3
-rw-r--r--source/blender/editors/include/UI_interface.h12
-rw-r--r--source/blender/editors/interface/interface.c28
-rw-r--r--source/blender/editors/interface/interface_intern.h15
-rw-r--r--source/blender/editors/interface/interface_layout.c201
-rw-r--r--source/blender/editors/interface/interface_panel.c113
-rw-r--r--source/blender/editors/screen/area.c77
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c1
-rw-r--r--source/blender/makesdna/DNA_screen_types.h8
-rw-r--r--source/blender/makesdna/DNA_space_types.h7
-rw-r--r--source/blender/makesrna/intern/rna_space.c20
13 files changed, 469 insertions, 24 deletions
diff --git a/release/scripts/startup/bl_ui/space_properties.py b/release/scripts/startup/bl_ui/space_properties.py
index d4d5843f415..891f73434e0 100644
--- a/release/scripts/startup/bl_ui/space_properties.py
+++ b/release/scripts/startup/bl_ui/space_properties.py
@@ -29,6 +29,10 @@ class PROPERTIES_HT_header(Header):
layout.template_header()
+ layout.separator_spacer()
+ layout.prop(view, "search_filter", icon='VIEWZOOM', text="")
+ layout.separator_spacer()
+
row = layout.row()
row.emboss = 'NONE'
row.operator("buttons.toggle_pin", icon=('PINNED' if view.use_pin_id else 'UNPINNED'), text="")
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index b0f0a08651c..d013006b602 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -4924,6 +4924,9 @@ static void direct_link_region(BlendDataReader *reader, ARegion *region, int spa
BLO_read_list(reader, &region->ui_lists);
+ /* The area's search filter is runtime only, so we need to clear the active flag on read. */
+ region->flag &= ~RGN_FLAG_SEARCH_FILTER_ACTIVE;
+
LISTBASE_FOREACH (uiList *, ui_list, &region->ui_lists) {
ui_list->type = NULL;
ui_list->dyn_data = NULL;
@@ -5164,6 +5167,7 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
sbuts->texuser = NULL;
sbuts->mainbo = sbuts->mainb;
sbuts->mainbuser = sbuts->mainb;
+ memset(&sbuts->runtime, 0x0, sizeof(sbuts->runtime));
}
else if (sl->spacetype == SPACE_CONSOLE) {
SpaceConsole *sconsole = (SpaceConsole *)sl;
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index d9c7128c2ee..1e6f3ed3af1 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -80,6 +80,9 @@ 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_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..64b4a058ca2 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,10 @@ 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_has_search_filter(const uiBlock *block);
+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 +1691,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 +1871,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);
+void UI_block_apply_search_filter(uiBlock *block);
+
void UI_region_message_subscribe(struct ARegion *region, struct wmMsgBus *mbus);
uiBlock *uiLayoutGetBlock(uiLayout *layout);
@@ -1914,6 +1925,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 10650da4b0e..b0530c797a8 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -1959,8 +1959,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();
@@ -3505,6 +3509,26 @@ void UI_block_theme_style_set(uiBlock *block, char theme_style)
block->theme_style = theme_style;
}
+bool UI_block_has_search_filter(const uiBlock *block)
+{
+ return block->search_filter != NULL && block->search_filter[0] != '\0';
+}
+
+bool UI_block_is_search_only(const uiBlock *block)
+{
+ return block->flag & UI_BLOCK_SEARCH_ONLY;
+}
+
+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 4661d0816ae..ac5230c551a 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 983c3e5ebd3..59807dce8be 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 because there might be buttons in the header.
+ */
+ bool search_only;
+
ListBase button_groups; /* #uiButtonGroup. */
int emw, emh;
@@ -5086,6 +5093,197 @@ 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
+ * \{ */
+
+// #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;
+}
+
+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);
+}
+
+/**
+ * Remove layouts used only for search and hide their buttons.
+ */
+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);
+ MEM_freeN(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 performance reasons. */
+ 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 context 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 the 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 search match if any button matches.
+ *
+ * \note It would be great to return early here if we found a match, but because
+ * the results could be visible we have to continue searching the entire block.
+ *
+ * \return Whether 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 be run before #UI_block_layout_resolve.
+ */
+void UI_block_apply_search_filter(uiBlock *block)
+{
+ if (!(block->search_filter && block->search_filter[0])) {
+ return;
+ }
+
+ 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);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -5529,6 +5727,9 @@ 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 */
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 6e2229ce3e3..8d63bc40ea1 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_SEARCH_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,64 @@ 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 is filtered (removed) we need to check 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.
+ */
+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.
+ */
+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 +905,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 +917,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 +940,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 +1016,8 @@ 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_SEARCH_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;
@@ -1859,13 +1940,15 @@ void UI_panels_draw(const bContext *C, ARegion *region)
* UI blocks 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 2da9dd01ceb..171d6105547 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,34 @@ void ED_area_tag_refresh(ScrArea *area)
/* *************************************************************** */
+/**
+ * Returns the search string if the space type supports property search.
+ */
+const char *ED_area_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;
+}
+
+void ED_region_search_filter_update(const ScrArea *area, ARegion *region)
+{
+ region->flag |= RGN_FLAG_SEARCH_FILTER_UPDATE;
+
+ const char *search_filter = ED_area_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 +2589,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,6 +2604,8 @@ 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);
@@ -2590,9 +2625,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 +2657,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 +2670,7 @@ static void ed_panel_draw(const bContext *C,
panel->labelofs = 0;
}
- if (open) {
+ if (open || UI_block_has_search_filter(block) || search_only) {
short panelContext;
/* panel context can either be toolbar region or normal panels region */
@@ -2655,9 +2694,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 +2710,22 @@ static void ed_panel_draw(const bContext *C,
UI_block_end(C, block);
/* Draw child panels. */
- if (open) {
+ if (open || UI_block_has_search_filter(block)) {
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);
}
}
}
@@ -2782,6 +2832,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_search_filter_get(area, region);
+
/* set view2d view matrix - UI_block_begin() stores it */
UI_view2d_view_ortho(v2d);
@@ -2813,7 +2866,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. */
@@ -2846,7 +2901,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 33ce24190b3..16bc6f5be47 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -123,6 +123,7 @@ static SpaceLink *buttons_duplicate(SpaceLink *sl)
/* clear or remove stuff from old */
sbutsn->path = NULL;
sbutsn->texuser = NULL;
+ sbutsn->runtime.search_string[0] = '\0';
return (SpaceLink *)sbutsn;
}
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index 93110d148bf..43b836ca86b 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -687,6 +687,14 @@ enum {
/** When the user sets the region is hidden,
* needed for floating regions that may be hidden for other reasons. */
RGN_FLAG_HIDDEN_BY_USER = (1 << 7),
+ /** Property search filter is active. */
+ RGN_FLAG_SEARCH_FILTER_ACTIVE = (1 << 8),
+ /**
+ * Update the expansion of the region's panels and switch contexts. Only Set
+ * temporarily when the search filter is updated so that interactions are still
+ * interactive, cleared at the end of the region's layout pass.
+ */
+ RGN_FLAG_SEARCH_FILTER_UPDATE = (1 << 9),
};
/** #ARegion.do_draw */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 06ab01a9730..56966ca26d3 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -129,6 +129,11 @@ typedef enum eSpaceInfo_RptMask {
/** \name Properties Editor
* \{ */
+typedef struct SpaceProperties_Runtime {
+ /** For filtering properties displayed in the space. Length defined as UI_MAX_NAME_STR. */
+ char search_string[128];
+} SpaceProperties_Runtime;
+
/* Properties Editor */
typedef struct SpaceProperties {
SpaceLink *next, *prev;
@@ -159,6 +164,8 @@ typedef struct SpaceProperties {
ID *pinid;
void *texuser;
+
+ SpaceProperties_Runtime runtime;
} SpaceProperties;
/* button defines (deprecated) */
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 317759ce418..13b316a9d5d 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -1817,6 +1817,17 @@ static void rna_SpaceProperties_context_update(Main *UNUSED(bmain),
}
}
+static void rna_SpaceProperties_search_filter_update(struct bContext *C,
+ struct PointerRNA *UNUSED(ptr))
+{
+ ScrArea *area = CTX_wm_area(C);
+
+ /* Update the search filter flag for the main region with the panels. */
+ ARegion *main_region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
+ BLI_assert(main_region != NULL);
+ ED_region_search_filter_update(area, main_region);
+}
+
/* Space Console */
static void rna_ConsoleLine_body_get(PointerRNA *ptr, char *value)
{
@@ -4482,6 +4493,15 @@ static void rna_def_space_properties(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_pin_id", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SB_PIN_CONTEXT);
RNA_def_property_ui_text(prop, "Pin ID", "Use the pinned context");
+
+ /* Property search. */
+ prop = RNA_def_property(srna, "search_filter", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "runtime.search_string");
+ RNA_def_property_ui_text(prop, "Display Filter", "Live search filtering string");
+ RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(
+ prop, NC_SPACE | ND_SPACE_PROPERTIES, "rna_SpaceProperties_search_filter_update");
}
static void rna_def_space_image(BlenderRNA *brna)