[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