From 61c66a996ca5e590097e8864df027602493f58f4 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 6 Feb 2015 18:10:46 +1100 Subject: Outliner: DragDrop objects to groups Support drag&drop objects to groups in the outliner. D989 by @lichtwerk --- source/blender/editors/object/object_group.c | 53 ++---------------- .../blender/editors/space_outliner/outliner_edit.c | 63 ++++++++++++++++++++++ .../editors/space_outliner/outliner_intern.h | 1 + .../blender/editors/space_outliner/outliner_ops.c | 1 + .../editors/space_outliner/space_outliner.c | 25 +++++++++ 5 files changed, 94 insertions(+), 49 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c index 20e2e22cdf8..3c43f2729bd 100644 --- a/source/blender/editors/object/object_group.c +++ b/source/blender/editors/object/object_group.c @@ -61,47 +61,6 @@ /********************* 3d view operators ***********************/ -static bool group_link_early_exit_check(Group *group, Object *object) -{ - GroupObject *group_object; - - for (group_object = group->gobject.first; group_object; group_object = group_object->next) { - if (group_object->ob == object) { - return true; - } - } - - return false; -} - -static bool check_object_instances_group_recursive(Object *object, Group *group) -{ - if (object->dup_group) { - Group *dup_group = object->dup_group; - if ((dup_group->id.flag & LIB_DOIT) == 0) { - /* Cycle already exists in groups, let's prevent further crappyness */ - return true; - } - /* flag the object to identify cyclic dependencies in further dupli groups */ - dup_group->id.flag &= ~LIB_DOIT; - - if (dup_group == group) - return true; - else { - GroupObject *gob; - for (gob = dup_group->gobject.first; gob; gob = gob->next) { - if (check_object_instances_group_recursive(gob->ob, group)) - return true; - } - } - - /* un-flag the object, it's allowed to have the same group multiple times in parallel */ - dup_group->id.flag |= LIB_DOIT; - } - - return false; -} - /* can be called with C == NULL */ static EnumPropertyItem *group_object_active_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { @@ -185,15 +144,12 @@ static int objects_add_active_exec(bContext *C, wmOperator *op) if (!BKE_group_object_exists(group, ob)) continue; - /* for recursive check */ - BKE_main_id_tag_listbase(&bmain->group, true); - CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { - if (group_link_early_exit_check(group, base->object)) + if (BKE_group_object_exists(group, base->object)) continue; - if (!check_object_instances_group_recursive(base->object, group)) { + if (!BKE_group_object_cyclic_check(bmain, base->object, group)) { BKE_group_object_add(group, base->object, scene, base); updated = true; } @@ -486,7 +442,7 @@ static int group_link_exec(bContext *C, wmOperator *op) * we could sckip all the dependency check and just consider * operator is finished. */ - if (group_link_early_exit_check(group, ob)) { + if (BKE_group_object_exists(group, ob)) { return OPERATOR_FINISHED; } @@ -495,8 +451,7 @@ static int group_link_exec(bContext *C, wmOperator *op) * It is also bad idea to add object to group which is in group which * contains our current object. */ - BKE_main_id_tag_listbase(&bmain->group, true); - if (check_object_instances_group_recursive(ob, group)) { + if (BKE_group_object_cyclic_check(bmain, ob, group)) { BKE_report(op->reports, RPT_ERROR, "Could not add the group because of dependency cycle detected"); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 9514a04e46f..d17ab33d0fa 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -50,6 +50,7 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_material.h" +#include "BKE_group.h" #include "ED_object.h" #include "ED_screen.h" @@ -1833,3 +1834,65 @@ void OUTLINER_OT_material_drop(wmOperatorType *ot) RNA_def_string(ot->srna, "material", "Material", MAX_ID_NAME, "Material", "Target Material"); } +static int group_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Main *bmain = CTX_data_main(C); + Group *group = NULL; + Object *ob = NULL; + Scene *scene = CTX_data_scene(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + ARegion *ar = CTX_wm_region(C); + TreeElement *te = NULL; + char ob_name[MAX_ID_NAME - 2]; + float fmval[2]; + + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + + /* Find object hovered over */ + te = outliner_dropzone_find(soops, fmval, true); + + if (te) { + group = (Group *)BKE_libblock_find_name(ID_GR, te->name); + + RNA_string_get(op->ptr, "object", ob_name); + ob = (Object *)BKE_libblock_find_name(ID_OB, ob_name); + + if (ELEM(NULL, group, ob)) { + return OPERATOR_CANCELLED; + } + if (BKE_group_object_exists(group, ob)) { + return OPERATOR_FINISHED; + } + + if (BKE_group_object_cyclic_check(bmain, ob, group)) { + BKE_report(op->reports, RPT_ERROR, "Could not add the group because of dependency cycle detected"); + return OPERATOR_CANCELLED; + } + + BKE_group_object_add(group, ob, scene, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; +} + +void OUTLINER_OT_group_link(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Link Object to Group"; + ot->description = "Link Object to Group in Outliner"; + ot->idname = "OUTLINER_OT_group_link"; + + /* api callbacks */ + ot->invoke = group_link_invoke; + + ot->poll = ED_operator_outliner_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + + /* properties */ + RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object"); +} diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index c7ac561734a..26283dfdd83 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -237,6 +237,7 @@ void OUTLINER_OT_parent_drop(struct wmOperatorType *ot); void OUTLINER_OT_parent_clear(struct wmOperatorType *ot); void OUTLINER_OT_scene_drop(struct wmOperatorType *ot); void OUTLINER_OT_material_drop(struct wmOperatorType *ot); +void OUTLINER_OT_group_link(struct wmOperatorType *ot); /* outliner_tools.c ---------------------------------------------- */ diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 4f13454ef34..d54ae3f22a7 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -77,6 +77,7 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_parent_clear); WM_operatortype_append(OUTLINER_OT_scene_drop); WM_operatortype_append(OUTLINER_OT_material_drop); + WM_operatortype_append(OUTLINER_OT_group_link); } void outliner_keymap(wmKeyConfig *keyconf) diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 171a11c114e..df5a1c8d8c6 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -230,6 +230,30 @@ static void outliner_material_drop_copy(wmDrag *drag, wmDropBox *drop) RNA_string_set(drop->ptr, "material", id->name + 2); } +static int outliner_group_link_poll(bContext *C, wmDrag *drag, const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + float fmval[2]; + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + + if (drag->type == WM_DRAG_ID) { + ID *id = drag->poin; + if (GS(id->name) == ID_OB) { + /* Ensure item under cursor is valid drop target */ + TreeElement *te = outliner_dropzone_find(soops, fmval, true); + return (te && te->idcode == ID_GR && TREESTORE(te)->type == 0); + } + } + return 0; +} + +static void outliner_group_link_copy(wmDrag *drag, wmDropBox *drop) +{ + ID *id = drag->poin; + RNA_string_set(drop->ptr, "object", id->name + 2); +} + /* region dropbox definition */ static void outliner_dropboxes(void) { @@ -239,6 +263,7 @@ static void outliner_dropboxes(void) WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", outliner_parent_clear_poll, outliner_parent_clear_copy); WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", outliner_scene_drop_poll, outliner_scene_drop_copy); WM_dropbox_add(lb, "OUTLINER_OT_material_drop", outliner_material_drop_poll, outliner_material_drop_copy); + WM_dropbox_add(lb, "OUTLINER_OT_group_link", outliner_group_link_poll, outliner_group_link_copy); } static void outliner_main_area_draw(const bContext *C, ARegion *ar) -- cgit v1.2.3