diff options
-rw-r--r-- | release/scripts/startup/bl_ui/space_properties.py | 6 | ||||
-rw-r--r-- | source/blender/editors/include/ED_buttons.h | 5 | ||||
-rw-r--r-- | source/blender/editors/include/ED_screen.h | 5 | ||||
-rw-r--r-- | source/blender/editors/include/UI_interface.h | 1 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_layout.c | 13 | ||||
-rw-r--r-- | source/blender/editors/screen/area.c | 146 | ||||
-rw-r--r-- | source/blender/editors/space_buttons/buttons_intern.h | 11 | ||||
-rw-r--r-- | source/blender/editors/space_buttons/space_buttons.c | 174 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_space_types.h | 12 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_space.c | 64 |
10 files changed, 423 insertions, 14 deletions
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(®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(); diff --git a/source/blender/editors/space_buttons/buttons_intern.h b/source/blender/editors/space_buttons/buttons_intern.h index a5419fea5ca..0a0846cf216 100644 --- a/source/blender/editors/space_buttons/buttons_intern.h +++ b/source/blender/editors/space_buttons/buttons_intern.h @@ -23,6 +23,7 @@ #pragma once +#include "BLI_bitmap.h" #include "DNA_listBase.h" #include "RNA_types.h" @@ -37,6 +38,16 @@ struct bNodeTree; struct uiLayout; struct wmOperatorType; +struct SpaceProperties_Runtime { + /** For filtering properties displayed in the space. */ + char search_string[UI_MAX_NAME_STR]; + /** + * Bitfield (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. + */ + BLI_bitmap *tab_search_results; +}; + /* context data */ typedef struct ButsContextPath { diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 8c1030f6fc4..e7f057683ab 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -26,6 +26,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_bitmap.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" @@ -48,6 +49,7 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "UI_interface.h" #include "UI_resources.h" #include "buttons_intern.h" /* own include */ @@ -110,7 +112,10 @@ static void buttons_free(SpaceLink *sl) MEM_freeN(ct); } - MEM_SAFE_FREE(sbuts->runtime); + if (sbuts->runtime != NULL) { + MEM_SAFE_FREE(sbuts->runtime->tab_search_results); + MEM_freeN(sbuts->runtime); + } } /* spacetype; init callback */ @@ -121,6 +126,7 @@ static void buttons_init(struct wmWindowManager *UNUSED(wm), ScrArea *area) if (sbuts->runtime == NULL) { sbuts->runtime = MEM_mallocN(sizeof(SpaceProperties_Runtime), __func__); sbuts->runtime->search_string[0] = '\0'; + sbuts->runtime->tab_search_results = BLI_BITMAP_NEW(BCONTEXT_TOT * 2, __func__); } } @@ -135,6 +141,7 @@ static SpaceLink *buttons_duplicate(SpaceLink *sl) if (sfile_old->runtime != NULL) { sbutsn->runtime = MEM_dupallocN(sfile_old->runtime); sbutsn->runtime->search_string[0] = '\0'; + sbutsn->runtime->tab_search_results = BLI_BITMAP_NEW(BCONTEXT_TOT, __func__); } return (SpaceLink *)sbutsn; @@ -298,6 +305,163 @@ static void buttons_main_region_layout_properties(const bContext *C, ED_region_panels_layout_ex(C, region, ®ion->type->paneltypes, contexts, NULL); } +const char *ED_buttons_search_string_get(SpaceProperties *sbuts) +{ + return sbuts->runtime->search_string; +} + +int ED_buttons_search_string_length(struct SpaceProperties *sbuts) +{ + return BLI_strnlen(sbuts->runtime->search_string, sizeof(sbuts->runtime->search_string)); +} + +void ED_buttons_search_string_set(SpaceProperties *sbuts, const char *value) +{ + BLI_strncpy(sbuts->runtime->search_string, value, sizeof(sbuts->runtime->search_string)); +} + +bool ED_buttons_tab_has_search_result(SpaceProperties *sbuts, const int index) +{ + return BLI_BITMAP_TEST(sbuts->runtime->tab_search_results, index); +} + +static bool property_search_for_context(const bContext *C, ARegion *region, SpaceProperties *sbuts) +{ + const char *contexts[2] = {buttons_main_region_context_string(sbuts->mainb), NULL}; + + if (sbuts->mainb == BCONTEXT_TOOL) { + return false; + } + + buttons_context_compute(C, sbuts); + return ED_region_property_search(C, region, ®ion->type->paneltypes, contexts, NULL); +} + +static void property_search_move_to_next_tab_with_results(SpaceProperties *sbuts, + const short *context_tabs_array, + const int tabs_len) +{ + /* As long as all-tab search in the tool is disabled in the tool context, don't move from it. */ + if (sbuts->mainb == BCONTEXT_TOOL) { + return; + } + + 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 (BLI_BITMAP_TEST(sbuts->runtime->tab_search_results, 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 (BLI_BITMAP_TEST(sbuts->runtime->tab_search_results, i)) { + sbuts->mainbuser = context_tabs_array[i]; + return; + } + } +} + +static void property_search_all_tabs(const bContext *C, + SpaceProperties *sbuts, + ARegion *main_region, + const short *context_tabs_array, + const int tabs_len) +{ + /* Use local copies of the area and duplicate the region as a mainly-paranoid protection + * against changing any of the space / region data while running the search. */ + ScrArea area_copy = *CTX_wm_area(C); + ARegion *region_copy = BKE_area_region_copy(area_copy.type, main_region); + 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 = *sbuts; + sbuts_copy.path = NULL; + sbuts_copy.texuser = NULL; + sbuts_copy.runtime = MEM_dupallocN(sbuts->runtime); + sbuts_copy.runtime->tab_search_results = NULL; + area_copy.spacedata.first = &sbuts_copy; + + /* Loop through the tabs added to the properties editor. */ + for (int i = 0; i < tabs_len; i++) { + /* -1 corresponds to a spacer. */ + if (context_tabs_array[i] == -1) { + continue; + } + + /* Handle search for the current tab in the normal layout pass. */ + if (context_tabs_array[i] == sbuts->mainb) { + continue; + } + + sbuts_copy.mainb = sbuts_copy.mainbo = sbuts_copy.mainbuser = context_tabs_array[i]; + + /* Actually do the search and store the result in the bitmap. */ + BLI_BITMAP_SET(sbuts->runtime->tab_search_results, + i, + property_search_for_context(C_copy, region_copy, &sbuts_copy)); + + UI_blocklist_free(C_copy, ®ion_copy->uiblocks); + } + + BKE_area_region_free(area_copy.type, region_copy); + MEM_freeN(region_copy); + buttons_free((SpaceLink *)&sbuts_copy); + MEM_freeN(C_copy); +} + +/** + * Handle property search for the layout pass, including finding which tabs have + * search results and switching if the current tab doesn't have a result. + */ +static void buttons_main_region_property_search(const bContext *C, + SpaceProperties *sbuts, + ARegion *region) +{ + /* Theoretical maximum of every context shown with a spacer between every tab. */ + short context_tabs_array[BCONTEXT_TOT * 2]; + int tabs_len = ED_buttons_tabs_list(sbuts, context_tabs_array); + + property_search_all_tabs(C, sbuts, region, context_tabs_array, tabs_len); + + /* Check whether the current tab has a search match. */ + bool current_tab_has_search_match = false; + LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { + if (UI_panel_is_active(panel) && UI_panel_matches_search_filter(panel)) { + current_tab_has_search_match = true; + } + } + + /* Find which index in the list the current tab corresponds to. */ + int current_tab_index = -1; + for (int i = 0; i < tabs_len; i++) { + if (context_tabs_array[i] == sbuts->mainb) { + current_tab_index = i; + } + } + BLI_assert(current_tab_index != -1); + + /* Update the tab search match flag for the current tab. */ + BLI_BITMAP_SET( + sbuts->runtime->tab_search_results, current_tab_index, current_tab_has_search_match); + + /* Move to the next tab with a result */ + if (!current_tab_has_search_match) { + if (region->flag & RGN_FLAG_SEARCH_FILTER_UPDATE) { + property_search_move_to_next_tab_with_results(sbuts, context_tabs_array, tabs_len); + } + } +} + static void buttons_main_region_layout(const bContext *C, ARegion *region) { /* draw entirely, view changes should be handled here */ @@ -310,6 +474,10 @@ static void buttons_main_region_layout(const bContext *C, ARegion *region) buttons_main_region_layout_properties(C, sbuts, region); } + if (region->flag & RGN_FLAG_SEARCH_FILTER_ACTIVE) { + buttons_main_region_property_search(C, sbuts, region); + } + sbuts->mainbo = sbuts->mainb; } @@ -722,8 +890,8 @@ void ED_spacetype_buttons(void) buttons_context_register(art); BLI_addhead(&st->regiontypes, art); - /* Register the panel types from modifiers. The actual panels are built per modifier rather than - * per modifier type. */ + /* Register the panel types from modifiers. The actual panels are built per modifier rather + * than per modifier type. */ for (ModifierType i = 0; i < NUM_MODIFIER_TYPES; i++) { const ModifierTypeInfo *mti = BKE_modifier_get_info(i); if (mti != NULL && mti->panelRegister != NULL) { diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 9d9b41a1f81..be02e450412 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -56,6 +56,9 @@ struct bNodeTree; struct wmOperator; struct wmTimer; +/* Defined in `buttons_intern.h`. */ +typedef struct SpaceProperties_Runtime SpaceProperties_Runtime; + /* TODO 2.8: We don't write the global areas to files currently. Uncomment * define to enable writing (should become the default in a bit). */ //#define WITH_GLOBAL_AREA_WRITING @@ -129,13 +132,6 @@ 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; @@ -168,7 +164,7 @@ typedef struct SpaceProperties { void *texuser; /* Doesn't necessarily need to be a pointer, but runtime structs are still written to files. */ - SpaceProperties_Runtime *runtime; + struct 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 2a4bc6bae06..5b34281ffa0 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -1825,6 +1825,53 @@ static void rna_SpaceProperties_context_update(Main *UNUSED(bmain), } } +static int rna_SpaceProperties_tab_search_results_getlength(PointerRNA *ptr, + int length[RNA_MAX_ARRAY_DIMENSION]) +{ + SpaceProperties *sbuts = ptr->data; + + short context_tabs_array[BCONTEXT_TOT * 2]; /* Dummy variable. */ + const int tabs_len = ED_buttons_tabs_list(sbuts, context_tabs_array); + + length[0] = tabs_len; + + return length[0]; +} + +static void rna_SpaceProperties_tab_search_results_get(PointerRNA *ptr, bool *values) +{ + SpaceProperties *sbuts = ptr->data; + + short context_tabs_array[BCONTEXT_TOT * 2]; /* Dummy variable. */ + const int tabs_len = ED_buttons_tabs_list(sbuts, context_tabs_array); + + for (int i = 0; i < tabs_len; i++) { + values[i] = ED_buttons_tab_has_search_result(sbuts, i); + } +} + +static void rna_SpaceProperties_search_filter_get(PointerRNA *ptr, char *value) +{ + SpaceProperties *sbuts = ptr->data; + const char *search_filter = ED_buttons_search_string_get(sbuts); + + strcpy(value, search_filter); +} + +static int rna_SpaceProperties_search_filter_length(PointerRNA *ptr) +{ + SpaceProperties *sbuts = ptr->data; + + return ED_buttons_search_string_length(sbuts); +} + +static void rna_SpaceProperties_search_filter_set(struct PointerRNA *ptr, const char *value) +{ + SpaceProperties *sbuts = ptr->data; + + ED_buttons_search_string_set(sbuts, value); +} + static void rna_SpaceProperties_search_filter_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) @@ -4514,8 +4561,23 @@ 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, "tab_search_results", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_array(prop, 0); /* Dynamic length, see next line. */ + RNA_def_property_flag(prop, PROP_DYNAMIC); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_boolean_funcs(prop, "rna_SpaceProperties_tab_search_results_get", NULL); + RNA_def_property_dynamic_array_funcs(prop, "rna_SpaceProperties_tab_search_results_getlength"); + RNA_def_property_ui_text( + prop, "Tab Search Results", "Whether or not each visible tab has a search result"); + prop = RNA_def_property(srna, "search_filter", PROP_STRING, PROP_NONE); - RNA_def_property_string_sdna(prop, NULL, "runtime->search_string"); + /* The search filter is stored in the property editor's runtime struct which + * is only defined in an internal header, so use the getter / setter here. */ + RNA_def_property_string_funcs(prop, + "rna_SpaceProperties_search_filter_get", + "rna_SpaceProperties_search_filter_length", + "rna_SpaceProperties_search_filter_set"); RNA_def_property_ui_text(prop, "Display Filter", "Live search filtering string"); RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE); RNA_def_property_update( |