Outliner: use generic WM drag and drop system for collections.
authorBrecht Van Lommel <brechtvanlommel@gmail.com>
Fri, 10 Aug 2018 15:04:05 +0000 (17:04 +0200)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Fri, 10 Aug 2018 15:54:00 +0000 (17:54 +0200)
* Drag and drop between multiple outliners now works.
* Dragging the icon and text now give the same results.
* Fixes various crashes.

source/blender/editors/space_outliner/outliner_collections.c
source/blender/editors/space_outliner/outliner_dragdrop.c
source/blender/editors/space_outliner/outliner_draw.c
source/blender/editors/space_outliner/outliner_edit.c
source/blender/editors/space_outliner/outliner_intern.h
source/blender/editors/space_outliner/outliner_ops.c
source/blender/editors/space_outliner/outliner_tree.c
source/blender/makesdna/DNA_outliner_types.h
source/blender/windowmanager/intern/wm_dragdrop.c

index 946d2b019a99a9dbd8647c7d61b43d633de4dfb5..d4c85ce28bd723f450634e998ed4ccf19cac2436 100644 (file)
@@ -99,6 +99,24 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te)
        return NULL;
 }
 
+TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata)
+{
+       struct ObjectsSelectedData *data = customdata;
+       TreeStoreElem *tselem = TREESTORE(te);
+
+       if (outliner_is_collection_tree_element(te)) {
+               return TRAVERSE_CONTINUE;
+       }
+
+       if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
+               return TRAVERSE_SKIP_CHILDS;
+       }
+
+       BLI_addtail(&data->objects_selected_array, BLI_genericNodeN(te));
+
+       return TRAVERSE_CONTINUE;
+}
+
 /* -------------------------------------------------------------------- */
 /* Poll functions. */
 
index f9a4fda0c450595ce502f3cbe2aa71abef90a3be..55b9a5615031df8fabd2ef62901a0559e46bbcf5 100644 (file)
@@ -129,6 +129,101 @@ static ID *outliner_ID_drop_find(bContext *C, const wmEvent *event, short idcode
        }
 }
 
+/* Find tree element to drop into, with additional before and after reorder support. */
+static TreeElement *outliner_drop_insert_find(
+        bContext *C, const wmEvent *event,
+        TreeElementInsertType *r_insert_type)
+{
+       SpaceOops *soops = CTX_wm_space_outliner(C);
+       ARegion *ar = CTX_wm_region(C);
+       TreeElement *te_hovered;
+       float view_mval[2];
+
+       UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
+       te_hovered = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
+
+       if (te_hovered) {
+               /* mouse hovers an element (ignoring x-axis), now find out how to insert the dragged item exactly */
+               const float margin = UI_UNIT_Y * (1.0f / 4);
+
+               if (view_mval[1] < (te_hovered->ys + margin)) {
+                       if (TSELEM_OPEN(TREESTORE(te_hovered), soops)) {
+                               /* inserting after a open item means we insert into it, but as first child */
+                               if (BLI_listbase_is_empty(&te_hovered->subtree)) {
+                                       *r_insert_type = TE_INSERT_INTO;
+                                       return te_hovered;
+                               }
+                               else {
+                                       *r_insert_type = TE_INSERT_BEFORE;
+                                       return te_hovered->subtree.first;
+                               }
+                       }
+                       else {
+                               *r_insert_type = TE_INSERT_AFTER;
+                               return te_hovered;
+                       }
+               }
+               else if (view_mval[1] > (te_hovered->ys + (3 * margin))) {
+                       *r_insert_type = TE_INSERT_BEFORE;
+                       return te_hovered;
+               }
+               else {
+                       *r_insert_type = TE_INSERT_INTO;
+                       return te_hovered;
+               }
+       }
+       else {
+               /* mouse doesn't hover any item (ignoring x-axis), so it's either above list bounds or below. */
+               TreeElement *first = soops->tree.first;
+               TreeElement *last = soops->tree.last;
+
+               if (view_mval[1] < last->ys) {
+                       *r_insert_type = TE_INSERT_AFTER;
+                       return last;
+               }
+               else if (view_mval[1] > (first->ys + UI_UNIT_Y)) {
+                       *r_insert_type = TE_INSERT_BEFORE;
+                       return first;
+               }
+               else {
+                       BLI_assert(0);
+                       return NULL;
+               }
+       }
+}
+
+static TreeElement *outliner_drop_insert_collection_find(
+        bContext *C, const wmEvent *event,
+        TreeElementInsertType *r_insert_type)
+{
+       TreeElement *te = outliner_drop_insert_find(C, event, r_insert_type);
+       if (!te) {
+               return NULL;
+       }
+
+       Collection *collection = outliner_collection_from_tree_element(te);
+       if (!collection) {
+               return NULL;
+       }
+
+       /* We can't insert/before after master collection. */
+       if (collection->flag & COLLECTION_IS_MASTER) {
+               if (*r_insert_type == TE_INSERT_BEFORE) {
+                       /* can't go higher than master collection, insert into it */
+                       *r_insert_type = TE_INSERT_INTO;
+               }
+               else if (*r_insert_type == TE_INSERT_AFTER) {
+                       te = te->subtree.last;
+                       collection = outliner_collection_from_tree_element(te);
+                       if (!collection) {
+                               return NULL;
+                       }
+               }
+       }
+
+       return te;
+}
+
 /* ******************** Parent Drop Operator *********************** */
 
 static bool parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(tooltip))
@@ -542,404 +637,306 @@ void OUTLINER_OT_material_drop(wmOperatorType *ot)
 
 /* ******************** Collection Drop Operator *********************** */
 
-static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(tooltip))
-{
-       Object *ob = (Object *)WM_drag_ID(drag, ID_OB);
-       Collection *collection = (Collection *)WM_drag_ID(drag, ID_GR);
+typedef struct CollectionDrop {
+       Collection *from;
+       Collection *to;
 
-       if (ob || collection) {
-               TreeElement *te = outliner_drop_find(C, event);
-               return (te && outliner_is_collection_tree_element(te));
-       }
-       else {
-               return false;
-       }
-}
+       TreeElement *te;
+       TreeElementInsertType insert_type;
+} CollectionDrop;
 
