diff options
author | Jacques Lucke <mail@jlucke.com> | 2018-10-22 14:53:36 +0300 |
---|---|---|
committer | Jacques Lucke <mail@jlucke.com> | 2018-10-22 14:53:36 +0300 |
commit | 0f54c3a9b75be8f8db9022fb0aeb0f8d0d4f0299 (patch) | |
tree | 0e36509bcdd0a33063af244b410db62c18710a1a /source/blender | |
parent | 2d084d4ec430ec8b280a52286eeeca770f2221bc (diff) |
Outliner: drag&drop - separate moving from parenting
Use drag&drop to parent objects in the outliner by holding down shift.
Previously it was easy to accidently parent objects and there was no way to notice it immediatly.
In some views it is possible to parent objects without using shift; should be obvious from context.
Reviewers: brecht
Differential Revision: https://developer.blender.org/D3812
Diffstat (limited to 'source/blender')
3 files changed, 113 insertions, 82 deletions
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index c43f3d7eaf4..7448c4b65ce 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -81,7 +81,7 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te) TreeStoreElem *tselem = TREESTORE(te); if (!tselem) { - return false; + return NULL; } if (tselem->type == TSE_LAYER_COLLECTION) { diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c index 4a1e720fe2a..66052166bf7 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.c +++ b/source/blender/editors/space_outliner/outliner_dragdrop.c @@ -50,6 +50,7 @@ #include "BKE_material.h" #include "BKE_report.h" #include "BKE_scene.h" +#include "BKE_object.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -192,18 +193,32 @@ static TreeElement *outliner_drop_insert_find( } } +static Collection *outliner_collection_from_tree_element_and_parents(TreeElement *te, TreeElement **r_te) +{ + while (te != NULL) { + Collection *collection = outliner_collection_from_tree_element(te); + if (collection) { + *r_te = te; + return collection; + } + te = te->parent; + } + 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; - } + if (!te) return NULL; - Collection *collection = outliner_collection_from_tree_element(te); - if (!collection) { - return NULL; + TreeElement *collection_te; + Collection *collection = outliner_collection_from_tree_element_and_parents(te, &collection_te); + if (!collection) return NULL; + + if (collection_te != te) { + *r_insert_type = TE_INSERT_INTO; } /* We can't insert before/after master collection. */ @@ -211,54 +226,80 @@ static TreeElement *outliner_drop_insert_collection_find( *r_insert_type = TE_INSERT_INTO; } - return te; + return collection_te; } /* ******************** Parent Drop Operator *********************** */ -static bool parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(tooltip)) +static bool parent_drop_allowed(SpaceOops *soops, TreeElement *te, Object *potential_child) { - SpaceOops *soops = CTX_wm_space_outliner(C); - Object *ob = (Object *)WM_drag_ID(drag, ID_OB); - if (!ob) { + TreeStoreElem *tselem = TREESTORE(te); + if (te->idcode != ID_OB || tselem->type != 0) { return false; } - /* Ensure item under cursor is valid drop target */ - TreeElement *te = outliner_drop_find(C, event); - TreeStoreElem *tselem = te ? TREESTORE(te) : NULL; + Object *potential_parent = (Object *)tselem->id; - if (!te) { - /* pass */ + if (potential_parent == potential_child) return false; + if (BKE_object_is_child_recursive(potential_child, potential_parent)) return false; + if (potential_parent == potential_child->parent) return false; + + /* check that parent/child are both in the same scene */ + Scene *scene = (Scene *)outliner_search_back(soops, te, ID_SCE); + + /* currently outliner organized in a way that if there's no parent scene + * element for object it means that all displayed objects belong to + * active scene and parenting them is allowed (sergey) + */ + if (scene) { + for (ViewLayer *view_layer = scene->view_layers.first; + view_layer; + view_layer = view_layer->next) + { + if (BKE_view_layer_base_find(view_layer, potential_child)) { + return true; + } + } + return false; + } + else { + return true; } - else if (te->idcode == ID_OB && tselem->type == 0) { - Scene *scene; - ID *te_id = tselem->id; +} - /* check if dropping self or parent */ - if (te_id == &ob->id || (Object *)te_id == ob->parent) +static bool allow_parenting_without_modifier_key(SpaceOops *soops) +{ + switch (soops->outlinevis) { + case SO_VIEW_LAYER: + return soops->filter & SO_FILTER_NO_COLLECTION; + case SO_SCENES: + return true; + default: return false; + } +} - /* check that parent/child are both in the same scene */ - scene = (Scene *)outliner_search_back(soops, te, ID_SCE); +static bool parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(tooltip)) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); - /* currently outliner organized in a way that if there's no parent scene - * element for object it means that all displayed objects belong to - * active scene and parenting them is allowed (sergey) - */ - if (!scene) { - return true; - } - else { - for (ViewLayer *view_layer = scene->view_layers.first; - view_layer; - view_layer = view_layer->next) - { - if (BKE_view_layer_base_find(view_layer, ob)) { - return true; - } - } - } + bool changed = outliner_flag_set(&soops->tree, TSE_DRAG_ANY, false); + if (changed) ED_region_tag_redraw_no_rebuild(CTX_wm_region(C)); + + Object *potential_child = (Object *)WM_drag_ID(drag, ID_OB); + if (!potential_child) return false; + + if (!allow_parenting_without_modifier_key(soops)) { + if (!event->shift) return false; + } + + TreeElement *te = outliner_drop_find(C, event); + if (!te) return false; + + if (parent_drop_allowed(soops, te, potential_child)) { + TREESTORE(te)->flag |= TSE_DRAG_INTO; + ED_region_tag_redraw_no_rebuild(CTX_wm_region(C)); + return true; } return false; @@ -436,52 +477,38 @@ void OUTLINER_OT_parent_drop(wmOperatorType *ot) RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", ""); } -static bool parenting_poll(bContext *C) -{ - SpaceOops *soops = CTX_wm_space_outliner(C); - - if (soops) { - if (soops->outlinevis == SO_SCENES) { - return true; - } - else if ((soops->outlinevis == SO_VIEW_LAYER) && - (soops->filter & SO_FILTER_NO_COLLECTION)) - { - return true; - } - } - - return false; -} - /* ******************** Parent Clear Operator *********************** */ static bool parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(tooltip)) { SpaceOops *soops = CTX_wm_space_outliner(C); - if (!ELEM(soops->outlinevis, SO_VIEW_LAYER)) { - return false; + if (!allow_parenting_without_modifier_key(soops)) { + if (!event->shift) return false; } Object *ob = (Object *)WM_drag_ID(drag, ID_OB); - if (!(ob && ob->parent)) { - return false; - } + if (!ob) return false; + if (!ob->parent) return false; TreeElement *te = outliner_drop_find(C, event); if (te) { TreeStoreElem *tselem = TREESTORE(te); + ID *id = tselem->id; + if (!id) return true; - switch (te->idcode) { - case ID_SCE: - return (ELEM(tselem->type, TSE_R_LAYER_BASE, TSE_R_LAYER)); + switch (GS(id->name)) { case ID_OB: - return (ELEM(tselem->type, TSE_MODIFIER_BASE, TSE_CONSTRAINT_BASE)); - /* Other codes to ignore? */ + return ELEM(tselem->type, TSE_MODIFIER_BASE, TSE_CONSTRAINT_BASE); + case ID_GR: + return event->shift; + default: + return true; } } - return (te == NULL); + else { + return true; + } } static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) @@ -511,7 +538,7 @@ void OUTLINER_OT_parent_clear(wmOperatorType *ot) /* api callbacks */ ot->invoke = parent_clear_invoke; - ot->poll = parenting_poll; + ot->poll = ED_operator_outliner_active; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; @@ -655,6 +682,8 @@ static Collection *collection_parent_from_ID(ID *id) static bool collection_drop_init(bContext *C, wmDrag *drag, const wmEvent *event, CollectionDrop *data) { + SpaceOops *soops = CTX_wm_space_outliner(C); + /* Get collection to drop into. */ TreeElementInsertType insert_type; TreeElement *te = outliner_drop_insert_collection_find(C, event, &insert_type); @@ -685,7 +714,7 @@ static bool collection_drop_init(bContext *C, wmDrag *drag, const wmEvent *event /* Get collection to drag out of. */ ID *parent = drag_id->from_parent; Collection *from_collection = collection_parent_from_ID(parent); - if (event->ctrl) { + if (event->ctrl || soops->outlinevis == SO_SCENES) { from_collection = NULL; } @@ -714,14 +743,15 @@ static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event bool changed = outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED | TSE_DRAG_ANY, false); CollectionDrop data; - if (collection_drop_init(C, drag, event, &data)) { + if (!event->shift && collection_drop_init(C, drag, event, &data)) { + TreeElement *te = data.te; + TreeStoreElem *tselem = TREESTORE(te); if (!data.from || event->ctrl) { + tselem->flag |= TSE_DRAG_INTO; + changed = true; *tooltip = IFACE_("Link inside Collection"); } else { - TreeElement *te = data.te; - TreeStoreElem *tselem = TREESTORE(te); - switch (data.insert_type) { case TE_INSERT_BEFORE: tselem->flag |= TSE_DRAG_BEFORE; @@ -746,17 +776,17 @@ static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event case TE_INSERT_INTO: tselem->flag |= TSE_DRAG_INTO; changed = true; - *tooltip = TIP_("Move inside collection (Ctrl to link)"); + *tooltip = TIP_("Move inside collection (Ctrl to link, Shift to parent)"); break; } } + if (changed) ED_region_tag_redraw_no_rebuild(ar); + return true; } - - if (changed) { - ED_region_tag_redraw_no_rebuild(ar); + else { + if (changed) ED_region_tag_redraw_no_rebuild(ar); + return false; } - - return true; } static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 2794c79eeb2..089b153fa26 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -156,6 +156,7 @@ void outliner_keymap(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "OUTLINER_OT_operation", RIGHTMOUSE, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "OUTLINER_OT_item_drag_drop", EVT_TWEAK_L, KM_ANY, 0, 0); + WM_keymap_add_item(keymap, "OUTLINER_OT_item_drag_drop", EVT_TWEAK_L, KM_ANY, KM_SHIFT, 0); WM_keymap_add_item(keymap, "OUTLINER_OT_show_hierarchy", HOMEKEY, KM_PRESS, 0, 0); |