diff options
Diffstat (limited to 'source/blender/editors/screen/area.c')
-rw-r--r-- | source/blender/editors/screen/area.c | 146 |
1 files changed, 145 insertions, 1 deletions
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(®ion->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, ®ion->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, ®ion->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, ®ion->uiblocks); + UI_panels_free_instanced(C, region); + BKE_area_region_panels_free(®ion->panels); + + return has_result; +} + void ED_region_header_layout(const bContext *C, ARegion *region) { const uiStyle *style = UI_style_get_dpi(); |