-static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+static Collection *collection_parent_from_ID(ID *id)
 {
-       Main *bmain = CTX_data_main(C);
-       TreeElement *te = outliner_drop_find(C, event);
-
-       if (!te || !outliner_is_collection_tree_element(te)) {
-               return OPERATOR_CANCELLED;
+       /* Can't change linked parent collections. */
+       if (!id || ID_IS_LINKED(id)) {
+               return NULL;
        }
 
-       Collection *collection = outliner_collection_from_tree_element(te);
-
-       // TODO: don't use scene, makes no sense anymore
-       // TODO: move rather than link, change hover text
-       Scene *scene = BKE_scene_find_from_collection(bmain, collection);
-       Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB);
-       if (ELEM(NULL, ob, scene, collection)) {
-               return OPERATOR_CANCELLED;
+       /* Also support dropping into/from scene collection. */
+       if (GS(id->name) == ID_SCE) {
+               return ((Scene *)id)->master_collection;
+       }
+       else if (GS(id->name) == ID_GR) {
+               return (Collection *)id;
        }
 
-       BKE_collection_object_add(bmain, collection, ob);
-
-       DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE);
-       DEG_relations_tag_update(bmain);
-       WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
-
-       return OPERATOR_FINISHED;
+       return NULL;
 }
 
-void OUTLINER_OT_collection_drop(wmOperatorType *ot)
+static bool collection_drop_init(bContext *C, wmDrag *drag, const wmEvent *event, CollectionDrop *data)
 {
-       /* identifiers */
-       ot->name = "Link to Collection"; // TODO: rename to move?
-       ot->description = "Drag to move to collection in Outliner";
-       ot->idname = "OUTLINER_OT_collection_drop";
-
-       /* api callbacks */
-       ot->invoke = collection_drop_invoke;
-       ot->poll = ED_operator_outliner_active;
-
-       /* flags */
-       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
-}
+       /* Get collection to drop into. */
+       TreeElementInsertType insert_type;
+       TreeElement *te = outliner_drop_insert_collection_find(C, event, &insert_type);
+       if (!te) {
+               return false;
+       }
 
-/* ********************* Outliner Drag Operator ******************** */
+       Collection *to_collection = outliner_collection_from_tree_element(te);
+       if (ID_IS_LINKED(to_collection)) {
+               return false;
+       }
 
-typedef struct OutlinerDragDropTooltip {
-       TreeElement *te;
-       void *handle;
-} OutlinerDragDropTooltip;
+       /* Get drag datablocks. */
+       if (drag->type != WM_DRAG_ID) {
+               return false;
+       }
 
-static bool outliner_item_drag_drop_poll(bContext *C)
-{
-       SpaceOops *soops = CTX_wm_space_outliner(C);
-       return ED_operator_outliner_active(C) &&
-              /* Only collection display modes supported for now. Others need more design work */
-              ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_LIBRARIES);
-}
+       wmDragID *drag_id = drag->ids.first;
+       if (drag_id == NULL) {
+               return false;
+       }
 
-static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *ar, const wmEvent *event)
-{
-       /* note: using EVT_TWEAK_ events to trigger dragging is fine,
-        * it sends coordinates from where dragging was started */
-       const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]);
-       return outliner_find_item_at_y(soops, &soops->tree, my);
-}
+       ID *id = drag_id->id;
+       if (!(id && ELEM(GS(id->name), ID_GR, ID_OB))) {
+               return false;
+       }
 
