Outliner: DragDrop objects to groups

Support drag&drop objects to groups in the outliner.

D989 by @lichtwerk
This commit is contained in:
Campbell Barton 2015-02-06 18:10:46 +11:00
parent b752597805
commit 61c66a996c
7 changed files with 132 additions and 49 deletions

View File

@ -50,6 +50,7 @@ bool BKE_group_object_add(struct Group *group, struct Object *ob, struc
bool BKE_group_object_unlink(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
struct Group *BKE_group_object_find(struct Group *group, struct Object *ob);
bool BKE_group_object_exists(struct Group *group, struct Object *ob);
bool BKE_group_object_cyclic_check(struct Main *bmain, struct Object *object, struct Group *group);
bool BKE_group_is_animated(struct Group *group, struct Object *parent);
void BKE_group_tag_recalc(struct Group *group);

View File

@ -219,6 +219,43 @@ static int group_object_unlink_internal(Group *group, Object *ob)
return removed;
}
static bool group_object_cyclic_check_internal(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 (group_object_cyclic_check_internal(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;
}
bool BKE_group_object_cyclic_check(Main *bmain, Object *object, Group *group)
{
/* first flag all groups */
BKE_main_id_tag_listbase(&bmain->group, true);
return group_object_cyclic_check_internal(object, group);
}
bool BKE_group_object_unlink(Group *group, Object *object, Scene *scene, Base *base)
{
if (group_object_unlink_internal(group, object)) {

View File

@ -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;
}

View File

@ -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");
}

View File

@ -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 ---------------------------------------------- */

View File

@ -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)

View File

@ -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)