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:
authorJulian Eisel <eiseljulian@gmail.com>2017-05-12 02:42:42 +0300
committerJulian Eisel <eiseljulian@gmail.com>2017-05-12 02:47:55 +0300
commitc20c203b82260c06888c2a535c08ec383923ee8a (patch)
treebc6dba9408a4c37d2105c9a91f4dd5d29f077424
parentc8ab7d46566c4a65c6176cd2ebe27778512f7fef (diff)
UI: Add template_search (version of template_ID for non-IDs)
Adds a version of template_ID that can be used for non-ID properties. The property to search for and the collection to search in has to be passed to it. Like template_ID it also takes arguments to define a 'new' and 'unlink' operator. They will be displayed as icon-only buttons then. Also added a version that can display preview thumbnails. Had to do some additional changes to make text-buttons support displaying/modifying empty RNA properties. This will be needed for workspaces, see D2451. Reviewed By: campbellbarton Differential Revision: https://developer.blender.org/D2666
-rw-r--r--source/blender/editors/include/UI_interface.h11
-rw-r--r--source/blender/editors/interface/interface.c21
-rw-r--r--source/blender/editors/interface/interface_handlers.c3
-rw-r--r--source/blender/editors/interface/interface_intern.h19
-rw-r--r--source/blender/editors/interface/interface_layout.c102
-rw-r--r--source/blender/editors/interface/interface_templates.c421
-rw-r--r--source/blender/editors/interface/interface_utils.c85
-rw-r--r--source/blender/makesrna/RNA_access.h4
-rw-r--r--source/blender/makesrna/intern/rna_ID.c2
-rw-r--r--source/blender/makesrna/intern/rna_access.c5
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c26
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c11
12 files changed, 518 insertions, 192 deletions
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index ee15413b4d0..b3c95aa0712 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -912,6 +912,17 @@ void uiTemplateIDPreview(uiLayout *layout, struct bContext *C, struct PointerRNA
const char *newop, const char *openop, const char *unlinkop, int rows, int cols);
void uiTemplateAnyID(uiLayout *layout, struct PointerRNA *ptr, const char *propname,
const char *proptypename, const char *text);
+void uiTemplateSearch(
+ uiLayout *layout, struct bContext *C,
+ struct PointerRNA *ptr, const char *propname,
+ struct PointerRNA *searchptr, const char *searchpropname,
+ const char *newop, const char *unlinkop);
+void uiTemplateSearchPreview(
+ uiLayout *layout, struct bContext *C,
+ struct PointerRNA *ptr, const char *propname,
+ struct PointerRNA *searchptr, const char *searchpropname,
+ const char *newop, const char *unlinkop,
+ const int rows, const int cols);
void uiTemplatePathBuilder(uiLayout *layout, struct PointerRNA *ptr, const char *propname,
struct PointerRNA *root_ptr, const char *text);
uiLayout *uiTemplateModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index e1ca6c60a74..562a2f6e32c 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -2373,7 +2373,7 @@ static void ui_but_string_free_internal(uiBut *but)
bool ui_but_string_set(bContext *C, uiBut *but, const char *str)
{
- if (but->rnaprop && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
+ if (but->rnaprop && but->rnapoin.data && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
if (RNA_property_editable(&but->rnapoin, but->rnaprop)) {
PropertyType type;
@@ -2420,8 +2420,15 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str)
}
else if (but->type == UI_BTYPE_TEXT) {
/* string */
- if (ui_but_is_utf8(but)) BLI_strncpy_utf8(but->poin, str, but->hardmax);
- else BLI_strncpy(but->poin, str, but->hardmax);
+ if (!but->poin || (str[0] == '\0')) {
+ str = "";
+ }
+ else if (ui_but_is_utf8(but)) {
+ BLI_strncpy_utf8(but->poin, str, but->hardmax);
+ }
+ else {
+ BLI_strncpy(but->poin, str, but->hardmax);
+ }
return true;
}
@@ -2627,6 +2634,10 @@ static void ui_but_free(const bContext *C, uiBut *but)
MEM_freeN(but->tip_argN);
}
+ if (!but->editstr && but->free_search_arg) {
+ MEM_SAFE_FREE(but->search_arg);
+ }
+
if (but->active) {
/* XXX solve later, buttons should be free-able without context ideally,
* however they may have open tooltips or popup windows, which need to
@@ -3499,7 +3510,7 @@ static uiBut *ui_def_but_rna(
}
const char *info;
- if (!RNA_property_editable_info(&but->rnapoin, prop, &info)) {
+ if (but->rnapoin.data && !RNA_property_editable_info(&but->rnapoin, prop, &info)) {
ui_def_but_rna__disable(but, info);
}
@@ -4522,7 +4533,7 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
tmp = BLI_strdup(RNA_property_identifier(but->rnaprop));
}
else if (type == BUT_GET_RNASTRUCT_IDENTIFIER) {
- if (but->rnaprop)
+ if (but->rnaprop && but->rnapoin.data)
tmp = BLI_strdup(RNA_struct_identifier(but->rnapoin.type));
else if (but->optype)
tmp = BLI_strdup(but->optype->idname);
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index ca0a5ffcbfc..6dcdb312256 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -3159,6 +3159,9 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
ui_searchbox_free(C, data->searchbox);
data->searchbox = NULL;
+ if (but->free_search_arg) {
+ MEM_SAFE_FREE(but->search_arg);
+ }
}
but->editstr = NULL;
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 68bb48f66fb..ace3bb5b4f8 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -259,6 +259,7 @@ struct uiBut {
uiButSearchCreateFunc search_create_func;
uiButSearchFunc search_func;
+ bool free_search_arg;
void *search_arg;
uiButHandleRenameFunc rename_func;
@@ -278,7 +279,7 @@ struct uiBut {
BIFIconID icon;
char dt; /* drawtype: UI_EMBOSS, UI_EMBOSS_NONE ... etc, copied from the block */
signed char pie_dir; /* direction in a pie menu, used for collision detection (RadialDirection) */
- char changed; /* could be made into a single flag */
+ bool changed; /* could be made into a single flag */
unsigned char unit_type; /* so buttons can support unit systems which are not RNA */
short modifier_key;
short iconadd;
@@ -748,4 +749,20 @@ void UI_OT_eyedropper_id(struct wmOperatorType *ot);
void UI_OT_eyedropper_depth(struct wmOperatorType *ot);
void UI_OT_eyedropper_driver(struct wmOperatorType *ot);
+/* interface_util.c */
+
+/**
+ * For use with #ui_rna_collection_search_cb.
+ */
+typedef struct uiRNACollectionSearch {
+ PointerRNA target_ptr;
+ PropertyRNA *target_prop;
+
+ PointerRNA search_ptr;
+ PropertyRNA *search_prop;
+
+ bool *but_changed; /* pointer to uiBut.changed */
+} uiRNACollectionSearch;
+void ui_rna_collection_search_cb(const struct bContext *C, void *arg, const char *str, uiSearchItems *items);
+
#endif /* __INTERFACE_INTERN_H__ */
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 30a2094fee7..5462043c961 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -1574,95 +1574,6 @@ void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname
/* Pointer RNA button with search */
-typedef struct CollItemSearch {
- struct CollItemSearch *next, *prev;
- char *name;
- int index;
- int iconid;
-} CollItemSearch;
-
-static int sort_search_items_list(const void *a, const void *b)
-{
- const CollItemSearch *cis1 = a;
- const CollItemSearch *cis2 = b;
-
- if (BLI_strcasecmp(cis1->name, cis2->name) > 0)
- return 1;
- else
- return 0;
-}
-
-static void rna_search_cb(const struct bContext *C, void *arg_but, const char *str, uiSearchItems *items)
-{
- uiBut *but = arg_but;
- char *name;
- int i = 0, iconid = 0, flag = RNA_property_flag(but->rnaprop);
- ListBase *items_list = MEM_callocN(sizeof(ListBase), "items_list");
- CollItemSearch *cis;
- const bool skip_filter = !but->changed;
-
- /* build a temporary list of relevant items first */
- RNA_PROP_BEGIN (&but->rnasearchpoin, itemptr, but->rnasearchprop)
- {
- if (flag & PROP_ID_SELF_CHECK)
- if (itemptr.data == but->rnapoin.id.data)
- continue;
-
- /* use filter */
- if (RNA_property_type(but->rnaprop) == PROP_POINTER) {
- if (RNA_property_pointer_poll(&but->rnapoin, but->rnaprop, &itemptr) == 0)
- continue;
- }
-
- if (itemptr.type && RNA_struct_is_ID(itemptr.type)) {
- ID *id = itemptr.data;
- char name_ui[MAX_ID_NAME];
-
-#if 0 /* this name is used for a string comparison and can't be modified, TODO */
- /* if ever enabled, make name_ui be MAX_ID_NAME+1 */
- BKE_id_ui_prefix(name_ui, id);
-#else
- BLI_strncpy(name_ui, id->name + 2, sizeof(name_ui));
-#endif
- name = BLI_strdup(name_ui);
- iconid = ui_id_icon_get(C, id, false);
- }
- else {
- name = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL); /* could use the string length here */
- iconid = 0;
- }
-
- if (name) {
- if (skip_filter || BLI_strcasestr(name, str)) {
- cis = MEM_callocN(sizeof(CollItemSearch), "CollectionItemSearch");
- cis->name = MEM_dupallocN(name);
- cis->index = i;
- cis->iconid = iconid;
- BLI_addtail(items_list, cis);
- }
- MEM_freeN(name);
- }
-
- i++;
- }
- RNA_PROP_END;
-
- BLI_listbase_sort(items_list, sort_search_items_list);
-
- /* add search items from temporary list */
- for (cis = items_list->first; cis; cis = cis->next) {
- if (false == UI_search_item_add(items, cis->name, SET_INT_IN_POINTER(cis->index), cis->iconid)) {
- break;
- }
- }
-
- for (cis = items_list->first; cis; cis = cis->next) {
- MEM_freeN(cis->name);
- }
- BLI_freelistN(items_list);
- MEM_freeN(items_list);
-}
-
static void search_id_collection(StructRNA *ptype, PointerRNA *ptr, PropertyRNA **prop)
{
StructRNA *srna;
@@ -1703,6 +1614,8 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN
/* turn button into search button */
if (searchprop) {
+ uiRNACollectionSearch *coll_search = MEM_mallocN(sizeof(*coll_search), __func__);
+
but->type = UI_BTYPE_SEARCH_MENU;
but->hardmax = MAX2(but->hardmax, 256.0f);
but->rnasearchpoin = *searchptr;
@@ -1712,13 +1625,22 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN
but->flag |= UI_BUT_VALUE_CLEAR;
}
+ coll_search->target_ptr = *ptr;
+ coll_search->target_prop = prop;
+ coll_search->search_ptr = *searchptr;
+ coll_search->search_prop = searchprop;
+ coll_search->but_changed = &but->changed;
+
if (RNA_property_type(prop) == PROP_ENUM) {
/* XXX, this will have a menu string,
* but in this case we just want the text */
but->str[0] = 0;
}
- UI_but_func_search_set(but, ui_searchbox_create_generic, rna_search_cb, but, NULL, NULL);
+ UI_but_func_search_set(
+ but, ui_searchbox_create_generic, ui_rna_collection_search_cb,
+ coll_search, NULL, NULL);
+ but->free_search_arg = true;
}
}
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index e3a71feb1a9..266d8aacae3 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -89,10 +89,126 @@
#include "PIL_time.h"
+/* defines for templateID/TemplateSearch */
+#define TEMPLATE_SEARCH_TEXTBUT_WIDTH (UI_UNIT_X * 6)
+#define TEMPLATE_SEARCH_TEXTBUT_HEIGHT UI_UNIT_Y
+
+
void UI_template_fix_linking(void)
{
}
+/**
+ * Add a block button for the search menu for templateID and templateSearch.
+ */
+static void template_add_button_search_menu(
+ const bContext *C, uiLayout *layout, uiBlock *block,
+ PointerRNA *ptr, PropertyRNA *prop,
+ uiBlockCreateFunc block_func, void *block_argN, const char * const tip,
+ const bool use_previews, const bool editable)
+{
+ PointerRNA active_ptr = RNA_property_pointer_get(ptr, prop);
+ ID *id = (active_ptr.data && RNA_struct_is_ID(active_ptr.type)) ? active_ptr.data : NULL;
+ const ID *idfrom = ptr->id.data;
+ const StructRNA *type = active_ptr.type ? active_ptr.type : RNA_property_pointer_type(ptr, prop);
+ uiBut *but;
+
+ if (use_previews) {
+ ARegion *region = CTX_wm_region(C);
+ const bool use_big_size = (region->regiontype != RGN_TYPE_HEADER); /* silly check, could be more generic */
+ /* Ugly exception for screens here, drawing their preview in icon size looks ugly/useless */
+ const bool use_preview_icon = use_big_size || (id && (GS(id->name) != ID_SCR));
+ const short width = UI_UNIT_X * (use_big_size ? 6 : 1.6f);
+ const short height = UI_UNIT_Y * (use_big_size ? 6: 1);
+
+ but = uiDefBlockButN(block, block_func, block_argN, "", 0, 0, width, height, tip);
+ if (use_preview_icon) {
+ int icon = id ? ui_id_icon_get(C, id, use_big_size) : RNA_struct_ui_icon(type);
+ ui_def_but_icon(but, icon, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
+ }
+ else {
+ ui_def_but_icon(but, RNA_struct_ui_icon(type), UI_HAS_ICON);
+ UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
+ }
+
+ if ((idfrom && idfrom->lib) || !editable)
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
+ if (use_big_size) {
+ uiLayoutRow(layout, true);
+ }
+ }
+ else {
+ but = uiDefBlockButN(block, block_func, block_argN, "", 0, 0, UI_UNIT_X * 1.6, UI_UNIT_Y, tip);
+ ui_def_but_icon(but, RNA_struct_ui_icon(type), UI_HAS_ICON);
+ if (id) {
+ /* default dragging of icon for id browse buttons */
+ UI_but_drag_set_id(but, id);
+ }
+ UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
+
+ if ((idfrom && idfrom->lib) || !editable)
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
+ }
+}
+
+static uiBlock *template_common_search_menu(
+ const bContext *C, ARegion *region,
+ uiButSearchFunc search_func, void *search_arg,
+ uiButHandleFunc handle_func, void *active_item,
+ const int preview_rows, const int preview_cols)
+{
+ static char search[256];
+ wmWindow *win = CTX_wm_window(C);
+ uiBlock *block;
+ uiBut *but;
+
+ /* clear initial search string, then all items show */
+ search[0] = 0;
+
+ block = UI_block_begin(C, region, "_popup", UI_EMBOSS);
+ UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_SEARCH_MENU);
+
+ /* preview thumbnails */
+ if (preview_rows > 0 && preview_cols > 0) {
+ const int w = 4 * U.widget_unit * preview_cols;
+ const int h = 5 * U.widget_unit * preview_rows;
+
+ /* fake button, it holds space for search items */
+ uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 26, w, h, NULL, 0, 0, 0, 0, NULL);
+
+ but = uiDefSearchBut(
+ block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, w, UI_UNIT_Y,
+ preview_rows, preview_cols, "");
+ }
+ /* list view */
+ else {
+ const int searchbox_width = UI_searchbox_size_x();
+ const int searchbox_height = UI_searchbox_size_y();
+
+ /* fake button, it holds space for search items */
+ uiDefBut(
+ block, UI_BTYPE_LABEL, 0, "", 10, 15, searchbox_width, searchbox_height,
+ NULL, 0, 0, 0, 0, NULL);
+ but = uiDefSearchBut(
+ block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0,
+ searchbox_width, UI_UNIT_Y - 1, 0, 0, "");
+ }
+ UI_but_func_search_set(
+ but, ui_searchbox_create_generic, search_func,
+ search_arg, handle_func, active_item);
+
+
+ UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
+ UI_block_direction_set(block, UI_DIR_DOWN);
+
+ /* give search-field focus */
+ UI_but_focus_on_enter_event(win, but);
+ /* this type of search menu requires undo */
+ but->flag |= UI_BUT_UNDO;
+
+ return block;
+}
+
/********************** Header Template *************************/
void uiTemplateHeader(uiLayout *layout, bContext *C)
@@ -174,61 +290,16 @@ static void id_search_cb(const bContext *C, void *arg_template, const char *str,
/* ID Search browse menu, open */
static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
{
- static char search[256];
static TemplateID template;
- PointerRNA idptr;
- wmWindow *win = CTX_wm_window(C);
- uiBlock *block;
- uiBut *but;
-
- /* clear initial search string, then all items show */
- search[0] = 0;
+ PointerRNA active_item_ptr;
+
/* arg_litem is malloced, can be freed by parent button */
template = *((TemplateID *)arg_litem);
-
- /* get active id for showing first item */
- idptr = RNA_property_pointer_get(&template.ptr, template.prop);
+ active_item_ptr = RNA_property_pointer_get(&template.ptr, template.prop);
- block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
- UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_SEARCH_MENU);
-
- /* preview thumbnails */
- if (template.prv_rows > 0 && template.prv_cols > 0) {
- int w = 4 * U.widget_unit * template.prv_cols;
- int h = 5 * U.widget_unit * template.prv_rows;
-
- /* fake button, it holds space for search items */
- uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 26, w, h, NULL, 0, 0, 0, 0, NULL);
-
- but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, w, UI_UNIT_Y,
- template.prv_rows, template.prv_cols, "");
- UI_but_func_search_set(
- but, ui_searchbox_create_generic, id_search_cb,
- &template, id_search_call_cb, idptr.data);
- }
- /* list view */
- else {
- const int searchbox_width = UI_searchbox_size_x();
- const int searchbox_height = UI_searchbox_size_y();
-
- /* fake button, it holds space for search items */
- uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 15, searchbox_width, searchbox_height, NULL, 0, 0, 0, 0, NULL);
- but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, searchbox_width, UI_UNIT_Y - 1, 0, 0, "");
- UI_but_func_search_set(
- but, ui_searchbox_create_generic, id_search_cb,
- &template, id_search_call_cb, idptr.data);
- }
-
-
- UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
- UI_block_direction_set(block, UI_DIR_DOWN);
-
- /* give search-field focus */
- UI_but_focus_on_enter_event(win, but);
- /* this type of search menu requires undo */
- but->flag |= UI_BUT_UNDO;
-
- return block;
+ return template_common_search_menu(
+ C, ar, id_search_cb, &template, id_search_call_cb, active_item_ptr.data,
+ template.prv_rows, template.prv_cols);
}
/************************ ID Template ***************************/
@@ -345,7 +416,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
}
}
-static const char *template_id_browse_tip(StructRNA *type)
+static const char *template_id_browse_tip(const StructRNA *type)
{
if (type) {
switch (RNA_type_to_ID_code(type)) {
@@ -406,6 +477,7 @@ static void template_ID(
// ListBase *lb; // UNUSED
ID *id, *idfrom;
const bool editable = RNA_property_editable(&template->ptr, template->prop);
+ const bool use_previews = template->preview = (flag & UI_ID_PREVIEWS) != 0;
idptr = RNA_property_pointer_get(&template->ptr, template->prop);
id = idptr.data;
@@ -418,43 +490,11 @@ static void template_ID(
if (idptr.type)
type = idptr.type;
- if (flag & UI_ID_PREVIEWS) {
- ARegion *region = CTX_wm_region(C);
- const bool use_big_size = (region->regiontype != RGN_TYPE_HEADER); /* silly check, could be more generic */
- /* Ugly exception for screens here, drawing their preview in icon size looks ugly/useless */
- const bool use_preview_icon = use_big_size || (id && (GS(id->name) != ID_SCR));
- const short width = UI_UNIT_X * (use_big_size ? 6 : 1.6f);
- const short height = UI_UNIT_Y * (use_big_size ? 6: 1);
-
- template->preview = true;
-
- but = uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, width, height,
- TIP_(template_id_browse_tip(type)));
- if (use_preview_icon) {
- int icon = id ? ui_id_icon_get(C, id, use_big_size) : RNA_struct_ui_icon(type);
- ui_def_but_icon(but, icon, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
- }
- else {
- ui_def_but_icon(but, RNA_struct_ui_icon(type), UI_HAS_ICON);
- UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
- }
-
- if ((idfrom && idfrom->lib) || !editable)
- UI_but_flag_enable(but, UI_BUT_DISABLED);
- if (use_big_size) {
- uiLayoutRow(layout, true);
- }
- }
- else if (flag & UI_ID_BROWSE) {
- but = uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X * 1.6, UI_UNIT_Y,
- TIP_(template_id_browse_tip(type)));
- ui_def_but_icon(but, RNA_struct_ui_icon(type), UI_HAS_ICON);
- /* default dragging of icon for id browse buttons */
- UI_but_drag_set_id(but, id);
- UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
-
- if ((idfrom && idfrom->lib) || !editable)
- UI_but_flag_enable(but, UI_BUT_DISABLED);
+ if (flag & UI_ID_BROWSE) {
+ template_add_button_search_menu(
+ C, layout, block, &template->ptr, template->prop,
+ id_search_menu, MEM_dupallocN(template), TIP_(template_id_browse_tip(type)),
+ use_previews, editable);
}
/* text button with name */
@@ -464,8 +504,9 @@ static void template_ID(
//text_idbutton(id, name);
name[0] = '\0';
- but = uiDefButR(block, UI_BTYPE_TEXT, 0, name, 0, 0, UI_UNIT_X * 6, UI_UNIT_Y,
- &idptr, "name", -1, 0, 0, -1, -1, RNA_struct_ui_description(type));
+ but = uiDefButR(
+ block, UI_BTYPE_TEXT, 0, name, 0, 0, TEMPLATE_SEARCH_TEXTBUT_WIDTH, TEMPLATE_SEARCH_TEXTBUT_HEIGHT,
+ &idptr, "name", -1, 0, 0, -1, -1, RNA_struct_ui_description(type));
UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_RENAME));
if (user_alert) UI_but_flag_enable(but, UI_BUT_REDALERT);
@@ -751,6 +792,204 @@ void uiTemplateAnyID(
uiItemFullR(sub, ptr, propID, 0, 0, 0, "", ICON_NONE);
}
+/********************* Search Template ********************/
+
+typedef struct TemplateSearch {
+ uiRNACollectionSearch search_data;
+
+ bool use_previews;
+ int preview_rows, preview_cols;
+} TemplateSearch;
+
+static void template_search_handle_cb(bContext *C, void *arg_template, void *item)
+{
+ TemplateSearch *template_search = arg_template;
+ uiRNACollectionSearch *coll_search = &template_search->search_data;
+ StructRNA *type = RNA_property_pointer_type(&coll_search->target_ptr, coll_search->target_prop);
+ PointerRNA item_ptr;
+
+ RNA_pointer_create(NULL, type, item, &item_ptr);
+ RNA_property_pointer_set(&coll_search->target_ptr, coll_search->target_prop, item_ptr);
+ RNA_property_update(C, &coll_search->target_ptr, coll_search->target_prop);
+}
+
+static uiBlock *template_search_menu(bContext *C, ARegion *region, void *arg_template)
+{
+ static TemplateSearch template_search;
+ PointerRNA active_ptr;
+
+ /* arg_template is malloced, can be freed by parent button */
+ template_search = *((TemplateSearch *)arg_template);
+ active_ptr = RNA_property_pointer_get(&template_search.search_data.target_ptr,
+ template_search.search_data.target_prop);
+
+ return template_common_search_menu(
+ C, region, ui_rna_collection_search_cb, &template_search,
+ template_search_handle_cb, active_ptr.data,
+ template_search.preview_rows, template_search.preview_cols);
+}
+
+static void template_search_add_button_searchmenu(
+ const bContext *C, uiLayout *layout, uiBlock *block,
+ TemplateSearch *template_search, const bool editable)
+{
+ const char *ui_description = RNA_property_ui_description(template_search->search_data.target_prop);
+
+ template_add_button_search_menu(
+ C, layout, block,
+ &template_search->search_data.target_ptr, template_search->search_data.target_prop,
+ template_search_menu, MEM_dupallocN(template_search), ui_description,
+ template_search->use_previews, editable);
+}
+
+static void template_search_add_button_name(
+ uiBlock *block, PointerRNA *active_ptr, const StructRNA *type)
+{
+ uiDefAutoButR(
+ block, active_ptr, RNA_struct_name_property(type), 0, "", ICON_NONE,
+ 0, 0, TEMPLATE_SEARCH_TEXTBUT_WIDTH, TEMPLATE_SEARCH_TEXTBUT_HEIGHT);
+}
+
+static void template_search_add_button_operator(
+ uiBlock *block, const char * const operator_name,
+ const int opcontext, const int icon, const bool editable)
+{
+ if (!operator_name) {
+ return;
+ }
+
+ uiBut *but = uiDefIconButO(
+ block, UI_BTYPE_BUT, operator_name, opcontext, icon,
+ 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
+
+ if (!editable) {
+ UI_but_drawflag_enable(but, UI_BUT_DISABLED);
+ }
+}
+
+static void template_search_buttons(
+ const bContext *C, uiLayout *layout, TemplateSearch *template_search,
+ const char *newop, const char *unlinkop)
+{
+ uiBlock *block = uiLayoutGetBlock(layout);
+ uiRNACollectionSearch *search_data = &template_search->search_data;
+ StructRNA *type = RNA_property_pointer_type(&search_data->target_ptr, search_data->target_prop);
+ const bool editable = RNA_property_editable(&search_data->target_ptr, search_data->target_prop);
+ PointerRNA active_ptr = RNA_property_pointer_get(&search_data->target_ptr, search_data->target_prop);
+
+ if (active_ptr.type) {
+ /* can only get correct type when there is an active item */
+ type = active_ptr.type;
+ }
+
+ uiLayoutRow(layout, true);
+ UI_block_align_begin(block);
+
+ template_search_add_button_searchmenu(C, layout, block, template_search, editable);
+ template_search_add_button_name(block, &active_ptr, type);
+ template_search_add_button_operator(block, newop, WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN, editable);
+ template_search_add_button_operator(block, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, editable);
+
+ UI_block_align_end(block);
+}
+
+static PropertyRNA *template_search_get_searchprop(
+ PointerRNA *targetptr, PropertyRNA *targetprop,
+ PointerRNA *searchptr, const char * const searchpropname)
+{
+ PropertyRNA *searchprop;
+
+ if (searchptr && !searchptr->data) {
+ searchptr = NULL;
+ }
+
+ if (!searchptr && !searchpropname) {
+ /* both NULL means we don't use a custom rna collection to search in */
+ }
+ else if (!searchptr && searchpropname) {
+ RNA_warning("searchpropname defined (%s) but searchptr is missing", searchpropname);
+ }
+ else if (searchptr && !searchpropname) {
+ RNA_warning("searchptr defined (%s) but searchpropname is missing", RNA_struct_identifier(searchptr->type));
+ }
+ else if (!(searchprop = RNA_struct_find_property(searchptr, searchpropname))) {
+ RNA_warning("search collection property not found: %s.%s",
+ RNA_struct_identifier(searchptr->type), searchpropname);
+ }
+ else if (RNA_property_type(searchprop) != PROP_COLLECTION) {
+ RNA_warning("search collection property is not a collection type: %s.%s",
+ RNA_struct_identifier(searchptr->type), searchpropname);
+ }
+ /* check if searchprop has same type as targetprop */
+ else if (RNA_property_pointer_type(searchptr, searchprop) != RNA_property_pointer_type(targetptr, targetprop)) {
+ RNA_warning("search collection items from %s.%s are not of type %s",
+ RNA_struct_identifier(searchptr->type), searchpropname,
+ RNA_struct_identifier(RNA_property_pointer_type(targetptr, targetprop)));
+ }
+ else {
+ return searchprop;
+ }
+
+ return NULL;
+}
+
+static TemplateSearch *template_search_setup(
+ PointerRNA *ptr, const char * const propname,
+ PointerRNA *searchptr, const char * const searchpropname)
+{
+ TemplateSearch *template_search;
+ PropertyRNA *prop, *searchprop;
+
+ prop = RNA_struct_find_property(ptr, propname);
+
+ if (!prop || RNA_property_type(prop) != PROP_POINTER) {
+ RNA_warning("pointer property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
+ return NULL;
+ }
+ searchprop = template_search_get_searchprop(ptr, prop, searchptr, searchpropname);
+
+ template_search = MEM_callocN(sizeof(*template_search), __func__);
+ template_search->search_data.target_ptr = *ptr;
+ template_search->search_data.target_prop = prop;
+ template_search->search_data.search_ptr = *searchptr;
+ template_search->search_data.search_prop = searchprop;
+
+ return template_search;
+}
+
+/**
+ * Search menu to pick an item from a collection.
+ * A version of uiTemplateID that works for non-ID types.
+ */
+void uiTemplateSearch(
+ uiLayout *layout, bContext *C,
+ PointerRNA *ptr, const char *propname,
+ PointerRNA *searchptr, const char *searchpropname,
+ const char *newop, const char *unlinkop)
+{
+ TemplateSearch *template_search = template_search_setup(ptr, propname, searchptr, searchpropname);
+ template_search_buttons(C, layout, template_search, newop, unlinkop);
+ MEM_freeN(template_search);
+}
+
+void uiTemplateSearchPreview(
+ uiLayout *layout, bContext *C,
+ PointerRNA *ptr, const char *propname,
+ PointerRNA *searchptr, const char *searchpropname,
+ const char *newop, const char *unlinkop,
+ const int rows, const int cols)
+{
+ TemplateSearch *template_search = template_search_setup(ptr, propname, searchptr, searchpropname);
+
+ template_search->use_previews = true;
+ template_search->preview_rows = rows;
+ template_search->preview_cols = cols;
+
+ template_search_buttons(C, layout, template_search, newop, unlinkop);
+
+ MEM_freeN(template_search);
+}
+
/********************* RNA Path Builder Template ********************/
/* ---------- */
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index 636b7e4e9ce..f2e79ec0c7f 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -214,6 +214,91 @@ int uiDefAutoButsRNA(
return tot;
}
+/* *** RNA collection search menu *** */
+
+typedef struct CollItemSearch {
+ struct CollItemSearch *next, *prev;
+ ID *id;
+ char *name;
+ int index;
+ int iconid;
+} CollItemSearch;
+
+static int sort_search_items_list(const void *a, const void *b)
+{
+ const CollItemSearch *cis1 = a;
+ const CollItemSearch *cis2 = b;
+
+ if (BLI_strcasecmp(cis1->name, cis2->name) > 0)
+ return 1;
+ else
+ return 0;
+}
+
+void ui_rna_collection_search_cb(const struct bContext *C, void *arg, const char *str, uiSearchItems *items)
+{
+ uiRNACollectionSearch *data = arg;
+ char *name;
+ int i = 0, iconid = 0, flag = RNA_property_flag(data->target_prop);
+ ListBase *items_list = MEM_callocN(sizeof(ListBase), "items_list");
+ CollItemSearch *cis;
+ const bool skip_filter = !(data->but_changed && *data->but_changed);
+
+ /* build a temporary list of relevant items first */
+ RNA_PROP_BEGIN (&data->search_ptr, itemptr, data->search_prop)
+ {
+ ID *id = NULL;
+
+ if (flag & PROP_ID_SELF_CHECK)
+ if (itemptr.data == data->target_ptr.id.data)
+ continue;
+
+ /* use filter */
+ if (RNA_property_type(data->target_prop) == PROP_POINTER) {
+ if (RNA_property_pointer_poll(&data->target_ptr, data->target_prop, &itemptr) == 0)
+ continue;
+ }
+
+ name = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL); /* could use the string length here */
+ iconid = 0;
+ if (itemptr.type && RNA_struct_is_ID(itemptr.type)) {
+ id = itemptr.data;
+ iconid = ui_id_icon_get(C, id, false);
+ }
+
+ if (name) {
+ if (skip_filter || BLI_strcasestr(name, str)) {
+ cis = MEM_callocN(sizeof(CollItemSearch), "CollectionItemSearch");
+ cis->id = id;
+ cis->name = MEM_dupallocN(name);
+ cis->index = i;
+ cis->iconid = iconid;
+ BLI_addtail(items_list, cis);
+ }
+ MEM_freeN(name);
+ }
+
+ i++;
+ }
+ RNA_PROP_END;
+
+ BLI_listbase_sort(items_list, sort_search_items_list);
+
+ /* add search items from temporary list */
+ for (cis = items_list->first; cis; cis = cis->next) {
+ void *poin = cis->id ? cis->id : SET_INT_IN_POINTER(cis->index);
+ if (UI_search_item_add(items, cis->name, poin, cis->iconid) == false) {
+ break;
+ }
+ }
+
+ for (cis = items_list->first; cis; cis = cis->next) {
+ MEM_freeN(cis->name);
+ }
+ BLI_freelistN(items_list);
+ MEM_freeN(items_list);
+}
+
/***************************** ID Utilities *******************************/
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 1a6b3008a79..7f919ef058a 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -751,7 +751,7 @@ const char *RNA_struct_ui_description_raw(const StructRNA *type);
const char *RNA_struct_translation_context(const StructRNA *type);
int RNA_struct_ui_icon(const StructRNA *type);
-PropertyRNA *RNA_struct_name_property(StructRNA *type);
+PropertyRNA *RNA_struct_name_property(const StructRNA *type);
PropertyRNA *RNA_struct_iterator_property(StructRNA *type);
StructRNA *RNA_struct_base(StructRNA *type);
@@ -1191,7 +1191,7 @@ int RNA_function_call_direct_va_lookup(struct bContext *C, struct ReportList *re
/* ID */
-short RNA_type_to_ID_code(StructRNA *type);
+short RNA_type_to_ID_code(const StructRNA *type);
StructRNA *ID_code_to_RNA_type(short idcode);
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index a74758a4f71..4291e5b63ae 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -136,7 +136,7 @@ static int rna_ID_name_editable(PointerRNA *ptr, const char **UNUSED(r_info))
return PROP_EDITABLE;
}
-short RNA_type_to_ID_code(StructRNA *type)
+short RNA_type_to_ID_code(const StructRNA *type)
{
if (RNA_struct_is_a(type, &RNA_Action)) return ID_AC;
if (RNA_struct_is_a(type, &RNA_Armature)) return ID_AR;
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index bd91315ed11..facb7116b67 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -560,7 +560,7 @@ const char *RNA_struct_translation_context(const StructRNA *type)
return type->translation_context;
}
-PropertyRNA *RNA_struct_name_property(StructRNA *type)
+PropertyRNA *RNA_struct_name_property(const StructRNA *type)
{
return type->nameproperty;
}
@@ -2765,6 +2765,9 @@ char *RNA_property_string_get_alloc(PointerRNA *ptr, PropertyRNA *prop,
int length;
BLI_assert(RNA_property_type(prop) == PROP_STRING);
+ if (!ptr->data) {
+ return NULL;
+ }
length = RNA_property_string_length(ptr, prop);
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index 6ef4bc6a371..abad70a46d2 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -671,7 +671,31 @@ void RNA_api_ui_layout(StructRNA *srna)
"Identifier of property in data giving the type of the ID-blocks to use");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
api_ui_item_common_text(func);
-
+
+ func = RNA_def_function(srna, "template_search", "uiTemplateSearch");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ api_ui_item_rna_common(func);
+ parm = RNA_def_pointer(func, "search_data", "AnyType", "", "Data from which to take collection to search in");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ parm = RNA_def_string(func, "search_property", NULL, 0, "", "Identifier of search collection property");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_string(func, "new", NULL, 0, "", "Operator identifier to create a new item for the collection");
+ RNA_def_string(func, "unlink", NULL, 0, "", "Operator identifier to unlink or delete the active "
+ "item from the collection");
+
+ func = RNA_def_function(srna, "template_search_preview", "uiTemplateSearchPreview");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ api_ui_item_rna_common(func);
+ parm = RNA_def_pointer(func, "search_data", "AnyType", "", "Data from which to take collection to search in");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ parm = RNA_def_string(func, "search_property", NULL, 0, "", "Identifier of search collection property");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_string(func, "new", NULL, 0, "", "Operator identifier to create a new item for the collection");
+ RNA_def_string(func, "unlink", NULL, 0, "", "Operator identifier to unlink or delete the active "
+ "item from the collection");
+ RNA_def_int(func, "rows", 0, 0, INT_MAX, "Number of thumbnail preview rows to display", "", 0, INT_MAX);
+ RNA_def_int(func, "cols", 0, 0, INT_MAX, "Number of thumbnail preview columns to display", "", 0, INT_MAX);
+
func = RNA_def_function(srna, "template_path_builder", "rna_uiTemplatePathBuilder");
parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index 642140d1b00..8790e73d039 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -623,6 +623,17 @@ struct uiLayout *uiTemplateConstraint(struct uiLayout *layout, struct PointerRNA
void uiTemplatePreview(struct uiLayout *layout, struct bContext *C, struct ID *id, int show_buttons, struct ID *parent,
struct MTex *slot, const char *preview_id) RET_NONE
void uiTemplateIDPreview(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, int rows, int cols) RET_NONE
+void uiTemplateSearch(
+ uiLayout *layout, struct bContext *C,
+ PointerRNA *ptr, const char *propname,
+ PointerRNA *searchptr, const char *searchpropname,
+ const char *newop, const char *unlinkop) RET_NONE
+void uiTemplateSearchPreview(
+ uiLayout *layout, struct bContext *C,
+ PointerRNA *ptr, const char *propname,
+ PointerRNA *searchptr, const char *searchpropname,
+ const char *newop, const char *unlinkop,
+ const int rows, const int cols) RET_NONE
void uiTemplateCurveMapping(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int type, int levels, int brush, int neg_slope) RET_NONE
void uiTemplateColorRamp(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int expand) RET_NONE
void uiTemplateLayers(uiLayout *layout, struct PointerRNA *ptr, const char *propname, PointerRNA *used_ptr, const char *used_propname, int active_layer) RET_NONE