-static void outliner_item_drag_end(wmWindow *win, OutlinerDragDropTooltip *data)
-{
-       MEM_SAFE_FREE(data->te->drag_data);
+       /* Get collection to drag out of. */
+       ID *parent = drag_id->from_parent;
+       Collection *from_collection = collection_parent_from_ID(parent);
+       if (event->ctrl) {
+               from_collection = NULL;
+       }
 
-       if (data->handle) {
-               WM_draw_cb_exit(win, data->handle);
+       /* Get collections. */
+       if (GS(id->name) == ID_GR) {
+               if (id == &to_collection->id) {
+                       return false;
+               }
+       }
+       else {
+               insert_type = TE_INSERT_INTO;
        }
 
-       MEM_SAFE_FREE(data);
+       data->from = from_collection;
+       data->to = to_collection;
+       data->te = te;
+       data->insert_type = insert_type;
+
+       return true;
 }
 
-static void outliner_item_drag_get_insert_data(
-        const SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged,
-        TreeElement **r_te_insert_handle, TreeElementInsertType *r_insert_type)
+static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **tooltip)
 {
-       TreeElement *te_hovered;
-       float view_mval[2];
-
-       UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
-       te_hovered = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
-
-       if (te_hovered) {
-               /* mouse hovers an element (ignoring x-axis), now find out how to insert the dragged item exactly */
+       SpaceOops *soops = CTX_wm_space_outliner(C);
+       ARegion *ar = CTX_wm_region(C);
+       bool changed = outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED | TSE_DRAG_ANY, false);
 
-               if (te_hovered == te_dragged) {
-                       *r_te_insert_handle = te_dragged;
+       CollectionDrop data;
+       if (collection_drop_init(C, drag, event, &data)) {
+               if (!data.from || event->ctrl) {
+                       *tooltip = IFACE_("Link inside Collection");
                }
-               else if (te_hovered != te_dragged) {
-                       const float margin = UI_UNIT_Y * (1.0f / 4);
-
-                       *r_te_insert_handle = te_hovered;
-                       if (view_mval[1] < (te_hovered->ys + margin)) {
-                               if (TSELEM_OPEN(TREESTORE(te_hovered), soops)) {
-                                       /* inserting after a open item means we insert into it, but as first child */
-                                       if (BLI_listbase_is_empty(&te_hovered->subtree)) {
-                                               *r_insert_type = TE_INSERT_INTO;
+               else {
+                       TreeElement *te = data.te;
+                       TreeStoreElem *tselem = TREESTORE(te);
+
+                       switch (data.insert_type) {
+                               case TE_INSERT_BEFORE:
+                                       tselem->flag |= TSE_DRAG_BEFORE;
+                                       changed = true;
+                                       if (te->prev && outliner_is_collection_tree_element(te->prev)) {
+                                               *tooltip = TIP_("Move between collections");
                                        }
                                        else {
-                                               *r_insert_type = TE_INSERT_BEFORE;
-                                               *r_te_insert_handle = te_hovered->subtree.first;
+                                               *tooltip = TIP_("Move before collection");
                                        }
-                               }
-                               else {
-                                       *r_insert_type = TE_INSERT_AFTER;
-                               }
-                       }
-                       else if (view_mval[1] > (te_hovered->ys + (3 * margin))) {
-                               *r_insert_type = TE_INSERT_BEFORE;
-                       }
-                       else {
-                               *r_insert_type = TE_INSERT_INTO;
+                                       break;
+                               case TE_INSERT_AFTER:
+                                       tselem->flag |= TSE_DRAG_AFTER;
+                                       changed = true;
+                                       if (te->next && outliner_is_collection_tree_element(te->next)) {
+                                               *tooltip = TIP_("Move between collections");
+                                       }
+                                       else {
+                                               *tooltip = TIP_("Move after collection");
+                                       }
+                                       break;
+                               case TE_INSERT_INTO:
+                                       tselem->flag |= TSE_DRAG_INTO;
+                                       changed = true;
+                                       *tooltip = TIP_("Move inside collection (Ctrl to link)");
+                                       break;
                        }
                }
        }
-       else {
-               /* mouse doesn't hover any item (ignoring x-axis), so it's either above list bounds or below. */
 
-               TreeElement *first = soops->tree.first;
-               TreeElement *last = soops->tree.last;
-
-               if (view_mval[1] < last->ys) {
-                       *r_te_insert_handle = last;
-                       *r_insert_type = TE_INSERT_AFTER;
-               }
-               else if (view_mval[1] > (first->ys + UI_UNIT_Y)) {
-                       *r_te_insert_handle = first;
-                       *r_insert_type = TE_INSERT_BEFORE;
-               }
-               else {
-                       BLI_assert(0);
-               }
+       if (changed) {
+               ED_region_tag_redraw_no_rebuild(ar);
        }
+
+       return true;
 }
 
-static void outliner_item_drag_handle(
-        SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged)
+static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
 {
-       TreeElement *te_insert_handle;
-       TreeElementInsertType insert_type;
-
-       outliner_item_drag_get_insert_data(soops, ar, event, te_dragged, &te_insert_handle, &insert_type);
+       Main *bmain = CTX_data_main(C);
+       Scene *scene = CTX_data_scene(C);
 
-       if (!te_dragged->reinsert_poll &&
-           /* there is no reinsert_poll, so we do some generic checks (same types and reinsert callback is available) */
-           (TREESTORE(te_dragged)->type == TREESTORE(te_insert_handle)->type) &&
-           te_dragged->reinsert)
-       {
-               /* pass */
-       }
-       else if (te_dragged == te_insert_handle) {
-               /* nothing will happen anyway, no need to do poll check */
-       }
-       else if (!te_dragged->reinsert_poll ||
-                !te_dragged->reinsert_poll(te_dragged, &te_insert_handle, &insert_type))
-       {
-               te_insert_handle = NULL;
+       if (event->custom != EVT_DATA_DRAGDROP) {
+               return OPERATOR_CANCELLED;
        }
-       te_dragged->drag_data->insert_type = insert_type;
-       te_dragged->drag_data->insert_handle = te_insert_handle;
-}
 
-/**
- * Returns true if it is a collection and empty.
- */
-static bool is_empty_collection(TreeElement *te)
-{
-       Collection *collection = outliner_collection_from_tree_element(te);
+       ListBase *lb = event->customdata;
+       wmDrag *drag = lb->first;
 
-       if (!collection) {
-               return false;
+       CollectionDrop data;
+       if (!collection_drop_init(C, drag, event, &data)) {
+               return OPERATOR_CANCELLED;
        }
 
-       return BLI_listbase_is_empty(&collection->gobject) &&
-              BLI_listbase_is_empty(&collection->children);
-}
-
-static bool outliner_item_drag_drop_apply(
-        Main *bmain,
-        Scene *scene,
-        SpaceOops *soops,
-        OutlinerDragDropTooltip *data,
-        const wmEvent *event)
-{
-       TreeElement *dragged_te = data->te;
-       TreeElement *insert_handle = dragged_te->drag_data->insert_handle;
-       TreeElementInsertType insert_type = dragged_te->drag_data->insert_type;
+       /* Before/after insert handling. */
+       Collection *relative = NULL;
+       bool relative_after = false;
 
-       if ((insert_handle == dragged_te) || !insert_handle) {
-               /* No need to do anything */
-       }
-       else if (dragged_te->reinsert) {
-               BLI_assert(!dragged_te->reinsert_poll || dragged_te->reinsert_poll(dragged_te, &insert_handle,
-                                                                                  &insert_type));
-               /* call of assert above should not have changed insert_handle and insert_type at this point */
-               BLI_assert(dragged_te->drag_data->insert_handle == insert_handle &&
-                          dragged_te->drag_data->insert_type == insert_type);
+       if (ELEM(data.insert_type, TE_INSERT_BEFORE, TE_INSERT_AFTER)) {
+               SpaceOops *soops = CTX_wm_space_outliner(C);
 
-               /* If the collection was just created and you moved objects/collections inside it,
-                * it is strange to have it closed and we not see the newly dragged elements. */
-               const bool should_open_collection = (insert_type == TE_INSERT_INTO) && is_empty_collection(insert_handle);
+               relative = data.to;
+               relative_after = (data.insert_type == TE_INSERT_AFTER);
 
-               dragged_te->reinsert(bmain, scene, soops, dragged_te, insert_handle, insert_type, event);
+               TreeElement *parent_te = outliner_find_parent_element(&soops->tree, NULL, data.te);
+               data.to = (parent_te) ? outliner_collection_from_tree_element(parent_te) : NULL;
+       }
 
-               if (should_open_collection && !is_empty_collection(insert_handle)) {
-                       TREESTORE(insert_handle)->flag &= ~TSE_CLOSED;
-               }
-               return true;
+       if (!data.to) {
+               return OPERATOR_CANCELLED;
        }
 
-       return false;
-}
+       for (wmDragID *drag_id = drag->ids.first; drag_id; drag_id = drag_id->next) {
+               /* Ctrl enables linking, so we don't need a from collection then. */
+               Collection *from = (event->ctrl) ? NULL : collection_parent_from_ID(drag_id->from_parent);
 
-static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
-       Main *bmain = CTX_data_main(C);
-       Scene *scene = CTX_data_scene(C);
-       ARegion *ar = CTX_wm_region(C);
-       SpaceOops *soops = CTX_wm_space_outliner(C);
-       OutlinerDragDropTooltip *data = op->customdata;
-       TreeElement *te_dragged = data->te;
-       int retval = OPERATOR_RUNNING_MODAL;
-       bool redraw = false;
-       bool skip_rebuild = true;
-
-       switch (event->type) {
-               case EVT_MODAL_MAP:
-                       if (event->val == OUTLINER_ITEM_DRAG_CONFIRM) {
-                               if (outliner_item_drag_drop_apply(bmain, scene, soops, data, event)) {
-                                       skip_rebuild = false;
-                               }
-                               retval = OPERATOR_FINISHED;
-                       }
-                       else if (event->val == OUTLINER_ITEM_DRAG_CANCEL) {
-                               retval = OPERATOR_CANCELLED;
+               if (GS(drag_id->id->name) == ID_OB) {
+                       /* Move/link object into collection. */
+                       Object *object = (Object *)drag_id->id;
+
+                       if (from) {
+                               BKE_collection_object_move(bmain, scene, data.to, from, object);
                        }
                        else {
-                               BLI_assert(0);
+                               BKE_collection_object_add(bmain, data.to, object);
                        }
-                       WM_event_add_mousemove(C); /* update highlight */
-                       outliner_item_drag_end(CTX_wm_window(C), data);
-                       redraw = true;
-                       break;
-               case MOUSEMOVE:
-                       outliner_item_drag_handle(soops, ar, event, te_dragged);
-                       redraw = true;
-                       break;
-       }
-
-       if (redraw) {
-               if (skip_rebuild) {
-                       ED_region_tag_redraw_no_rebuild(ar);
-               }
-               else {
-                       ED_region_tag_redraw(ar);
                }
-       }
-
-       return retval;
-}
-
-static const char *outliner_drag_drop_tooltip_get(
-        const TreeElement *te_float)
-{
-       const char *name = NULL;
+               else if (GS(drag_id->id->name) == ID_GR) {
+                       /* Move/link collection into collection. */
+                       Collection *collection = (Collection *)drag_id->id;
 
-       const TreeElement *te_insert = te_float->drag_data->insert_handle;
-       if (te_float && outliner_is_collection_tree_element(te_float)) {
-               if (te_insert == NULL) {
-                       name = TIP_("Move collection");
-               }
-               else {
-                       switch (te_float->drag_data->insert_type) {
-                               case TE_INSERT_BEFORE:
-                                       if (te_insert->prev && outliner_is_collection_tree_element(te_insert->prev)) {
-                                               name = TIP_("Move between collections");
-                                       }
-                                       else {
-                                               name = TIP_("Move before collection");
-                                       }
-                                       break;
-                               case TE_INSERT_AFTER:
-                                       if (te_insert->next && outliner_is_collection_tree_element(te_insert->next)) {
-                                               name = TIP_("Move between collections");
-                                       }
-                                       else {
-                                               name = TIP_("Move after collection");
-                                       }
-                                       break;
-                               case TE_INSERT_INTO:
-                                       name = TIP_("Move inside collection");
-                                       break;
+                       if (collection != from) {
+                               BKE_collection_move(bmain, data.to, from, relative, relative_after, collection);
                        }
                }
-       }
-       else if ((TREESTORE(te_float)->type == 0) && (te_float->idcode == ID_OB)) {
-               name = TIP_("Move to collection (Ctrl to link)");
+
+               if (from) {
+                       DEG_id_tag_update(&from->id, DEG_TAG_COPY_ON_WRITE);
+               }
        }
 
-       return name;
+       /* Update dependency graph. */
+       DEG_id_tag_update(&data.to->id, DEG_TAG_COPY_ON_WRITE);
+       DEG_relations_tag_update(bmain);
+       WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
+
+       return OPERATOR_FINISHED;
 }
 
-static void outliner_drag_drop_tooltip_cb(const wmWindow *win, void *vdata)
+void OUTLINER_OT_collection_drop(wmOperatorType *ot)
 {
-       OutlinerDragDropTooltip *data = vdata;
-       const char *tooltip;
-
-       int cursorx, cursory;
-       int x, y;
-
-       tooltip = outliner_drag_drop_tooltip_get(data->te);
-       if (tooltip == NULL) {
-               return;
-       }
-
-       cursorx = win->eventstate->x;
-       cursory = win->eventstate->y;
+       /* identifiers */
+       ot->name = "Move to Collection";
+       ot->description = "Drag to move to collection in Outliner";
+       ot->idname = "OUTLINER_OT_collection_drop";
 
-       x = cursorx + U.widget_unit;
-       y = cursory - U.widget_unit;
+       /* api callbacks */
+       ot->invoke = collection_drop_invoke;
+       ot->poll = ED_operator_outliner_active;
 
-       /* Drawing. */
-       const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+}
 
-       const float col_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f};
-       const float col_bg[4] = {0.0f, 0.0f, 0.0f, 0.2f};
+/* ********************* Outliner Drag Operator ******************** */
 
-       GPU_blend(true);
-       UI_fontstyle_draw_simple_backdrop(fstyle, x, y, tooltip, col_fg, col_bg);
-       GPU_blend(false);
+static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *ar, const wmEvent *event)
+{
+       /* note: using EVT_TWEAK_ events to trigger dragging is fine,
+        * it sends coordinates from where dragging was started */
+       const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]);
+       return outliner_find_item_at_y(soops, &soops->tree, my);
 }
 
-static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
 {
        ARegion *ar = CTX_wm_region(C);
        SpaceOops *soops = CTX_wm_space_outliner(C);
-       TreeElement *te_dragged = outliner_item_drag_element_find(soops, ar, event);
+       TreeElement *te = outliner_item_drag_element_find(soops, ar, event);
 
-       if (!te_dragged) {
-               return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
+       if (!te) {
+               return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+       }
+
+       TreeElementIcon data = tree_element_get_icon(TREESTORE(te), te);
+       if (!data.drag_id) {
+               return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
        }
 
-       OutlinerDragDropTooltip *data = MEM_mallocN(sizeof(OutlinerDragDropTooltip), __func__);
-       data->te = te_dragged;
+       wmDrag *drag = WM_event_start_drag(C, data.icon, WM_DRAG_ID, NULL, 0.0, WM_DRAG_NOP);
 
-       op->customdata = data;
-       te_dragged->drag_data = MEM_callocN(sizeof(*te_dragged->drag_data), __func__);
-       /* by default we don't change the item position */
-       te_dragged->drag_data->insert_handle = te_dragged;
-       /* unset highlighted tree element, dragged one will be highlighted instead */
-       outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED, false);
+       if (GS(data.drag_id->name) == ID_OB) {
+               /* For objects we cheat and drag all selected objects. */
+               TREESTORE(te)->flag |= TSE_SELECTED;
 
-       ED_region_tag_redraw_no_rebuild(ar);
+               struct ObjectsSelectedData selected = {
+                       .objects_selected_array  = {NULL, NULL},
+               };
 
-       WM_event_add_modal_handler(C, op);
+               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;
 
-       data->handle = WM_draw_cb_activate(CTX_wm_window(C), outliner_drag_drop_tooltip_cb, data);
+                       /* Find parent collection of object. */
+                       Collection *parent = NULL;
 
-       return OPERATOR_RUNNING_MODAL;
+                       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);
+                                               break;
+                                       }
+                               }
+                       }
+                       else {
+                               Scene *scene = CTX_data_scene(C);
+                               parent = BKE_collection_master(scene);
+                       }
+
+                       WM_drag_add_ID(drag, &ob->id, &parent->id);
+               }
+
+               BLI_freelistN(&selected.objects_selected_array);
+       }
+       else {
+               /* Add single ID. */
+               WM_drag_add_ID(drag, data.drag_id, data.drag_parent);
+       }
+
+       return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
 }
 
-/**
- * Notes about Outliner Item Drag 'n Drop:
- * Right now only collections display mode is supported. But ideally all/most modes would support this. There are
- * just some open design questions that have to be answered: do we want to allow mixing order of different data types
- * (like render-layers and objects)? Would that be a purely visual change or would that have any other effect? ...
- */
+/* Outliner drag and drop. This operator mostly exists to support dragging
+ * from outliner text instead of only from the icon, and also to show a
+ * hint in the statusbar keymap. */
+
 void OUTLINER_OT_item_drag_drop(wmOperatorType *ot)
 {
        ot->name = "Drag and Drop";
        ot->idname = "OUTLINER_OT_item_drag_drop";
-       ot->description = "Change the hierarchical position of an item by repositioning it using drag and drop";
+       ot->description = "Drag and drop element to another place";
 
        ot->invoke = outliner_item_drag_drop_invoke;
-       ot->modal = outliner_item_drag_drop_modal;
-
-       ot->poll = outliner_item_drag_drop_poll;
-
-       ot->flag = OPTYPE_UNDO;
+       ot->poll = ED_operator_outliner_active;
 }
 
 /* *************************** Drop Boxes ************************** */
index 5672351d62fbbb9f2d32b7366b4c33958254afd9..211c9e1a39278ecb1ffa6eb9fcd61af7edf1e3d2 100644 (file)
@@ -1356,13 +1356,10 @@ static void tselem_draw_icon(
                UI_icon_draw_alpha(x, y, data.icon, alpha);
        }
        else {
-               uiBut *but = uiDefIconBut(
+               uiDefIconBut(
                        block, UI_BTYPE_LABEL, 0, data.icon, x, y, UI_UNIT_X, UI_UNIT_Y, NULL,
                        0.0, 0.0, 1.0, alpha,
                        (data.drag_id && ID_IS_LINKED(data.drag_id)) ? data.drag_id->lib->name : "");
-
-               if (data.drag_id)
-                       UI_but_drag_set_id(but, data.drag_id);
        }
 }
 
@@ -1578,7 +1575,7 @@ static void outliner_set_coord_tree_element(TreeElement *te, int startx, int sta
 static void outliner_draw_tree_element(
         bContext *C, uiBlock *block, const uiFontStyle *fstyle, Scene *scene, ViewLayer *view_layer,
         ARegion *ar, SpaceOops *soops, TreeElement *te, bool draw_grayed_out,
-        int startx, int *starty, TreeElement **te_edit, TreeElement **te_floating)
+        int startx, int *starty, TreeElement **te_edit)
 {
        TreeStoreElem *tselem;
        float ufac = UI_UNIT_X / 20.0f;
@@ -1595,9 +1592,6 @@ static void outliner_draw_tree_element(
                if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == NULL)) {
                        *te_edit = te;
                }
-               if ((te->drag_data != NULL) && (*te_floating == NULL)) {
-                       *te_floating = te;
-               }
 
                /* icons can be ui buts, we don't want it to overlap with restrict */
                if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0)
@@ -1799,11 +1793,11 @@ static void outliner_draw_tree_element(
                for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) {
                        /* check if element needs to be drawn grayed out, but also gray out
                         * childs of a grayed out parent (pass on draw_grayed_out to childs) */
-                       bool draw_childs_grayed_out = draw_grayed_out || (ten->drag_data != NULL);
+                       bool draw_childs_grayed_out = draw_grayed_out || (ten->flag & TE_DRAGGING);
                        outliner_draw_tree_element(
                                C, block, fstyle, scene, view_layer,
                                ar, soops, ten, draw_childs_grayed_out,
-                               startx + UI_UNIT_X, starty, te_edit, te_floating);
+                               startx + UI_UNIT_X, starty, te_edit);
                }
        }
        else {
@@ -1815,54 +1809,6 @@ static void outliner_draw_tree_element(
        }
 }
 
