diff options
author | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2018-08-10 18:04:05 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2018-08-10 18:54:00 +0300 |
commit | d7b5e2fa72c91b603713b52eec22af9ae131926d (patch) | |
tree | 04a9e350c23cc68888f7a56e55bbd85ca9ecdfbe /source/blender | |
parent | 4375e7ff0b74f96447e27f78a0d9245353d36865 (diff) |
Outliner: use generic WM drag and drop system for collections.
* Drag and drop between multiple outliners now works.
* Dragging the icon and text now give the same results.
* Fixes various crashes.
Diffstat (limited to 'source/blender')
9 files changed, 385 insertions, 634 deletions
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index 946d2b019a9..d4c85ce28bd 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -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. */ diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c index f9a4fda0c45..55b9a561503 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.c +++ b/source/blender/editors/space_outliner/outliner_dragdrop.c @@ -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 ************************** */ diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 5672351d62f..211c9e1a392 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -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) { diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 6316b65fefb..e895ff53bc5 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -95,6 +95,12 @@ 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; diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index e5ed7de2a24..f8dc41b8d37 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -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); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index a4aad11a821..34d79ea5a61 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -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); } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 539df3aa085..55a437d6ad5 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -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( diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h index 449f71905f0..75d0ce493f5 100644 --- a/source/blender/makesdna/DNA_outliner_types.h +++ b/source/blender/makesdna/DNA_outliner_types.h @@ -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 */ diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index 0c77ad89292..73748ba6322 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -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: |