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,138 @@ 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 *UNUSED(ptr), PropertyRNA *UNUSED(prop), + int *do_free) +{ + EnumPropertyItem item_tmp = {0}, *item = NULL; + 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, why? This is what is done in RNA_group_local_itemf */ + if (id->lib == NULL) { + /* if this group is part of any object, add to enum list and break */ + 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; + item_tmp.value = i; + RNA_enum_item_add(&item, &totitem, &item_tmp); + break; + } + } + 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);