UI: Add custom attribute edge groups for bevel modifier #117366
|
@ -82,7 +82,9 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
|
|||
miter_inner,
|
||||
spread,
|
||||
custom_profile,
|
||||
vmesh_method);
|
||||
vmesh_method,
|
||||
"bevel_weight_edge",
|
||||
"bevel_weight_vert");
|
||||
|
||||
BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG);
|
||||
BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "edges.out", BM_EDGE, BM_ELEM_TAG);
|
||||
|
|
|
@ -7719,7 +7719,9 @@ void BM_mesh_bevel(BMesh *bm,
|
|||
const int miter_inner,
|
||||
const float spread,
|
||||
const CurveProfile *custom_profile,
|
||||
const int vmesh_method)
|
||||
const int vmesh_method,
|
||||
const char *edge_weight_name,
|
||||
const char *vertex_weight_name)
|
||||
{
|
||||
BMIter iter, liter;
|
||||
BMVert *v, *v_next;
|
||||
|
@ -7737,9 +7739,9 @@ void BM_mesh_bevel(BMesh *bm,
|
|||
bp.affect_type = affect_type;
|
||||
bp.use_weights = use_weights;
|
||||
bp.bweight_offset_vert = CustomData_get_offset_named(
|
||||
&bm->vdata, CD_PROP_FLOAT, "bevel_weight_vert");
|
||||
&bm->vdata, CD_PROP_FLOAT, vertex_weight_name);
|
||||
bp.bweight_offset_edge = CustomData_get_offset_named(
|
||||
&bm->edata, CD_PROP_FLOAT, "bevel_weight_edge");
|
||||
&bm->edata, CD_PROP_FLOAT, edge_weight_name);
|
||||
bp.loop_slide = loop_slide;
|
||||
bp.limit_offset = limit_offset;
|
||||
bp.offset_adjust = (bp.affect_type != BEVEL_AFFECT_VERTICES) &&
|
||||
|
|
|
@ -44,4 +44,6 @@ void BM_mesh_bevel(BMesh *bm,
|
|||
int miter_inner,
|
||||
float spread,
|
||||
const CurveProfile *custom_profile,
|
||||
int vmesh_method);
|
||||
int vmesh_method,
|
||||
const char *edge_weight_name,
|
||||
const char *vertex_weight_name);
|
||||
|
|
|
@ -2886,6 +2886,15 @@ void uiItemPointerR_prop(uiLayout *layout,
|
|||
const char *name,
|
||||
int icon,
|
||||
bool results_are_suggestions);
|
||||
void uiItemPointerR_att_prop(uiLayout *layout,
|
||||
PointerRNA *ptr,
|
||||
PropertyRNA *prop,
|
||||
PointerRNA *searchptr,
|
||||
PropertyRNA *searchprop,
|
||||
const char *name,
|
||||
int icon,
|
||||
bool results_are_suggestions,
|
||||
int domain_filter);
|
||||
void uiItemPointerR(uiLayout *layout,
|
||||
PointerRNA *ptr,
|
||||
const char *propname,
|
||||
|
@ -2893,6 +2902,14 @@ void uiItemPointerR(uiLayout *layout,
|
|||
const char *searchpropname,
|
||||
const char *name,
|
||||
int icon);
|
||||
void uiItemPointerR_att(uiLayout *layout,
|
||||
PointerRNA *ptr,
|
||||
const char *propname,
|
||||
PointerRNA *searchptr,
|
||||
const char *searchpropname,
|
||||
const char *name,
|
||||
int icon,
|
||||
int domain_filter);
|
||||
|
||||
/**
|
||||
* Create a list of enum items.
|
||||
|
|
|
@ -1309,6 +1309,14 @@ uiBut *ui_but_add_search(uiBut *but,
|
|||
PointerRNA *searchptr,
|
||||
PropertyRNA *searchprop,
|
||||
bool results_are_suggestions);
|
||||
|
||||
uiBut *ui_but_add_search_att(uiBut *but,
|
||||
PointerRNA *ptr,
|
||||
PropertyRNA *prop,
|
||||
PointerRNA *searchptr,
|
||||
PropertyRNA *searchprop,
|
||||
bool results_are_suggestions,
|
||||
int domain_filter);
|
||||
/**
|
||||
* Check all buttons defined in this layout,
|
||||
* and set any button flagged as UI_BUT_LIST_ITEM as active/selected.
|
||||
|
@ -1518,6 +1526,13 @@ struct uiRNACollectionSearch {
|
|||
void ui_rna_collection_search_update_fn(
|
||||
const bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first);
|
||||
|
||||
void ui_rna_collection_search_att_edge_update_fn(
|
||||
const bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first);
|
||||
|
||||
void ui_rna_collection_search_att_point_update_fn(
|
||||
const bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first);
|
||||
|
||||
|
||||
/* `interface_ops.cc` */
|
||||
|
||||
bool ui_jump_to_target_button_poll(bContext *C);
|
||||
|
|
|
@ -2890,6 +2890,102 @@ uiBut *ui_but_add_search(uiBut *but,
|
|||
return but;
|
||||
}
|
||||
|
||||
uiBut *ui_but_add_search_att(uiBut *but,
|
||||
PointerRNA *ptr,
|
||||
PropertyRNA *prop,
|
||||
PointerRNA *searchptr,
|
||||
PropertyRNA *searchprop,
|
||||
const bool results_are_suggestions,
|
||||
int domain_filter)
|
||||
{
|
||||
/* for ID's we do automatic lookup */
|
||||
bool has_search_fn = false;
|
||||
PointerRNA sptr;
|
||||
if (!searchprop) {
|
||||
if (RNA_property_type(prop) == PROP_STRING) {
|
||||
has_search_fn = (RNA_property_string_search_flag(prop) != 0);
|
||||
}
|
||||
if (RNA_property_type(prop) == PROP_POINTER) {
|
||||
StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
|
||||
search_id_collection(ptype, &sptr, &searchprop);
|
||||
searchptr = &sptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* turn button into search button */
|
||||
if (has_search_fn || searchprop) {
|
||||
uiRNACollectionSearch *coll_search = static_cast<uiRNACollectionSearch *>(
|
||||
MEM_mallocN(sizeof(*coll_search), __func__));
|
||||
uiButSearch *search_but;
|
||||
|
||||
but = ui_but_change_type(but, UI_BTYPE_SEARCH_MENU);
|
||||
search_but = (uiButSearch *)but;
|
||||
|
||||
if (searchptr) {
|
||||
search_but->rnasearchpoin = *searchptr;
|
||||
search_but->rnasearchprop = searchprop;
|
||||
}
|
||||
|
||||
but->hardmax = std::max(but->hardmax, 256.0f);
|
||||
but->drawflag |= UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT;
|
||||
if (RNA_property_is_unlink(prop)) {
|
||||
but->flag |= UI_BUT_VALUE_CLEAR;
|
||||
}
|
||||
|
||||
coll_search->target_ptr = *ptr;
|
||||
coll_search->target_prop = prop;
|
||||
|
||||
if (searchptr) {
|
||||
coll_search->search_ptr = *searchptr;
|
||||
coll_search->search_prop = searchprop;
|
||||
}
|
||||
else {
|
||||
/* Rely on `has_search_fn`. */
|
||||
coll_search->search_ptr = PointerRNA_NULL;
|
||||
coll_search->search_prop = nullptr;
|
||||
}
|
||||
|
||||
coll_search->search_but = but;
|
||||
coll_search->butstore_block = but->block;
|
||||
coll_search->butstore = UI_butstore_create(coll_search->butstore_block);
|
||||
UI_butstore_register(coll_search->butstore, &coll_search->search_but);
|
||||
|
||||
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.clear();
|
||||
}
|
||||
|
||||
UI_but_func_search_set_results_are_suggestions(but, results_are_suggestions);
|
||||
|
||||
uiButSearchUpdateFn update_fn = nullptr;
|
||||
if (domain_filter == 0) {
|
||||
update_fn = ui_rna_collection_search_att_point_update_fn;
|
||||
} else if (domain_filter == 1) {
|
||||
update_fn = ui_rna_collection_search_att_edge_update_fn;
|
||||
}
|
||||
UI_but_func_search_set(but,
|
||||
ui_searchbox_create_generic,
|
||||
update_fn,
|
||||
coll_search,
|
||||
false,
|
||||
ui_rna_collection_search_arg_free_fn,
|
||||
nullptr,
|
||||
nullptr);
|
||||
/* If this is called multiple times for the same button, an earlier call may have taken the
|
||||
* else branch below so the button was disabled. Now we have a searchprop, so it can be enabled
|
||||
* again. */
|
||||
but->flag &= ~UI_BUT_DISABLED;
|
||||
}
|
||||
else if (but->type == UI_BTYPE_SEARCH_MENU) {
|
||||
/* In case we fail to find proper searchprop,
|
||||
* so other code might have already set but->type to search menu... */
|
||||
but->flag |= UI_BUT_DISABLED;
|
||||
}
|
||||
|
||||
return but;
|
||||
}
|
||||
|
||||
void uiItemPointerR_prop(uiLayout *layout,
|
||||
PointerRNA *ptr,
|
||||
PropertyRNA *prop,
|
||||
|
@ -2949,6 +3045,66 @@ void uiItemPointerR_prop(uiLayout *layout,
|
|||
but = ui_but_add_search(but, ptr, prop, searchptr, searchprop, results_are_suggestions);
|
||||
}
|
||||
|
||||
void uiItemPointerR_att_prop(uiLayout *layout,
|
||||
PointerRNA *ptr,
|
||||
PropertyRNA *prop,
|
||||
PointerRNA *searchptr,
|
||||
PropertyRNA *searchprop,
|
||||
const char *name,
|
||||
int icon,
|
||||
bool results_are_suggestions,
|
||||
int domain_filter)
|
||||
{
|
||||
const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
|
||||
|
||||
ui_block_new_button_group(uiLayoutGetBlock(layout), uiButtonGroupFlag(0));
|
||||
|
||||
const PropertyType type = RNA_property_type(prop);
|
||||
if (!ELEM(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) {
|
||||
RNA_warning("Property %s.%s must be a pointer, string or enum",
|
||||
RNA_struct_identifier(ptr->type),
|
||||
RNA_property_identifier(prop));
|
||||
return;
|
||||
}
|
||||
if (RNA_property_type(searchprop) != PROP_COLLECTION) {
|
||||
RNA_warning("search collection property is not a collection type: %s.%s",
|
||||
RNA_struct_identifier(searchptr->type),
|
||||
RNA_property_identifier(searchprop));
|
||||
return;
|
||||
}
|
||||
|
||||
/* get icon & name */
|
||||
if (icon == ICON_NONE) {
|
||||
StructRNA *icontype;
|
||||
if (type == PROP_POINTER) {
|
||||
icontype = RNA_property_pointer_type(ptr, prop);
|
||||
}
|
||||
else {
|
||||
icontype = RNA_property_pointer_type(searchptr, searchprop);
|
||||
}
|
||||
|
||||
icon = RNA_struct_ui_icon(icontype);
|
||||
}
|
||||
if (!name) {
|
||||
name = RNA_property_ui_name(prop);
|
||||
}
|
||||
|
||||
char namestr[UI_MAX_NAME_STR];
|
||||
if (use_prop_sep == false) {
|
||||
name = ui_item_name_add_colon(name, namestr);
|
||||
}
|
||||
|
||||
/* create button */
|
||||
uiBlock *block = uiLayoutGetBlock(layout);
|
||||
|
||||
int w, h;
|
||||
ui_item_rna_size(layout, name, icon, ptr, prop, 0, false, false, &w, &h);
|
||||
w += UI_UNIT_X; /* X icon needs more space */
|
||||
uiBut *but = ui_item_with_label(layout, block, name, icon, ptr, prop, 0, 0, 0, w, h, 0);
|
||||
|
||||
but = ui_but_add_search_att(but, ptr, prop, searchptr, searchprop, results_are_suggestions, domain_filter);
|
||||
}
|
||||
|
||||
void uiItemPointerR(uiLayout *layout,
|
||||
PointerRNA *ptr,
|
||||
const char *propname,
|
||||
|
@ -2974,6 +3130,32 @@ void uiItemPointerR(uiLayout *layout,
|
|||
uiItemPointerR_prop(layout, ptr, prop, searchptr, searchprop, name, icon, false);
|
||||
}
|
||||
|
||||
void uiItemPointerR_att(uiLayout *layout,
|
||||
PointerRNA *ptr,
|
||||
const char *propname,
|
||||
PointerRNA *searchptr,
|
||||
const char *searchpropname,
|
||||
const char *name,
|
||||
int icon,
|
||||
int domain_filter)
|
||||
{
|
||||
/* validate arguments */
|
||||
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
|
||||
if (!prop) {
|
||||
RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
|
||||
return;
|
||||
}
|
||||
PropertyRNA *searchprop = RNA_struct_find_property(searchptr, searchpropname);
|
||||
if (!searchprop) {
|
||||
RNA_warning("search collection property not found: %s.%s",
|
||||
RNA_struct_identifier(searchptr->type),
|
||||
searchpropname);
|
||||
return;
|
||||
}
|
||||
|
||||
uiItemPointerR_att_prop(layout, ptr, prop, searchptr, searchprop, name, icon, false, domain_filter);
|
||||
}
|
||||
|
||||
void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
|
||||
{
|
||||
MenuType *mt = (MenuType *)arg_mt;
|
||||
|
|
|
@ -675,6 +675,368 @@ void ui_rna_collection_search_update_fn(
|
|||
MEM_freeN(items_list);
|
||||
}
|
||||
|
||||
|
||||
void ui_rna_collection_search_att_edge_update_fn(
|
||||
const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
|
||||
{
|
||||
uiRNACollectionSearch *data = static_cast<uiRNACollectionSearch *>(arg);
|
||||
const int flag = RNA_property_flag(data->target_prop);
|
||||
ListBase *items_list = MEM_cnew<ListBase>("items_list");
|
||||
const bool is_ptr_target = (RNA_property_type(data->target_prop) == PROP_POINTER);
|
||||
/* For non-pointer properties, UI code acts entirely based on the item's name. So the name has to
|
||||
* match the RNA name exactly. So only for pointer properties, the name can be modified to add
|
||||
* further UI hints. */
|
||||
const bool requires_exact_data_name = !is_ptr_target;
|
||||
const bool skip_filter = is_first;
|
||||
char name_buf[UI_MAX_DRAW_STR];
|
||||
char *name;
|
||||
bool has_id_icon = false;
|
||||
|
||||
blender::ui::string_search::StringSearch<CollItemSearch> search;
|
||||
|
||||
if (data->search_prop != nullptr) {
|
||||
/* build a temporary list of relevant items first */
|
||||
int item_index = 0;
|
||||
RNA_PROP_BEGIN (&data->search_ptr, itemptr, data->search_prop) {
|
||||
|
||||
if (flag & PROP_ID_SELF_CHECK) {
|
||||
if (itemptr.data == data->target_ptr.owner_id) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* use filter */
|
||||
if (is_ptr_target) {
|
||||
if (RNA_property_pointer_poll(&data->target_ptr, data->target_prop, &itemptr) == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
int name_prefix_offset = 0;
|
||||
int iconid = ICON_NONE;
|
||||
bool has_sep_char = false;
|
||||
const bool is_id = itemptr.type && RNA_struct_is_ID(itemptr.type);
|
||||
|
||||
if (is_id) {
|
||||
iconid = ui_id_icon_get(C, static_cast<ID *>(itemptr.data), false);
|
||||
if (!ELEM(iconid, 0, ICON_BLANK1)) {
|
||||
has_id_icon = true;
|
||||
}
|
||||
|
||||
if (requires_exact_data_name) {
|
||||
name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), nullptr);
|
||||
}
|
||||
else {
|
||||
const ID *id = static_cast<ID *>(itemptr.data);
|
||||
BKE_id_full_name_ui_prefix_get(name_buf, id, true, UI_SEP_CHAR, &name_prefix_offset);
|
||||
BLI_STATIC_ASSERT(sizeof(name_buf) >= MAX_ID_FULL_NAME_UI,
|
||||
"Name string buffer should be big enough to hold full UI ID name");
|
||||
name = name_buf;
|
||||
has_sep_char = ID_IS_LINKED(id);
|
||||
}
|
||||
}
|
||||
else {
|
||||
name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), nullptr);
|
||||
}
|
||||
|
||||
if (name) {
|
||||
CollItemSearch *cis = MEM_cnew<CollItemSearch>(__func__);
|
||||
cis->data = itemptr.data;
|
||||
cis->name = BLI_strdup(name);
|
||||
cis->index = item_index;
|
||||
cis->iconid = iconid;
|
||||
cis->is_id = is_id;
|
||||
cis->name_prefix_offset = name_prefix_offset;
|
||||
cis->has_sep_char = has_sep_char;
|
||||
|
||||
PropertyRNA *domain_prop = RNA_struct_find_property(&itemptr, "domain");
|
||||
int domain = RNA_property_int_get(&itemptr, domain_prop);
|
||||
|
||||
int domain_filter = 1;
|
||||
if (domain == domain_filter && name[0] != '.') {
|
||||
if (!skip_filter) {
|
||||
search.add(name, cis);
|
||||
}
|
||||
BLI_addtail(items_list, cis);
|
||||
}
|
||||
|
||||
if (name != name_buf) {
|
||||
MEM_freeN(name);
|
||||
}
|
||||
}
|
||||
|
||||
item_index++;
|
||||
}
|
||||
RNA_PROP_END;
|
||||
}
|
||||
else {
|
||||
BLI_assert(RNA_property_type(data->target_prop) == PROP_STRING);
|
||||
const eStringPropertySearchFlag search_flag = RNA_property_string_search_flag(
|
||||
data->target_prop);
|
||||
BLI_assert(search_flag & PROP_STRING_SEARCH_SUPPORTED);
|
||||
|
||||
struct SearchVisitUserData {
|
||||
blender::string_search::StringSearch<CollItemSearch> *search;
|
||||
bool skip_filter;
|
||||
int item_index;
|
||||
ListBase *items_list;
|
||||
const char *func_id;
|
||||
} user_data = {nullptr};
|
||||
|
||||
user_data.search = &search;
|
||||
user_data.skip_filter = skip_filter;
|
||||
user_data.items_list = items_list;
|
||||
user_data.func_id = __func__;
|
||||
|
||||
RNA_property_string_search(
|
||||
C,
|
||||
&data->target_ptr,
|
||||
data->target_prop,
|
||||
str,
|
||||
[](void *user_data, const StringPropertySearchVisitParams *visit_params) {
|
||||
const bool show_extra_info = (G.debug_value == 102);
|
||||
|
||||
SearchVisitUserData *search_data = (SearchVisitUserData *)user_data;
|
||||
CollItemSearch *cis = MEM_cnew<CollItemSearch>(search_data->func_id);
|
||||
cis->data = nullptr;
|
||||
if (visit_params->info && show_extra_info) {
|
||||
cis->name = BLI_sprintfN(
|
||||
"%s" UI_SEP_CHAR_S "%s", visit_params->text, visit_params->info);
|
||||
}
|
||||
else {
|
||||
cis->name = BLI_strdup(visit_params->text);
|
||||
}
|
||||
|
||||
cis->index = search_data->item_index;
|
||||
cis->iconid = ICON_NONE;
|
||||
cis->is_id = false;
|
||||
cis->name_prefix_offset = 0;
|
||||
cis->has_sep_char = visit_params->info != nullptr;
|
||||
if (!search_data->skip_filter) {
|
||||
search_data->search->add(visit_params->text, cis);
|
||||
}
|
||||
BLI_addtail(search_data->items_list, cis);
|
||||
search_data->item_index++;
|
||||
},
|
||||
(void *)&user_data);
|
||||
|
||||
if (search_flag & PROP_STRING_SEARCH_SORT) {
|
||||
BLI_listbase_sort(items_list, [](const void *a_, const void *b_) -> int {
|
||||
const CollItemSearch *cis_a = (const CollItemSearch *)a_;
|
||||
const CollItemSearch *cis_b = (const CollItemSearch *)b_;
|
||||
return BLI_strcasecmp_natural(cis_a->name, cis_b->name);
|
||||
});
|
||||
int i = 0;
|
||||
LISTBASE_FOREACH (CollItemSearch *, cis, items_list) {
|
||||
cis->index = i;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (skip_filter) {
|
||||
LISTBASE_FOREACH (CollItemSearch *, cis, items_list) {
|
||||
if (!add_collection_search_item(cis, requires_exact_data_name, has_id_icon, items)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const blender::Vector<CollItemSearch *> filtered_items = search.query(str);
|
||||
for (CollItemSearch *cis : filtered_items) {
|
||||
if (!add_collection_search_item(cis, requires_exact_data_name, has_id_icon, items)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (CollItemSearch *, cis, items_list) {
|
||||
MEM_freeN(cis->name);
|
||||
}
|
||||
BLI_freelistN(items_list);
|
||||
MEM_freeN(items_list);
|
||||
}
|
||||
|
||||
void ui_rna_collection_search_att_point_update_fn(
|
||||
const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
|
||||
{
|
||||
uiRNACollectionSearch *data = static_cast<uiRNACollectionSearch *>(arg);
|
||||
const int flag = RNA_property_flag(data->target_prop);
|
||||
ListBase *items_list = MEM_cnew<ListBase>("items_list");
|
||||
const bool is_ptr_target = (RNA_property_type(data->target_prop) == PROP_POINTER);
|
||||
/* For non-pointer properties, UI code acts entirely based on the item's name. So the name has to
|
||||
* match the RNA name exactly. So only for pointer properties, the name can be modified to add
|
||||
* further UI hints. */
|
||||
const bool requires_exact_data_name = !is_ptr_target;
|
||||
const bool skip_filter = is_first;
|
||||
char name_buf[UI_MAX_DRAW_STR];
|
||||
char *name;
|
||||
bool has_id_icon = false;
|
||||
|
||||
blender::ui::string_search::StringSearch<CollItemSearch> search;
|
||||
|
||||
if (data->search_prop != nullptr) {
|
||||
/* build a temporary list of relevant items first */
|
||||
int item_index = 0;
|
||||
RNA_PROP_BEGIN (&data->search_ptr, itemptr, data->search_prop) {
|
||||
|
||||
if (flag & PROP_ID_SELF_CHECK) {
|
||||
if (itemptr.data == data->target_ptr.owner_id) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* use filter */
|
||||
if (is_ptr_target) {
|
||||
if (RNA_property_pointer_poll(&data->target_ptr, data->target_prop, &itemptr) == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
int name_prefix_offset = 0;
|
||||
int iconid = ICON_NONE;
|
||||
bool has_sep_char = false;
|
||||
const bool is_id = itemptr.type && RNA_struct_is_ID(itemptr.type);
|
||||
|
||||
if (is_id) {
|
||||
iconid = ui_id_icon_get(C, static_cast<ID *>(itemptr.data), false);
|
||||
if (!ELEM(iconid, 0, ICON_BLANK1)) {
|
||||
has_id_icon = true;
|
||||
}
|
||||
|
||||
if (requires_exact_data_name) {
|
||||
name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), nullptr);
|
||||
}
|
||||
else {
|
||||
const ID *id = static_cast<ID *>(itemptr.data);
|
||||
BKE_id_full_name_ui_prefix_get(name_buf, id, true, UI_SEP_CHAR, &name_prefix_offset);
|
||||
BLI_STATIC_ASSERT(sizeof(name_buf) >= MAX_ID_FULL_NAME_UI,
|
||||
"Name string buffer should be big enough to hold full UI ID name");
|
||||
name = name_buf;
|
||||
has_sep_char = ID_IS_LINKED(id);
|
||||
}
|
||||
}
|
||||
else {
|
||||
name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), nullptr);
|
||||
}
|
||||
|
||||
if (name) {
|
||||
CollItemSearch *cis = MEM_cnew<CollItemSearch>(__func__);
|
||||
cis->data = itemptr.data;
|
||||
cis->name = BLI_strdup(name);
|
||||
cis->index = item_index;
|
||||
cis->iconid = iconid;
|
||||
cis->is_id = is_id;
|
||||
cis->name_prefix_offset = name_prefix_offset;
|
||||
cis->has_sep_char = has_sep_char;
|
||||
|
||||
PropertyRNA *domain_prop = RNA_struct_find_property(&itemptr, "domain");
|
||||
int domain = RNA_property_int_get(&itemptr, domain_prop);
|
||||
|
||||
int domain_filter = 0;
|
||||
if (domain == domain_filter && name[0] != '.') {
|
||||
if (!skip_filter) {
|
||||
search.add(name, cis);
|
||||
}
|
||||
BLI_addtail(items_list, cis);
|
||||
}
|
||||
|
||||
if (name != name_buf) {
|
||||
MEM_freeN(name);
|
||||
}
|
||||
}
|
||||
|
||||
item_index++;
|
||||
}
|
||||
RNA_PROP_END;
|
||||
}
|
||||
else {
|
||||
BLI_assert(RNA_property_type(data->target_prop) == PROP_STRING);
|
||||
const eStringPropertySearchFlag search_flag = RNA_property_string_search_flag(
|
||||
data->target_prop);
|
||||
BLI_assert(search_flag & PROP_STRING_SEARCH_SUPPORTED);
|
||||
|
||||
struct SearchVisitUserData {
|
||||
blender::string_search::StringSearch<CollItemSearch> *search;
|
||||
bool skip_filter;
|
||||
int item_index;
|
||||
ListBase *items_list;
|
||||
const char *func_id;
|
||||
} user_data = {nullptr};
|
||||
|
||||
user_data.search = &search;
|
||||
user_data.skip_filter = skip_filter;
|
||||
user_data.items_list = items_list;
|
||||
user_data.func_id = __func__;
|
||||
|
||||
RNA_property_string_search(
|
||||
C,
|
||||
&data->target_ptr,
|
||||
data->target_prop,
|
||||
str,
|
||||
[](void *user_data, const StringPropertySearchVisitParams *visit_params) {
|
||||
const bool show_extra_info = (G.debug_value == 102);
|
||||
|
||||
SearchVisitUserData *search_data = (SearchVisitUserData *)user_data;
|
||||
CollItemSearch *cis = MEM_cnew<CollItemSearch>(search_data->func_id);
|
||||
cis->data = nullptr;
|
||||
if (visit_params->info && show_extra_info) {
|
||||
cis->name = BLI_sprintfN(
|
||||
"%s" UI_SEP_CHAR_S "%s", visit_params->text, visit_params->info);
|
||||
}
|
||||
else {
|
||||
cis->name = BLI_strdup(visit_params->text);
|
||||
}
|
||||
|
||||
cis->index = search_data->item_index;
|
||||
cis->iconid = ICON_NONE;
|
||||
cis->is_id = false;
|
||||
cis->name_prefix_offset = 0;
|
||||
cis->has_sep_char = visit_params->info != nullptr;
|
||||
if (!search_data->skip_filter) {
|
||||
search_data->search->add(visit_params->text, cis);
|
||||
}
|
||||
BLI_addtail(search_data->items_list, cis);
|
||||
search_data->item_index++;
|
||||
},
|
||||
(void *)&user_data);
|
||||
|
||||
if (search_flag & PROP_STRING_SEARCH_SORT) {
|
||||
BLI_listbase_sort(items_list, [](const void *a_, const void *b_) -> int {
|
||||
const CollItemSearch *cis_a = (const CollItemSearch *)a_;
|
||||
const CollItemSearch *cis_b = (const CollItemSearch *)b_;
|
||||
return BLI_strcasecmp_natural(cis_a->name, cis_b->name);
|
||||
});
|
||||
int i = 0;
|
||||
LISTBASE_FOREACH (CollItemSearch *, cis, items_list) {
|
||||
cis->index = i;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (skip_filter) {
|
||||
LISTBASE_FOREACH (CollItemSearch *, cis, items_list) {
|
||||
if (!add_collection_search_item(cis, requires_exact_data_name, has_id_icon, items)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const blender::Vector<CollItemSearch *> filtered_items = search.query(str);
|
||||
for (CollItemSearch *cis : filtered_items) {
|
||||
if (!add_collection_search_item(cis, requires_exact_data_name, has_id_icon, items)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (CollItemSearch *, cis, items_list) {
|
||||
MEM_freeN(cis->name);
|
||||
}
|
||||
BLI_freelistN(items_list);
|
||||
MEM_freeN(items_list);
|
||||
}
|
||||
|
||||
|
||||
int UI_icon_from_id(const ID *id)
|
||||
{
|
||||
if (id == nullptr) {
|
||||
|
|
|
@ -53,6 +53,8 @@
|
|||
.miter_outer = MOD_BEVEL_MITER_SHARP, \
|
||||
.affect_type = MOD_BEVEL_AFFECT_EDGES, \
|
||||
.profile = 0.5f, \
|
||||
.edge_weight_name = "bevel_weight_edge", \
|
||||
.vertex_weight_name = "bevel_weight_vert", \
|
||||
.bevel_angle = DEG2RADF(30.0f), \
|
||||
.spread = 0.1f, \
|
||||
.defgrp_name = "", \
|
||||
|
|
|
@ -481,6 +481,12 @@ typedef struct BevelModifierData {
|
|||
struct CurveProfile *custom_profile;
|
||||
|
||||
void *_pad2;
|
||||
/** Custom bevel edge weight name. */
|
||||
char edge_weight_name[64];
|
||||
|
||||
/** Custom bevel vertex weight name. */
|
||||
char vertex_weight_name[64];
|
||||
|
||||
} BevelModifierData;
|
||||
|
||||
/** #BevelModifierData.flags and BevelModifierData.lim_flags */
|
||||
|
|
|
@ -952,6 +952,20 @@ static bool rna_HookModifier_object_override_apply(Main *bmain,
|
|||
return true;
|
||||
}
|
||||
|
||||
static void rna_BevelModifier_edge_weight_name_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
BevelModifierData *bmd = static_cast<BevelModifierData *>(ptr->data);
|
||||
Mike93 marked this conversation as resolved
Outdated
|
||||
|
||||
STRNCPY(bmd->edge_weight_name, value);
|
||||
}
|
||||
|
||||
static void rna_BevelModifier_vertex_weight_name_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
BevelModifierData *bmd = static_cast<BevelModifierData *>(ptr->data);
|
||||
|
||||
STRNCPY(bmd->vertex_weight_name, value);
|
||||
}
|
||||
|
||||
static void rna_HookModifier_subtarget_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
Object *owner = (Object *)ptr->owner_id;
|
||||
|
@ -4312,6 +4326,20 @@ static void rna_def_modifier_bevel(BlenderRNA *brna)
|
|||
RNA_def_property_ui_text(prop, "Limit Method", "");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "edge_weight", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, nullptr, "edge_weight_name");
|
||||
RNA_def_property_ui_text(prop, "Edge Attribute", "Edge weight attribute");
|
||||
RNA_def_property_string_funcs(
|
||||
prop, nullptr, nullptr, "rna_BevelModifier_edge_weight_name_set");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "vertex_weight", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, nullptr, "vertex_weight_name");
|
||||
RNA_def_property_ui_text(prop, "Vertex Attribute", "Vertex weight attribute");
|
||||
RNA_def_property_string_funcs(
|
||||
prop, nullptr, nullptr, "rna_BevelModifier_vertex_weight_name_set");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "angle_limit", PROP_FLOAT, PROP_ANGLE);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "bevel_angle");
|
||||
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
|
@ -90,6 +91,14 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
|
|||
int vgroup = -1;
|
||||
const MDeformVert *dvert = nullptr;
|
||||
BevelModifierData *bmd = (BevelModifierData *)md;
|
||||
|
||||
if (bmd->vertex_weight_name == "") {
|
||||
STRNCPY(bmd->vertex_weight_name, "bevel_weight_vert");
|
||||
}
|
||||
if (bmd->edge_weight_name == "") {
|
||||
STRNCPY(bmd->edge_weight_name, "bevel_weight_edge");
|
||||
}
|
||||
|
||||
const float threshold = cosf(bmd->bevel_angle + 0.000000175f);
|
||||
const bool do_clamp = !(bmd->flags & MOD_BEVEL_OVERLAP_OK);
|
||||
const int offset_type = bmd->val_flags;
|
||||
|
@ -124,9 +133,9 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
|
|||
}
|
||||
|
||||
const int bweight_offset_vert = CustomData_get_offset_named(
|
||||
&bm->vdata, CD_PROP_FLOAT, "bevel_weight_vert");
|
||||
&bm->vdata, CD_PROP_FLOAT, bmd->vertex_weight_name);
|
||||
const int bweight_offset_edge = CustomData_get_offset_named(
|
||||
&bm->edata, CD_PROP_FLOAT, "bevel_weight_edge");
|
||||
&bm->edata, CD_PROP_FLOAT, bmd->edge_weight_name);
|
||||
|
||||
if (bmd->affect_type == MOD_BEVEL_AFFECT_VERTICES) {
|
||||
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
|
||||
|
@ -214,7 +223,9 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
|
|||
miter_inner,
|
||||
spread,
|
||||
bmd->custom_profile,
|
||||
bmd->vmesh_method);
|
||||
bmd->vmesh_method,
|
||||
bmd->edge_weight_name,
|
||||
bmd->vertex_weight_name);
|
||||
|
||||
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh);
|
||||
|
||||
|
@ -281,6 +292,20 @@ static void panel_draw(const bContext * /*C*/, Panel *panel)
|
|||
uiLayoutSetActive(sub, edge_bevel);
|
||||
uiItemR(col, ptr, "angle_limit", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
}
|
||||
else if (limit_method == MOD_BEVEL_WEIGHT) {
|
||||
sub = uiLayoutColumn(col, false);
|
||||
uiLayoutSetActive(sub, edge_bevel);
|
||||
|
||||
const char *weight_type = "edge_weight";
|
||||
int domain_filter = 1;
|
||||
if (!edge_bevel) {
|
||||
weight_type = "vertex_weight";
|
||||
domain_filter = 0;
|
||||
}
|
||||
|
||||
PointerRNA object_data_ptr = RNA_pointer_get(&ob_ptr, "data");
|
||||
uiItemPointerR_att(col, ptr, weight_type, &object_data_ptr, "attributes", nullptr, ICON_NONE, domain_filter);
|
||||
}
|
||||
else if (limit_method == MOD_BEVEL_VGROUP) {
|
||||
modifier_vgroup_ui(col, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", nullptr);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Remove this line; you never used this result.