WIP: UI: Preferences Search #119072
|
@ -63,9 +63,12 @@ class USERPREF_PT_navigation_bar(Panel):
|
|||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
view = context.space_data
|
||||
|
||||
prefs = context.preferences
|
||||
|
||||
layout.prop(view, "search_filter", icon='VIEWZOOM', text="")
|
||||
|
||||
col = layout.column()
|
||||
|
||||
col.scale_x = 1.3
|
||||
|
|
|
@ -9,3 +9,9 @@
|
|||
#pragma once
|
||||
|
||||
void ED_operatortypes_userpref();
|
||||
|
||||
int ED_userpref_tabs_list(SpaceUserPref *sprefs, short *context_tabs_array);
|
||||
bool ED_userpref_tab_has_search_result(SpaceUserPref *sprefs, int index);
|
||||
void ED_userpref_search_string_set(SpaceUserPref *sprefs, const char *value);
|
||||
int ED_userpref_search_string_length(SpaceUserPref *sprefs);
|
||||
const char *ED_userpref_search_string_get(SpaceUserPref *sprefs);
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "ED_screen_types.hh"
|
||||
#include "ED_space_api.hh"
|
||||
#include "ED_time_scrub_ui.hh"
|
||||
#include "ED_userpref.hh"
|
||||
|
||||
#include "GPU_framebuffer.h"
|
||||
#include "GPU_immediate.h"
|
||||
|
@ -776,13 +777,18 @@ void ED_area_tag_region_size_update(ScrArea *area, ARegion *changed_region)
|
|||
|
||||
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 = static_cast<SpaceProperties *>(area->spacedata.first);
|
||||
if (region->regiontype == RGN_TYPE_WINDOW) {
|
||||
return ED_buttons_search_string_get(sbuts);
|
||||
}
|
||||
}
|
||||
else if (area->spacetype == SPACE_USERPREF) {
|
||||
SpaceUserPref *sprefs = static_cast<SpaceUserPref *>(area->spacedata.first);
|
||||
if (region->regiontype == RGN_TYPE_WINDOW) {
|
||||
return ED_userpref_search_string_get(sprefs);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
|
@ -29,6 +30,8 @@
|
|||
|
||||
#include "BLO_read_write.hh"
|
||||
|
||||
#include "userpref_intern.h"
|
||||
|
||||
/* ******************** default callbacks for userpref space ***************** */
|
||||
|
||||
static SpaceLink *userpref_create(const ScrArea *area, const Scene * /*scene*/)
|
||||
|
@ -77,18 +80,39 @@ static SpaceLink *userpref_create(const ScrArea *area, const Scene * /*scene*/)
|
|||
}
|
||||
|
||||
/* Doesn't free the space-link itself. */
|
||||
static void userpref_free(SpaceLink * /*sl*/)
|
||||
static void userpref_free(SpaceLink *sl)
|
||||
{
|
||||
// SpaceUserPref *spref = (SpaceUserPref *)sl;
|
||||
SpaceUserPref *spref = (SpaceUserPref *)sl;
|
||||
if (spref->runtime != nullptr) {
|
||||
MEM_SAFE_FREE(spref->runtime->tab_search_results);
|
||||
MEM_freeN(spref->runtime);
|
||||
}
|
||||
}
|
||||
|
||||
/* spacetype; init callback */
|
||||
static void userpref_init(wmWindowManager * /*wm*/, ScrArea * /*area*/) {}
|
||||
static void userpref_init(wmWindowManager * /*wm*/, ScrArea *area)
|
||||
{
|
||||
SpaceUserPref *spref = (SpaceUserPref *)area->spacedata.first;
|
||||
|
||||
if (spref->runtime == nullptr) {
|
||||
spref->runtime = static_cast<SpaceUserPref_Runtime *>(
|
||||
MEM_mallocN(sizeof(SpaceUserPref_Runtime), __func__));
|
||||
spref->runtime->search_string[0] = '\0';
|
||||
spref->runtime->tab_search_results = BLI_BITMAP_NEW(BCONTEXT_TOT * 2, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
static SpaceLink *userpref_duplicate(SpaceLink *sl)
|
||||
{
|
||||
SpaceUserPref *sprefn_old = (SpaceUserPref *)sl;
|
||||
SpaceUserPref *sprefn = static_cast<SpaceUserPref *>(MEM_dupallocN(sl));
|
||||
|
||||
if (sprefn_old->runtime != nullptr) {
|
||||
sprefn->runtime = static_cast<SpaceUserPref_Runtime *>(MEM_dupallocN(sprefn_old->runtime));
|
||||
sprefn->runtime->search_string[0] = '\0';
|
||||
sprefn->runtime->tab_search_results = BLI_BITMAP_NEW(BCONTEXT_TOT, __func__);
|
||||
}
|
||||
|
||||
/* clear or remove stuff from old */
|
||||
|
||||
return (SpaceLink *)sprefn;
|
||||
|
@ -106,10 +130,227 @@ static void userpref_main_region_init(wmWindowManager *wm, ARegion *region)
|
|||
ED_region_panels_init(wm, region);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Userpref Search Access API
|
||||
* \{ */
|
||||
|
||||
const char *ED_userpref_search_string_get(SpaceUserPref *spref)
|
||||
{
|
||||
return spref->runtime->search_string;
|
||||
}
|
||||
|
||||
int ED_userpref_search_string_length(SpaceUserPref *spref)
|
||||
{
|
||||
return BLI_strnlen(spref->runtime->search_string, sizeof(spref->runtime->search_string));
|
||||
}
|
||||
|
||||
void ED_userpref_search_string_set(SpaceUserPref *spref, const char *value)
|
||||
{
|
||||
STRNCPY(spref->runtime->search_string, value);
|
||||
}
|
||||
|
||||
bool ED_userpref_tab_has_search_result(SpaceUserPref *spref, const int index)
|
||||
{
|
||||
return BLI_BITMAP_TEST(spref->runtime->tab_search_results, index);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
int ED_userpref_tabs_list(SpaceUserPref *prefs, short *context_tabs_array)
|
||||
{
|
||||
int length = 0;
|
||||
const EnumPropertyItem *items = rna_enum_preference_section_items;
|
||||
for (const EnumPropertyItem *it = rna_enum_preference_section_items; it->identifier != nullptr;
|
||||
it++)
|
||||
{
|
||||
if (it->name) {
|
||||
context_tabs_array[length] = it->value;
|
||||
length++;
|
||||
}
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name "Off Screen" Layout Generation for Userpref Search
|
||||
* \{ */
|
||||
|
||||
static const char *userpref_main_region_context_string(const short section) {}
|
||||
|
||||
static bool userpref_search_for_context(const bContext *C,
|
||||
ARegion *region,
|
||||
SpaceUserPref *sprefs,
|
||||
short section)
|
||||
{
|
||||
char lower[64];
|
||||
const char *name = nullptr;
|
||||
RNA_enum_id_from_value(rna_enum_preference_section_items, section, &name);
|
||||
STRNCPY(lower, name);
|
||||
BLI_str_tolower_ascii(lower, strlen(lower));
|
||||
|
||||
const char *contexts[2] = {lower, nullptr};
|
||||
return ED_region_property_search(C, region, ®ion->type->paneltypes, contexts, nullptr);
|
||||
}
|
||||
|
||||
static void userpref_search_move_to_next_tab_with_results(SpaceUserPref *sbuts,
|
||||
const short *context_tabs_array,
|
||||
const int tabs_len)
|
||||
{
|
||||
int current_tab_index = 0;
|
||||
for (int i = 0; i < tabs_len; i++) {
|
||||
if (U.space_data.section_active == context_tabs_array[i]) {
|
||||
current_tab_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try the tabs after the current tab. */
|
||||
for (int i = current_tab_index + 1; i < tabs_len; i++) {
|
||||
if (BLI_BITMAP_TEST(sbuts->runtime->tab_search_results, i)) {
|
||||
U.space_data.section_active = 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)) {
|
||||
U.space_data.section_active = context_tabs_array[i];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool userpref_search_move_to_first_tab_with_results(SpaceUserPref *sbuts,
|
||||
const short *context_tabs_array,
|
||||
const int tabs_len)
|
||||
{
|
||||
int current_tab_index = 0;
|
||||
for (int i = 0; i < tabs_len; i++) {
|
||||
if (U.space_data.section_active == context_tabs_array[i]) {
|
||||
current_tab_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)) {
|
||||
U.space_data.section_active = context_tabs_array[i];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void userpref_search_all_tabs(const bContext *C,
|
||||
SpaceUserPref *sprefs,
|
||||
ARegion *region_original,
|
||||
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_original = CTX_wm_area(C);
|
||||
ScrArea area_copy = blender::dna::shallow_copy(*area_original);
|
||||
ARegion *region_copy = BKE_area_region_copy(area_copy.type, region_original);
|
||||
/* Set the region visible field. Otherwise some layout code thinks we're drawing in a popup.
|
||||
* This likely isn't necessary, but it's nice to emulate a "real" region where possible. */
|
||||
region_copy->visible = true;
|
||||
CTX_wm_area_set((bContext *)C, &area_copy);
|
||||
CTX_wm_region_set((bContext *)C, region_copy);
|
||||
|
||||
SpaceUserPref sprefs_copy = blender::dna::shallow_copy(*sprefs);
|
||||
sprefs_copy.runtime = static_cast<SpaceUserPref_Runtime *>(MEM_dupallocN(sprefs->runtime));
|
||||
sprefs_copy.runtime->tab_search_results = nullptr;
|
||||
BLI_listbase_clear(&area_copy.spacedata);
|
||||
BLI_addtail(&area_copy.spacedata, &sprefs_copy);
|
||||
|
||||
/* Loop through the tabs. */
|
||||
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] == U.space_data.section_active) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Actually do the search and store the result in the bitmap. */
|
||||
const bool found = userpref_search_for_context(
|
||||
C, region_copy, &sprefs_copy, context_tabs_array[i]);
|
||||
BLI_BITMAP_SET(sprefs->runtime->tab_search_results, i, found);
|
||||
|
||||
UI_blocklist_free(C, region_copy);
|
||||
}
|
||||
|
||||
BKE_area_region_free(area_copy.type, region_copy);
|
||||
MEM_freeN(region_copy);
|
||||
userpref_free((SpaceLink *)&sprefs_copy);
|
||||
|
||||
CTX_wm_area_set((bContext *)C, area_original);
|
||||
CTX_wm_region_set((bContext *)C, region_original);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle userpref 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 userpref_main_region_property_search(const bContext *C,
|
||||
SpaceUserPref *sprefs,
|
||||
ARegion *region)
|
||||
{
|
||||
short context_tabs_array[50];
|
||||
int tabs_len = 0;
|
||||
tabs_len = ED_userpref_tabs_list(sprefs, context_tabs_array);
|
||||
BLI_bitmap_set_all(sprefs->runtime->tab_search_results, false, tabs_len);
|
||||
|
||||
userpref_search_all_tabs(C, sprefs, 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] == U.space_data.section_active) {
|
||||
current_tab_index = i;
|
||||
}
|
||||
}
|
||||
BLI_assert(current_tab_index != -1);
|
||||
|
||||
/* Update the tab search match flag for the current tab. */
|
||||
BLI_BITMAP_SET(
|
||||
sprefs->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) {
|
||||
userpref_search_move_to_next_tab_with_results(sprefs, context_tabs_array, tabs_len);
|
||||
}
|
||||
else {
|
||||
U.space_data.section_active = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
static void userpref_main_region_layout(const bContext *C, ARegion *region)
|
||||
{
|
||||
char id_lower[64];
|
||||
const char *contexts[2] = {id_lower, nullptr};
|
||||
SpaceUserPref *spref = CTX_wm_space_userpref(C);
|
||||
|
||||
/* Avoid duplicating identifiers, use existing RNA enum. */
|
||||
{
|
||||
|
@ -127,6 +368,10 @@ static void userpref_main_region_layout(const bContext *C, ARegion *region)
|
|||
|
||||
ED_region_panels_layout_ex(
|
||||
C, region, ®ion->type->paneltypes, WM_OP_INVOKE_REGION_WIN, contexts, nullptr);
|
||||
|
||||
if (region->flag & RGN_FLAG_SEARCH_FILTER_ACTIVE) {
|
||||
userpref_main_region_property_search(C, spref, region);
|
||||
}
|
||||
}
|
||||
|
||||
static void userpref_operatortypes() {}
|
||||
|
|
|
@ -8,4 +8,16 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_bitmap.h"
|
||||
|
||||
/* internal exports only */
|
||||
|
||||
struct SpaceUserPref_Runtime {
|
||||
/** For filtering properties displayed in the space. */
|
||||
char search_string[128];
|
||||
/**
|
||||
* Bit-field (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;
|
||||
};
|
||||
|
|
|
@ -56,6 +56,9 @@ typedef struct AssetRepresentationHandle AssetRepresentationHandle;
|
|||
/** Defined in `buttons_intern.h`. */
|
||||
typedef struct SpaceProperties_Runtime SpaceProperties_Runtime;
|
||||
|
||||
/** Defined in `userpref_intern.h`. */
|
||||
typedef struct SpaceUserPref_Runtime SpaceUserPref_Runtime;
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace blender::ed::space_node {
|
||||
struct SpaceNode_Runtime;
|
||||
|
@ -1723,6 +1726,7 @@ typedef struct SpaceConsole {
|
|||
* \{ */
|
||||
|
||||
typedef struct SpaceUserPref {
|
||||
DNA_DEFINE_CXX_METHODS(SpaceUserPref)
|
||||
SpaceLink *next, *prev;
|
||||
/** Storage of regions for inactive spaces. */
|
||||
ListBase regionbase;
|
||||
|
@ -1735,6 +1739,7 @@ typedef struct SpaceUserPref {
|
|||
char filter_type;
|
||||
/** Search term for filtering in the UI. */
|
||||
char filter[64];
|
||||
struct SpaceUserPref_Runtime *runtime;
|
||||
} SpaceUserPref;
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "ED_asset.hh"
|
||||
#include "ED_spreadsheet.hh"
|
||||
#include "ED_text.hh"
|
||||
#include "ED_userpref.hh"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
|
@ -2133,6 +2134,67 @@ static void rna_SpaceProperties_search_filter_update(Main * /*bmain*/,
|
|||
ED_region_search_filter_update(area, main_region);
|
||||
}
|
||||
|
||||
/* Space Userpref */
|
||||
|
||||
static int rna_SpaceUserPref_tab_search_results_getlength(const PointerRNA *ptr,
|
||||
int length[RNA_MAX_ARRAY_DIMENSION])
|
||||
{
|
||||
SpaceUserPref *sprefs = static_cast<SpaceUserPref *>(ptr->data);
|
||||
|
||||
short context_tabs_array[BCONTEXT_TOT * 2]; /* Dummy variable. */
|
||||
const int tabs_len = ED_userpref_tabs_list(sprefs, context_tabs_array);
|
||||
|
||||
length[0] = tabs_len;
|
||||
|
||||
return length[0];
|
||||
}
|
||||
|
||||
static void rna_SpaceUserPref_tab_search_results_get(PointerRNA *ptr, bool *values)
|
||||
{
|
||||
SpaceUserPref *sprefs = static_cast<SpaceUserPref *>(ptr->data);
|
||||
|
||||
short context_tabs_array[BCONTEXT_TOT * 2]; /* Dummy variable. */
|
||||
const int tabs_len = ED_userpref_tabs_list(sprefs, context_tabs_array);
|
||||
|
||||
for (int i = 0; i < tabs_len; i++) {
|
||||
values[i] = ED_userpref_tab_has_search_result(sprefs, i);
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_SpaceUserPref_search_filter_get(PointerRNA *ptr, char *value)
|
||||
{
|
||||
SpaceUserPref *sprefs = static_cast<SpaceUserPref *>(ptr->data);
|
||||
const char *search_filter = ED_userpref_search_string_get(sprefs);
|
||||
|
||||
strcpy(value, search_filter);
|
||||
}
|
||||
|
||||
static int rna_SpaceUserPref_search_filter_length(PointerRNA *ptr)
|
||||
{
|
||||
SpaceUserPref *sprefs = static_cast<SpaceUserPref *>(ptr->data);
|
||||
|
||||
return ED_userpref_search_string_length(sprefs);
|
||||
}
|
||||
|
||||
static void rna_SpaceUserPref_search_filter_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
SpaceUserPref *sprefs = static_cast<SpaceUserPref *>(ptr->data);
|
||||
|
||||
ED_userpref_search_string_set(sprefs, value);
|
||||
}
|
||||
|
||||
static void rna_SpaceUserPref_search_filter_update(Main * /*bmain*/,
|
||||
Scene * /*scene*/,
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
ScrArea *area = rna_area_from_space(ptr);
|
||||
|
||||
/* 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 != nullptr);
|
||||
ED_region_search_filter_update(area, main_region);
|
||||
}
|
||||
|
||||
/* Space Console */
|
||||
static void rna_ConsoleLine_body_get(PointerRNA *ptr, char *value)
|
||||
{
|
||||
|
@ -7345,6 +7407,18 @@ static void rna_def_space_userpref(BlenderRNA *brna)
|
|||
RNA_def_property_string_sdna(prop, nullptr, "filter");
|
||||
RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE);
|
||||
RNA_def_property_ui_text(prop, "Filter", "Search term for filtering in the UI");
|
||||
|
||||
prop = RNA_def_property(srna, "search_filter", PROP_STRING, PROP_NONE);
|
||||
/* The search filter is stored in the property editor's runtime which
|
||||
* is only defined in an internal header, so use the getter / setter here. */
|
||||
RNA_def_property_string_funcs(prop,
|
||||
"rna_SpaceUserPref_search_filter_get",
|
||||
"rna_SpaceUserPref_search_filter_length",
|
||||
"rna_SpaceUserPref_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(
|
||||
prop, NC_SPACE | ND_SPACE_PROPERTIES, "rna_SpaceUserPref_search_filter_update");
|
||||
}
|
||||
|
||||
static void rna_def_node_tree_path(BlenderRNA *brna)
|
||||
|
|
Loading…
Reference in New Issue