Index: source/blender/editors/object/object_group.c =================================================================== --- source/blender/editors/object/object_group.c (revision 48070) +++ source/blender/editors/object/object_group.c (working copy) @@ -160,6 +160,144 @@ void GROUP_OT_objects_remove_active(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +static int group_add_selected_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Group *group = BLI_findlink(&CTX_data_main(C)->group, RNA_enum_get(op->ptr, "group")); + int ok = 0, cycle = 0; + + /* Assign group to selected objects */ + CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) + { + if (base->object->dup_group != group) + add_to_group(group, base->object, scene, base); + else + cycle = 1; + ok = 1; + } + CTX_DATA_END; + + if (!ok) BKE_report(op->reports, RPT_ERROR, "No objects selected"); + if (cycle) + BKE_report(op->reports, RPT_WARNING, "Skipped some groups because of cycle detected"); + + DAG_scene_sort(bmain, scene); + WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GROUP_OT_group_add_selected(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Add Selected to Group"; + ot->idname = "GROUP_OT_group_add_selected"; + ot->description = "Add all selected objects to an existing group"; + + /* api callbacks */ + ot->exec = group_add_selected_exec; + ot->invoke = WM_enum_search_invoke; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", ""); + RNA_def_enum_funcs(prop, RNA_group_local_itemf); + ot->prop = prop; +} + +/* Only add items for groups that the selected objects are in*/ +static EnumPropertyItem *group_remove_selected_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), + int *do_free) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + EnumPropertyItem item_tmp = {0}, *item = NULL; + Group *group; + int totitem = 0; + int i = 0; + ID *id = C ? (ID *)CTX_data_main(C)->group.first : NULL; + + /* loop through groups first */ + for (; id; id = id->next) { + /* only get local groups */ + if (id->lib == NULL) { + /* loop through selected objects */ + CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) + { + if (object_in_group(base->object, (Group *) id)) { + item_tmp.identifier = item_tmp.name = id->name + 2; + + /* only add item if item not already in list */ + if (!RNA_enum_item_find(&item, &totitem, &item_tmp)) { + item_tmp.value = i; + RNA_enum_item_add(&item, &totitem, &item_tmp); + } + } + } + CTX_DATA_END; + } + /* increment i at end for each group because the value is used to find group in the main list */ + i++; + } + + RNA_enum_item_end(&item, &totitem); + *do_free = TRUE; + + return item; +} + +static int group_remove_selected_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Group *group = BLI_findlink(&CTX_data_main(C)->group, RNA_enum_get(op->ptr, "group")); + int ok = 0; + + /* Assign group to selected objects */ + CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) + { + if (object_in_group(base->object, group)) { + rem_from_group(group, base->object, scene, base); + ok = 1; + } + } + CTX_DATA_END; + + if (!ok) BKE_report(op->reports, RPT_ERROR, "No objects selected"); + + DAG_scene_sort(bmain, scene); + WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GROUP_OT_group_remove_selected(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Remove Selected from Group"; + ot->idname = "GROUP_OT_group_remove_selected"; + ot->description = "Remove all selected objects from an existing group"; + + /* api callbacks */ + ot->exec = group_remove_selected_exec; + ot->invoke = WM_enum_search_invoke; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", ""); + RNA_def_enum_funcs(prop, group_remove_selected_itemf); + ot->prop = prop; +} + static int group_objects_remove_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); Index: source/blender/editors/object/object_intern.h =================================================================== --- source/blender/editors/object/object_intern.h (revision 48070) +++ source/blender/editors/object/object_intern.h (working copy) @@ -142,6 +142,8 @@ void GROUP_OT_create(struct wmOperatorType *ot); void GROUP_OT_objects_remove(struct wmOperatorType *ot); void GROUP_OT_objects_add_active(struct wmOperatorType *ot); void GROUP_OT_objects_remove_active(struct wmOperatorType *ot); +void GROUP_OT_group_add_selected(wmOperatorType *ot); +void GROUP_OT_group_remove_selected(wmOperatorType *ot); /* object_modifier.c */ void OBJECT_OT_modifier_add(struct wmOperatorType *ot); Index: source/blender/editors/object/object_ops.c =================================================================== --- source/blender/editors/object/object_ops.c (revision 48070) +++ source/blender/editors/object/object_ops.c (working copy) @@ -108,7 +108,9 @@ void ED_operatortypes_object(void) WM_operatortype_append(GROUP_OT_objects_remove); WM_operatortype_append(GROUP_OT_objects_add_active); WM_operatortype_append(GROUP_OT_objects_remove_active); - + WM_operatortype_append(GROUP_OT_group_add_selected); + WM_operatortype_append(GROUP_OT_group_remove_selected); + WM_operatortype_append(OBJECT_OT_delete); WM_operatortype_append(OBJECT_OT_text_add); WM_operatortype_append(OBJECT_OT_armature_add); Index: source/blender/makesrna/RNA_define.h =================================================================== --- source/blender/makesrna/RNA_define.h (revision 48070) +++ source/blender/makesrna/RNA_define.h (working copy) @@ -195,6 +195,7 @@ void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropert void RNA_enum_item_add_separator(EnumPropertyItem **items, int *totitem); void RNA_enum_items_add(EnumPropertyItem **items, int *totitem, EnumPropertyItem *item); void RNA_enum_items_add_value(EnumPropertyItem **items, int *totitem, EnumPropertyItem *item, int value); +int RNA_enum_item_find(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item); void RNA_enum_item_end(EnumPropertyItem **items, int *totitem); /* Memory management */ Index: source/blender/makesrna/intern/rna_define.c =================================================================== --- source/blender/makesrna/intern/rna_define.c (revision 48070) +++ source/blender/makesrna/intern/rna_define.c (working copy) @@ -2817,6 +2817,19 @@ void RNA_enum_items_add_value(EnumPropertyItem **items, int *totitem, EnumProper } } +int RNA_enum_item_find(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item) +{ + int tot = *totitem; + int i; + + for (i = 0; i < tot; i++) { + if (strcmp((*items)[i].identifier, item->identifier) == 0) + return 1; + } + + return 0; +} + void RNA_enum_item_end(EnumPropertyItem **items, int *totitem) { static EnumPropertyItem empty = {0, NULL, 0, NULL, NULL};