-static void outliner_draw_tree_element_floating(
-        const ARegion *ar, const TreeElement *te_floating)
-{
-       const TreeElement *te_insert = te_floating->drag_data->insert_handle;
-       const int line_width = 2;
-
-       uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-       int coord_y = te_insert->ys;
-       int coord_x = te_insert->xs;
-       float col[4];
-
-       if (te_insert == te_floating) {
-               /* don't draw anything */
-               return;
-       }
-
-       UI_GetThemeColorShade4fv(TH_BACK, -40, col);
-       immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-       GPU_blend(true);
-
-       if (ELEM(te_floating->drag_data->insert_type, TE_INSERT_BEFORE, TE_INSERT_AFTER)) {
-               if (te_floating->drag_data->insert_type == TE_INSERT_BEFORE) {
-                       coord_y += UI_UNIT_Y;
-               }
-               immUniformColor4fv(col);
-               GPU_line_width(line_width);
-
-               immBegin(GPU_PRIM_LINE_STRIP, 2);
-               immVertex2f(pos, coord_x, coord_y);
-               immVertex2f(pos, ar->v2d.cur.xmax, coord_y);
-               immEnd();
-       }
-       else {
-               BLI_assert(te_floating->drag_data->insert_type == TE_INSERT_INTO);
-               immUniformColor3fvAlpha(col, col[3] * 0.5f);
-
-               immBegin(GPU_PRIM_TRI_STRIP, 4);
-               immVertex2f(pos, coord_x, coord_y + UI_UNIT_Y);
-               immVertex2f(pos, coord_x, coord_y);
-               immVertex2f(pos, ar->v2d.cur.xmax, coord_y + UI_UNIT_Y);
-               immVertex2f(pos, ar->v2d.cur.xmax, coord_y);
-               immEnd();
-       }
-
-       GPU_blend(false);
-       immUnbindProgram();
-}
-
 static void outliner_draw_hierarchy_lines_recursive(
         unsigned pos, SpaceOops *soops, ListBase *lb, int startx,
         const unsigned char col[4], bool draw_grayed_out,
@@ -1880,7 +1826,7 @@ static void outliner_draw_hierarchy_lines_recursive(
        /* For vertical lines between objects. */
        y1 = y2 = *starty;
        for (te = lb->first; te; te = te->next) {
-               bool draw_childs_grayed_out = draw_grayed_out || (te->drag_data != NULL);
+               bool draw_childs_grayed_out = draw_grayed_out || (te->flag & TE_DRAGGING);
                TreeStoreElem *tselem = TREESTORE(te);
 
                if (draw_childs_grayed_out) {
@@ -1997,18 +1943,42 @@ static void outliner_draw_highlights_recursive(
                        immRecti(pos, 0, start_y + 1, (int)ar->v2d.cur.xmax, start_y + UI_UNIT_Y - 1);
                }
 
-               /* search match highlights
-                *   we don't expand items when searching in the datablocks but we
-                *   still want to highlight any filter matches. */
-               if (is_searching && (tselem->flag & TSE_SEARCHMATCH)) {
-                       immUniformColor4fv(col_searchmatch);
-                       immRecti(pos, start_x, start_y + 1, ar->v2d.cur.xmax, start_y + UI_UNIT_Y - 1);
-               }
+               /* highlights */
+               if (tselem->flag & (TSE_DRAG_ANY | TSE_HIGHLIGHTED | TSE_SEARCHMATCH)) {
+                       const int end_x = (int)ar->v2d.cur.xmax;
 
-               /* mouse hover highlights */
-               if ((tselem->flag & TSE_HIGHLIGHTED) || (te->drag_data != NULL)) {
-                       immUniformColor4fv(col_highlight);
-                       immRecti(pos, 0, start_y + 1, (int)ar->v2d.cur.xmax, start_y + UI_UNIT_Y - 1);
+                       if (tselem->flag & TSE_DRAG_ANY) {
+                               /* drag and drop highlight */
+                               float col[4];
+                               UI_GetThemeColorShade4fv(TH_BACK, -40, col);
+
+                               if (tselem->flag & TSE_DRAG_BEFORE) {
+                                       immUniformColor4fv(col);
+                                       immRecti(pos, start_x, start_y + UI_UNIT_Y - 1, end_x, start_y + UI_UNIT_Y + 1);
+                               }
+                               else if (tselem->flag & TSE_DRAG_AFTER) {
+                                       immUniformColor4fv(col);
+                                       immRecti(pos, start_x, start_y - 1, end_x, start_y + 1);
+                               }
+                               else {
+                                       immUniformColor3fvAlpha(col, col[3] * 0.5f);
+                                       immRecti(pos, start_x, start_y + 1, end_x, start_y + UI_UNIT_Y - 1);
+                               }
+                       }
+                       else {
+                               if (is_searching && (tselem->flag & TSE_SEARCHMATCH)) {
+                                       /* search match highlights
+                                        *   we don't expand items when searching in the datablocks but we
+                                        *   still want to highlight any filter matches. */
+                                       immUniformColor4fv(col_searchmatch);
+                                       immRecti(pos, start_x, start_y + 1, end_x, start_y + UI_UNIT_Y - 1);
+                               }
+                               else if (tselem->flag & TSE_HIGHLIGHTED) {
+                                       /* mouse hover highlight */
+                                       immUniformColor4fv(col_highlight);
+                                       immRecti(pos, 0, start_y + 1, end_x, start_y + UI_UNIT_Y - 1);
+                               }
+                       }
                }
 
                *io_start_y -= UI_UNIT_Y;
@@ -2047,7 +2017,6 @@ static void outliner_draw_tree(
         TreeElement **te_edit)
 {
        const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
-       TreeElement *te_floating = NULL;
        int starty, startx;
 
        GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); // only once
@@ -2085,11 +2054,8 @@ static void outliner_draw_tree(
        for (TreeElement *te = soops->tree.first; te; te = te->next) {
                outliner_draw_tree_element(
                        C, block, fstyle, scene, view_layer,
-                       ar, soops, te, te->drag_data != NULL,
-                       startx, &starty, te_edit, &te_floating);
-       }
-       if (te_floating && te_floating->drag_data->insert_handle) {
-               outliner_draw_tree_element_floating(ar, te_floating);
+                       ar, soops, te, (te->flag & TE_DRAGGING) != 0,
+                       startx, &starty, te_edit);
        }
 
        if (has_restrict_icons) {
index 6316b65fefb2f38f3ab1fa18863d86356946f59d..e895ff53bc58a959b6d3acef6e956814ba57c0ba 100644 (file)
 
 static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
 {
+       /* Drag and drop does own highlighting. */
+       wmWindowManager *wm = CTX_wm_manager(C);
+       if (wm->drags.first) {
+               return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+       }
+
        ARegion *ar = CTX_wm_region(C);
        SpaceOops *soops = CTX_wm_space_outliner(C);
        const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]);
@@ -103,7 +109,7 @@ static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const
        bool changed = false;
 
        if (!hovered_te || !(hovered_te->store_elem->flag & TSE_HIGHLIGHTED)) {
-               changed = outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED, false);
+               changed = outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED | TSE_DRAG_ANY, false);
                if (hovered_te) {
                        hovered_te->store_elem->flag |= TSE_HIGHLIGHTED;
                        changed = true;
index e5ed7de2a24ec095f4c3610d6118413b3d590535..f8dc41b8d37c498f6c20ed5f2383413e4e2d720d 100644 (file)
@@ -67,23 +67,6 @@ typedef enum TreeTraversalAction {
        TRAVERSE_SKIP_CHILDS,
 } TreeTraversalAction;
 
-/**
- * Callback type for reinserting elements at a different position, used to allow user customizable element order.
- */
-typedef void (*TreeElementReinsertFunc)(struct Main *bmain,
-                                        struct Scene *scene,
-                                        struct SpaceOops *soops,
-                                        struct TreeElement *insert_element,
-                                        struct TreeElement *insert_handle,
-                                        TreeElementInsertType action,
-                                        const struct wmEvent *event);
-/**
- * Executed on (almost) each mouse move while dragging. It's supposed to give info
- * if reinserting insert_element before/after/into insert_handle would be allowed.
- * It's allowed to change the reinsert info here for non const pointers.
- */
-typedef bool (*TreeElementReinsertPollFunc)(const struct TreeElement *insert_element,
-                                            struct TreeElement **io_insert_handle, TreeElementInsertType *io_action);
 typedef TreeTraversalAction (*TreeTraversalFunc)(struct TreeElement *te, void *customdata);
 
 
@@ -99,17 +82,6 @@ typedef struct TreeElement {
        const char *name;
        void *directdata;          // Armature Bones, Base, Sequence, Strip...
        PointerRNA rnaptr;         // RNA Pointer
-
-       /* callbacks - TODO should be moved into a type (like TreeElementType) */
-       TreeElementReinsertFunc reinsert;
-       TreeElementReinsertPollFunc reinsert_poll;
-
-       struct {
-               TreeElementInsertType insert_type;
-               /* the element before/after/into which we may insert the dragged one (NULL to insert at top) */
-               struct TreeElement *insert_handle;
-               void *tooltip_draw_handle;
-       } *drag_data;
 } TreeElement;
 
 typedef struct TreeElementIcon {
@@ -131,6 +103,7 @@ enum {
        TE_LAZY_CLOSED = (1 << 2),
        TE_FREE_NAME   = (1 << 3),
        TE_DISABLED    = (1 << 4),
+       TE_DRAGGING    = (1 << 5),
 };
 
 /* button events */
@@ -294,11 +267,6 @@ void item_object_mode_exit_cb(
 void outliner_set_coordinates(struct ARegion *ar, struct SpaceOops *soops);
 
 /* outliner_dragdrop.c */
-enum {
-       OUTLINER_ITEM_DRAG_CANCEL,
-       OUTLINER_ITEM_DRAG_CONFIRM,
-};
-
 void outliner_dropboxes(void);
 
 void OUTLINER_OT_item_drag_drop(struct wmOperatorType *ot);
index a4aad11a8214025b8bf64112b2ee4c3c3389874c..34d79ea5a61ec476c2539de2a33949767e04c3f1 100644 (file)
@@ -117,36 +117,6 @@ void outliner_operatortypes(void)
        WM_operatortype_append(OUTLINER_OT_collection_indirect_only_clear);
 }
 
-static wmKeyMap *outliner_item_drag_drop_modal_keymap(wmKeyConfig *keyconf)
-{
-       static EnumPropertyItem modal_items[] = {
-               {OUTLINER_ITEM_DRAG_CANCEL,  "CANCEL",  0, "Cancel", ""},
-               {OUTLINER_ITEM_DRAG_CONFIRM, "CONFIRM", 0, "Confirm/Drop", ""},
-               {0, NULL, 0, NULL, NULL}
-       };
-       const char *map_name = "Outliner Item Drag & Drop Modal Map";
-
-       wmKeyMap *keymap = WM_modalkeymap_get(keyconf, map_name);
-
-       /* this function is called for each spacetype, only needs to add map once */
-       if (keymap && keymap->modal_items)
-               return NULL;
-
-       keymap = WM_modalkeymap_add(keyconf, map_name, modal_items);
-
-       /* items for modal map */
-       WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, OUTLINER_ITEM_DRAG_CANCEL);
-       WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, OUTLINER_ITEM_DRAG_CANCEL);
-
-       WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, OUTLINER_ITEM_DRAG_CONFIRM);
-       WM_modalkeymap_add_item(keymap, RETKEY, KM_RELEASE, KM_ANY, 0, OUTLINER_ITEM_DRAG_CONFIRM);
-       WM_modalkeymap_add_item(keymap, PADENTER, KM_RELEASE, KM_ANY, 0, OUTLINER_ITEM_DRAG_CONFIRM);
-
-       WM_modalkeymap_assign(keymap, "OUTLINER_OT_item_drag_drop");
-
-       return keymap;
-}
-
 void outliner_keymap(wmKeyConfig *keyconf)
 {
        wmKeyMap *keymap = WM_keymap_find(keyconf, "Outliner", SPACE_OUTLINER, 0);
@@ -236,6 +206,4 @@ void outliner_keymap(wmKeyConfig *keyconf)
        RNA_boolean_set(kmi->ptr, "unselected", false);
        kmi = WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_set", HKEY, KM_PRESS, KM_SHIFT, 0);
        RNA_boolean_set(kmi->ptr, "unselected", true);
-
-       outliner_item_drag_drop_modal_keymap(keyconf);
 }
index 539df3aa085c715f9990d6b8fa3e81f8979b8eb8..55a437d6ad541443e141b057ae9a4d8c5b65af72 100644 (file)
@@ -321,108 +321,9 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s
 
 }
 
-TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata)
-{
-       struct ObjectsSelectedData *data = customdata;
-       TreeStoreElem *tselem = TREESTORE(te);
-
-       if (outliner_is_collection_tree_element(te)) {
-               return TRAVERSE_CONTINUE;
-       }
-
-       if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
-               return TRAVERSE_SKIP_CHILDS;
-       }
-
-       BLI_addtail(&data->objects_selected_array, BLI_genericNodeN(te));
-
-       return TRAVERSE_CONTINUE;
-}
-
-/**
- * Move objects from a collection to another.
- * We ignore the original object being inserted, we used it for polling only.
- * Instead we move all the selected objects around.
- */
-static void outliner_object_reorder(
-        Main *bmain, Scene *scene,
-        SpaceOops *soops,
-        TreeElement *insert_element,
-        TreeElement *insert_handle, TreeElementInsertType action,
-        const wmEvent *event)
-{
-       Collection *collection = outliner_collection_from_tree_element(insert_handle);
-       Collection *collection_ob_parent = NULL;
-       ID *id = insert_handle->store_elem->id;
-
-       BLI_assert(action == TE_INSERT_INTO);
-       UNUSED_VARS_NDEBUG(action);
-
-       struct ObjectsSelectedData data = {
-               .objects_selected_array  = {NULL, NULL},
-       };
-
-       const bool is_append = event->ctrl;
-
-       /* Make sure we include the originally inserted element as well. */
-       TREESTORE(insert_element)->flag |= TSE_SELECTED;
-
-       outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data);
-       LISTBASE_FOREACH (LinkData *, link, &data.objects_selected_array) {
-               TreeElement *ten_selected = (TreeElement *)link->data;
-               Object *ob = (Object *)TREESTORE(ten_selected)->id;
-
-               if (is_append) {
-                       BKE_collection_object_add(bmain, collection, ob);
-                       continue;
-               }
-
-               /* Find parent collection of object. */
-               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)) {
-                                       collection_ob_parent = outliner_collection_from_tree_element(te_ob_parent);
-                                       break;
-                               }
-                       }
-               }
-               else {
-                       collection_ob_parent = BKE_collection_master(scene);
-               }
-
-               BKE_collection_object_move(bmain, scene, collection, collection_ob_parent, ob);
-       }
-
-       BLI_freelistN(&data.objects_selected_array);
-
-       DEG_relations_tag_update(bmain);
-
-       /* TODO(sergey): Use proper flag for tagging here. */
-       DEG_id_tag_update(id, 0);
-
-       WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
-}
-
-static bool outliner_object_reorder_poll(
-        const TreeElement *insert_element,
-        TreeElement **io_insert_handle, TreeElementInsertType *io_action)
-{
-       if (outliner_is_collection_tree_element(*io_insert_handle) &&
-           (insert_element->parent != *io_insert_handle))
-       {
-               *io_action = TE_INSERT_INTO;
-               return true;
-       }
-
-       return false;
-}
-
 // can be inlined if necessary
 static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, Object *ob)
 {
-       te->reinsert = outliner_object_reorder;
-       te->reinsert_poll = outliner_object_reorder_poll;
-
        if (outliner_animdata_test(ob->adt))
                outliner_add_element(soops, &te->subtree, ob, te, TSE_ANIM_DATA, 0);
 
@@ -1385,80 +1286,6 @@ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops)
        }
 }
 
