Outliner: support dragging multiple collections, same as objects.
authorBrecht Van Lommel <brechtvanlommel@gmail.com>
Wed, 29 Aug 2018 16:07:14 +0000 (18:07 +0200)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Thu, 30 Aug 2018 11:59:17 +0000 (13:59 +0200)
source/blender/editors/space_outliner/outliner_collections.c
source/blender/editors/space_outliner/outliner_dragdrop.c
source/blender/editors/space_outliner/outliner_intern.h

index 64315120afd0f09099def2be7c25f4d3f127de93..3412894238211f3842211105a07f0a2a0539fd34 100644 (file)
@@ -99,9 +99,26 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te)
        return NULL;
 }
 
+TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *customdata)
+{
+       struct IDsSelectedData *data = customdata;
+       TreeStoreElem *tselem = TREESTORE(te);
+
+       if (outliner_is_collection_tree_element(te)) {
+               BLI_addtail(&data->selected_array, BLI_genericNodeN(te));
+               return TRAVERSE_CONTINUE;
+       }
+
+       if (tselem->type || (tselem->id && GS(tselem->id->name) != ID_GR)) {
+               return TRAVERSE_SKIP_CHILDS;
+       }
+
+       return TRAVERSE_CONTINUE;
+}
+
 TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata)
 {
-       struct ObjectsSelectedData *data = customdata;
+       struct IDsSelectedData *data = customdata;
        TreeStoreElem *tselem = TREESTORE(te);
 
        if (outliner_is_collection_tree_element(te)) {
@@ -112,7 +129,7 @@ TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *custom
                return TRAVERSE_SKIP_CHILDS;
        }
 
-       BLI_addtail(&data->objects_selected_array, BLI_genericNodeN(te));
+       BLI_addtail(&data->selected_array, BLI_genericNodeN(te));
 
        return TRAVERSE_CONTINUE;
 }
@@ -811,12 +828,12 @@ void OUTLINER_OT_collection_indirect_only_clear(wmOperatorType *ot)
 void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects)
 {
        SpaceOops *soops = CTX_wm_space_outliner(C);
-       struct ObjectsSelectedData data = {{NULL}};
+       struct IDsSelectedData data = {{NULL}};
        outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data);
-       LISTBASE_FOREACH (LinkData *, link, &data.objects_selected_array) {
+       LISTBASE_FOREACH (LinkData *, link, &data.selected_array) {
                TreeElement *ten_selected = (TreeElement *)link->data;
                Object *ob = (Object *)TREESTORE(ten_selected)->id;
                BLI_addtail(objects, BLI_genericNodeN(ob));
        }
-       BLI_freelistN(&data.objects_selected_array);
+       BLI_freelistN(&data.selected_array);
 }
index 1c19bb4d3b8c00f5508a3ab29f6ee26405f0d554..60f02dd9529d564f089e14cdb58c8e45f9288d5d 100644 (file)
@@ -883,26 +883,55 @@ static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *UNUSED(op), c
 
        wmDrag *drag = WM_event_start_drag(C, data.icon, WM_DRAG_ID, NULL, 0.0, WM_DRAG_NOP);
 
-       if (GS(data.drag_id->name) == ID_OB) {
-               /* For objects we cheat and drag all selected objects. */
+       if (ELEM(GS(data.drag_id->name), ID_OB, ID_GR)) {
+               /* For collections and objects we cheat and drag all selected. */
                TREESTORE(te)->flag |= TSE_SELECTED;
 
-               struct ObjectsSelectedData selected = {
-                       .objects_selected_array  = {NULL, NULL},
+               /* Gather all selected elements. */
+               struct IDsSelectedData selected = {
+                       .selected_array  = {NULL, NULL},
                };
 
-               outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &selected);
-               LISTBASE_FOREACH (LinkData *, link, &selected.objects_selected_array) {
-                       TreeElement *ten_selected = (TreeElement *)link->data;
-                       Object *ob = (Object *)TREESTORE(ten_selected)->id;
+               if (GS(data.drag_id->name) == ID_OB) {
+                       outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &selected);
+               }
+               else {
+                       outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_collections, &selected);
+               }
+
+               LISTBASE_FOREACH (LinkData *, link, &selected.selected_array) {
+                       TreeElement *te_selected = (TreeElement *)link->data;
+                       ID *id;
+
+                       if (GS(data.drag_id->name) == ID_OB) {
+                               id = TREESTORE(te_selected)->id;
+                       }
+                       else {
+                               /* Keep collection hierarchies intact when dragging. */
+                               bool parent_selected = false;
+                               for (TreeElement *te_parent = te_selected->parent; te_parent; te_parent = te_parent->parent) {
+                                       if (outliner_is_collection_tree_element(te_parent)) {
+                                               if (TREESTORE(te_parent)->flag & TSE_SELECTED) {
+                                                       parent_selected = true;
+                                                       break;
+                                               }
+                                       }
+                               }
+
+                               if (parent_selected) {
+                                       continue;
+                               }
+
+                               id = &outliner_collection_from_tree_element(te_selected)->id;
+                       }
 
-                       /* Find parent collection of object. */
+                       /* Find parent collection. */
                        Collection *parent = NULL;
 
-                       if (ten_selected->parent) {
-                               for (TreeElement *te_ob_parent = ten_selected->parent; te_ob_parent; te_ob_parent = te_ob_parent->parent) {
-                                       if (outliner_is_collection_tree_element(te_ob_parent)) {
-                                               parent = outliner_collection_from_tree_element(te_ob_parent);
+                       if (te_selected->parent) {
+                               for (TreeElement *te_parent = te_selected->parent; te_parent; te_parent = te_parent->parent) {
+                                       if (outliner_is_collection_tree_element(te_parent)) {
+                                               parent = outliner_collection_from_tree_element(te_parent);
                                                break;
                                        }
                                }
@@ -912,10 +941,10 @@ static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *UNUSED(op), c
                                parent = BKE_collection_master(scene);
                        }
 
-                       WM_drag_add_ID(drag, &ob->id, &parent->id);
+                       WM_drag_add_ID(drag, id, &parent->id);
                }
 
-               BLI_freelistN(&selected.objects_selected_array);
+               BLI_freelistN(&selected.selected_array);
        }
        else {
                /* Add single ID. */
index f8dc41b8d37c498f6c20ed5f2383413e4e2d720d..99411df3fda5781ee7e8845162fc8f5e05da38bd 100644 (file)
@@ -176,10 +176,11 @@ void outliner_build_tree(
         struct Scene *scene, struct ViewLayer *view_layer,
         struct SpaceOops *soops, struct ARegion *ar);
 
-typedef struct ObjectsSelectedData {
-       struct ListBase objects_selected_array;
-} ObjectsSelectedData;
+typedef struct IDsSelectedData {
+       struct ListBase selected_array;
+} IDsSelectedData;
 
+TreeTraversalAction outliner_find_selected_collections(struct TreeElement *te, void *customdata);
 TreeTraversalAction outliner_find_selected_objects(struct TreeElement *te, void *customdata);
 
 /* outliner_draw.c ---------------------------------------------- */