Index: source/blender/editors/object/object_group.c =================================================================== --- source/blender/editors/object/object_group.c (revision 48142) +++ source/blender/editors/object/object_group.c (working copy) @@ -160,133 +160,171 @@ void GROUP_OT_objects_remove_active(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static int group_objects_remove_all_exec(bContext *C, wmOperator *UNUSED(op)) +static int group_add_selected_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Group *group = NULL; - + 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) { - group = NULL; - while ((group = find_group(base->object, group))) - rem_from_group(group, base->object, scene, base); + 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_objects_remove_all(wmOperatorType *ot) +void GROUP_OT_group_add_selected(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ - ot->name = "Remove From All Groups"; - ot->description = "Remove selected objects from all groups or a selected group"; - ot->idname = "GROUP_OT_objects_remove_all"; + 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_objects_remove_all_exec; - ot->poll = ED_operator_objectmode; - + 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; } -static int group_objects_remove_exec(bContext *C, wmOperator *op) +/* 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) { - Object *ob = ED_object_context(C); - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - int group_object_index = RNA_enum_get(op->ptr, "group"); - - /* first get the group back from the enum index, quite awkward and UI spesific */ - if (ob) { - Group *group = NULL; - int i = 0; - - while ((group = find_group(ob, group))) { - if (i == group_object_index) { - break; - } - i++; - } - - /* now remove all selected objects from the group */ - if (group) { - + 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) { - rem_from_group(group, base->object, scene, base); + 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++; + } - DAG_scene_sort(bmain, scene); - WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); + RNA_enum_item_end(&item, &totitem); + *do_free = TRUE; + + return item; +} - return OPERATOR_FINISHED; +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; - return OPERATOR_CANCELLED; + 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; } - -/* can be called with C == NULL */ -static EnumPropertyItem *group_objects_remove_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) +void GROUP_OT_group_remove_selected(wmOperatorType *ot) { - Object *ob = ED_object_context(C); - EnumPropertyItem *item = NULL, item_tmp = {0}; - int totitem = 0; + PropertyRNA *prop; - if (C == NULL) { - return DummyRNA_NULL_items; - } + /* 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; - /* check that the action exists */ - if (ob) { - Group *group = NULL; - int i = 0; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - while ((group = find_group(ob, group))) { - item_tmp.identifier = item_tmp.name = group->id.name + 2; - /* item_tmp.icon = ICON_ARMATURE_DATA; */ - item_tmp.value = i; - RNA_enum_item_add(&item, &totitem, &item_tmp); - } + /* 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; +} - i++; - } +static int group_objects_remove_all_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Group *group = NULL; - RNA_enum_item_end(&item, &totitem); - *free = 1; + CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) + { + group = NULL; + while ((group = find_group(base->object, group))) + rem_from_group(group, base->object, scene, base); + } + CTX_DATA_END; - return item; + DAG_scene_sort(bmain, scene); + WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); + + return OPERATOR_FINISHED; } -void GROUP_OT_objects_remove(wmOperatorType *ot) +void GROUP_OT_objects_remove_all(wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ - ot->name = "Remove From Group"; + ot->name = "Remove From All Groups"; ot->description = "Remove selected objects from all groups or a selected group"; - ot->idname = "GROUP_OT_objects_remove"; - + ot->idname = "GROUP_OT_objects_remove_all"; + /* api callbacks */ - ot->exec = group_objects_remove_exec; - ot->invoke = WM_menu_invoke; + ot->exec = group_objects_remove_all_exec; ot->poll = ED_operator_objectmode; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "The group to remove this object from"); - RNA_def_enum_funcs(prop, group_objects_remove_itemf); - ot->prop = prop; } static int group_create_exec(bContext *C, wmOperator *op) Index: source/blender/editors/object/object_intern.h =================================================================== --- source/blender/editors/object/object_intern.h (revision 48142) +++ source/blender/editors/object/object_intern.h (working copy) @@ -140,9 +140,10 @@ void LATTICE_OT_make_regular(struct wmOperatorType *ot); /* object_group.c */ void GROUP_OT_create(struct wmOperatorType *ot); void GROUP_OT_objects_remove_all(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 48142) +++ source/blender/editors/object/object_ops.c (working copy) @@ -106,10 +106,11 @@ void ED_operatortypes_object(void) WM_operatortype_append(GROUP_OT_create); WM_operatortype_append(GROUP_OT_objects_remove_all); - 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); @@ -394,10 +395,9 @@ void ED_keymap_object(wmKeyConfig *keyconf) WM_keymap_verify_item(keymap, "ANIM_OT_keying_set_active_set", IKEY, KM_PRESS, KM_CTRL | KM_SHIFT | KM_ALT, 0); WM_keymap_verify_item(keymap, "GROUP_OT_create", GKEY, KM_PRESS, KM_CTRL, 0); - WM_keymap_verify_item(keymap, "GROUP_OT_objects_remove", GKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); WM_keymap_verify_item(keymap, "GROUP_OT_objects_remove_all", GKEY, KM_PRESS, KM_SHIFT | KM_CTRL | KM_ALT, 0); - WM_keymap_verify_item(keymap, "GROUP_OT_objects_add_active", GKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); - WM_keymap_verify_item(keymap, "GROUP_OT_objects_remove_active", GKEY, KM_PRESS, KM_SHIFT | KM_ALT, 0); + WM_keymap_verify_item(keymap, "GROUP_OT_group_add_selected", GKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); + WM_keymap_verify_item(keymap, "GROUP_OT_group_remove_selected", GKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); WM_keymap_add_menu(keymap, "VIEW3D_MT_object_specials", WKEY, KM_PRESS, 0, 0);