-static void outliner_collections_reorder(
-        Main *bmain,
-        Scene *UNUSED(scene),
-        SpaceOops *soops,
-        TreeElement *insert_element,
-        TreeElement *insert_handle,
-        TreeElementInsertType action,
-        const wmEvent *UNUSED(event))
-{
-       TreeElement *from_parent_te, *to_parent_te;
-       Collection *from_parent, *to_parent;
-
-       Collection *collection = outliner_collection_from_tree_element(insert_element);
-       Collection *relative = NULL;
-       bool relative_after = false;
-
-       from_parent_te = outliner_find_parent_element(&soops->tree, NULL, insert_element);
-       from_parent = (from_parent_te) ? outliner_collection_from_tree_element(from_parent_te) : NULL;
-
-       if (ELEM(action, TE_INSERT_BEFORE, TE_INSERT_AFTER)) {
-               to_parent_te = outliner_find_parent_element(&soops->tree, NULL, insert_handle);
-               to_parent = (to_parent_te) ? outliner_collection_from_tree_element(to_parent_te) : NULL;
-
-               relative = outliner_collection_from_tree_element(insert_handle);
-               relative_after = (action == TE_INSERT_AFTER);
-       }
-       else if (action == TE_INSERT_INTO) {
-               to_parent = outliner_collection_from_tree_element(insert_handle);
-       }
-       else {
-               BLI_assert(0);
-               return;
-       }
-
-       if (!to_parent) {
-               return;
-       }
-
-       BKE_collection_move(bmain, to_parent, from_parent, relative, relative_after, collection);
-
-       DEG_relations_tag_update(bmain);
-}
-
-static bool outliner_collections_reorder_poll(
-        const TreeElement *insert_element,
-        TreeElement **io_insert_handle,
-        TreeElementInsertType *io_action)
-{
-       /* Can't move master collection. */
-       Collection *collection = outliner_collection_from_tree_element(insert_element);
-       if (collection->flag & COLLECTION_IS_MASTER) {
-               return false;
-       }
-
-       /* Can only move into collections. */
-       Collection *collection_handle = outliner_collection_from_tree_element(*io_insert_handle);
-       if (collection_handle == NULL) {
-               return false;
-       }
-
-       /* We can't insert/before after master collection. */
-       if (collection_handle->flag & COLLECTION_IS_MASTER) {
-               if (*io_action == TE_INSERT_BEFORE) {
-                       /* can't go higher than master collection, insert into it */
-                       *io_action = TE_INSERT_INTO;
-               }
-               else if (*io_action == TE_INSERT_AFTER) {
-                       *io_insert_handle = (*io_insert_handle)->subtree.last;
-               }
-       }
-
-       return true;
-}
-
 static void outliner_add_layer_collection_objects(
         SpaceOops *soops, ListBase *tree, ViewLayer *layer,
         LayerCollection *lc, TreeElement *ten)
