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
This commit is contained in:
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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__ */
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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 ********************/
|
||||
|
||||
/* ---------- */
|
||||
|
@@ -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 *******************************/
|
||||
|
||||
|
@@ -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);
|
||||
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user