[Bf-blender-cvs] [d7b5e2fa72c] blender2.8: Outliner: use generic WM drag and drop system for collections.
Brecht Van Lommel
noreply at git.blender.org
Fri Aug 10 17:57:41 CEST 2018
Commit: d7b5e2fa72c91b603713b52eec22af9ae131926d
Author: Brecht Van Lommel
Date: Fri Aug 10 17:04:05 2018 +0200
Branches: blender2.8
https://developer.blender.org/rBd7b5e2fa72c91b603713b52eec22af9ae131926d
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.
===================================================================
M source/blender/editors/space_outliner/outliner_collections.c
M source/blender/editors/space_outliner/outliner_dragdrop.c
M source/blender/editors/space_outliner/outliner_draw.c
M source/blender/editors/space_outliner/outliner_edit.c
M source/blender/editors/space_outliner/outliner_intern.h
M source/blender/editors/space_outliner/outliner_ops.c
M source/blender/editors/space_outliner/outliner_tree.c
M source/blender/makesdna/DNA_outliner_types.h
M source/blender/windowmanager/intern/wm_dragdrop.c
===================================================================
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 (vi
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list