@@ -1485,8 +1312,6 @@ static void outliner_add_layer_collections_recursive(
 
                ten->name = id->name + 2;
                ten->directdata = lc;
-               ten->reinsert = outliner_collections_reorder;
-               ten->reinsert_poll = outliner_collections_reorder_poll;
 
                const bool exclude = (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0;
                if (exclude ||
@@ -1528,8 +1353,6 @@ BLI_INLINE void outliner_add_collection_init(TreeElement *te, Collection *collec
        }
 
        te->directdata = collection;
-       te->reinsert = outliner_collections_reorder;
-       te->reinsert_poll = outliner_collections_reorder_poll;
 }
 
 BLI_INLINE void outliner_add_collection_objects(
index 449f71905f08d760bdf1875890a1a11f16e18bc2..75d0ce493f55c20401b0e52aae20b2b91f9a12be 100644 (file)
@@ -60,6 +60,10 @@ enum {
        TSE_CHILDSEARCH = (1 << 3),
        TSE_SEARCHMATCH = (1 << 4),
        TSE_HIGHLIGHTED = (1 << 5),
+       TSE_DRAG_INTO   = (1 << 6),
+       TSE_DRAG_BEFORE = (1 << 7),
+       TSE_DRAG_AFTER  = (1 << 8),
+       TSE_DRAG_ANY    = (TSE_DRAG_INTO | TSE_DRAG_BEFORE | TSE_DRAG_AFTER),
 };
 
 /* TreeStoreElem->types */
index 0c77ad89292052cdfc76c1bff3d6b16ac8f28c9d..73748ba6322654bd1349701c09fbbe90af5e398a 100644 (file)
@@ -352,9 +352,10 @@ static const char *wm_drag_name(wmDrag *drag)
                        if (single) {
                                return id->name + 2;
                        }
-                       else {
+                       else if (id) {
                                return BKE_idcode_to_name_plural(GS(id->name));
                        }
+                       break;
                }
                case WM_DRAG_PATH:
                case WM_DRAG_NAME: