[Bf-blender-cvs] [67302025105] blender2.8: Improve outliner drag&drop feedback by using drop poll callbacks

Julian Eisel noreply at git.blender.org
Fri Mar 10 17:17:18 CET 2017


Commit: 67302025105ed3f1273b5714d792ec7a79f7e381
Author: Julian Eisel
Date:   Fri Mar 10 17:05:50 2017 +0100
Branches: blender2.8
https://developer.blender.org/rB67302025105ed3f1273b5714d792ec7a79f7e381

Improve outliner drag&drop feedback by using drop poll callbacks

This way we can ensure the overlay to indicate where the item would be
placed if it was dropped now is always at the correct place and doesn't
mislead the user.

===================================================================

M	source/blender/editors/space_outliner/outliner_draw.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

===================================================================

diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 771591240d6..6207ed8579c 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -1772,7 +1772,7 @@ static void outliner_draw_tree(
 		outliner_draw_tree_element(C, block, fstyle, scene, sl, ar, soops, te, te->drag_data != NULL,
 		                           startx, &starty, te_edit, &te_floating);
 	}
-	if (te_floating) {
+	if (te_floating && te_floating->drag_data->insert_handle) {
 		outliner_draw_tree_element_floating(ar, te_floating);
 	}
 
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index cad34c96db4..2256e55a315 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -70,6 +70,13 @@ typedef enum TreeTraversalAction {
  */
 typedef void (*TreeElementReinsertFunc)(const struct Scene *scene, struct TreeElement *insert_element,
                                         struct TreeElement *insert_handle, TreeElementInsertType action);
+/**
+ * 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 Scene *scene, const struct TreeElement *insert_element,
+                                            struct TreeElement **io_insert_handle, TreeElementInsertType *io_action);
 typedef TreeTraversalAction (*TreeTraversalFunc)(struct TreeElement *te, void *customdata);
 
 
@@ -86,8 +93,9 @@ typedef struct TreeElement {
 	void *directdata;          // Armature Bones, Base, Sequence, Strip...
 	PointerRNA rnaptr;         // RNA Pointer
 
-	/* callbacks */
+	/* callbacks - TODO should be moved into a type (like TreeElementType) */
 	TreeElementReinsertFunc reinsert;
+	TreeElementReinsertPollFunc reinsert_poll;
 
 	struct {
 		TreeElementInsertType insert_type;
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index 4fc912f85c7..a96f99d332a 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -74,45 +74,48 @@ static void outliner_item_drag_end(TreeElement *dragged_te)
 	MEM_SAFE_FREE(dragged_te->drag_data);
 }
 
-static void outliner_item_drag_handle(
-        SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged)
+static void outliner_item_drag_get_insert_data(
+        SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged,
+        TreeElement **r_te_insert_handle, TreeElementInsertType *r_insert_type)
 {
-	TreeStoreElem *tselem_dragged = TREESTORE(te_dragged);
-	TreeElement *insert_handle;
+	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]);
-	insert_handle = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
+	te_hovered = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
+
+	if (te_hovered) {
+		TreeStoreElem *tselem_hovered = TREESTORE(te_hovered);
 
-	te_dragged->drag_data->insert_handle = NULL;
-	if (insert_handle) {
-		TreeStoreElem *tselem_handle = TREESTORE(insert_handle);
-		if (tselem_handle->type == tselem_dragged->type) {
+		if (te_hovered != te_dragged) {
 			const float margin = UI_UNIT_Y * (1.0f / 4);
 
-			te_dragged->drag_data->insert_handle = insert_handle;
-			if (view_mval[1] < (insert_handle->ys + margin)) {
-				if (TSELEM_OPEN(tselem_handle, soops)) {
+			*r_te_insert_handle = te_hovered;
+			if (view_mval[1] < (te_hovered->ys + margin)) {
+				if (TSELEM_OPEN(tselem_hovered, soops)) {
 					/* inserting after a open item means we insert into it, but as first child */
-					if (BLI_listbase_is_empty(&insert_handle->subtree)) {
-						te_dragged->drag_data->insert_type = TE_INSERT_INTO;
+					if (BLI_listbase_is_empty(&te_hovered->subtree)) {
+						*r_insert_type = TE_INSERT_INTO;
 					}
 					else {
-						te_dragged->drag_data->insert_type = TE_INSERT_BEFORE;
-						te_dragged->drag_data->insert_handle = insert_handle->subtree.first;
+						*r_insert_type = TE_INSERT_BEFORE;
+						*r_te_insert_handle = te_hovered->subtree.first;
 					}
 				}
 				else {
-					te_dragged->drag_data->insert_type = TE_INSERT_AFTER;
+					*r_insert_type = TE_INSERT_AFTER;
 				}
 			}
-			else if (view_mval[1] > (insert_handle->ys + (2 * margin))) {
-				te_dragged->drag_data->insert_type = TE_INSERT_BEFORE;
+			else if (view_mval[1] > (te_hovered->ys + (2 * margin))) {
+				*r_insert_type = TE_INSERT_BEFORE;
 			}
 			else {
-				te_dragged->drag_data->insert_type = TE_INSERT_INTO;
+				*r_insert_type = TE_INSERT_INTO;
 			}
 		}
+		else {
+			*r_te_insert_handle = te_dragged;
+		}
 	}
 	else {
 		TreeElement *first = soops->tree.first;
@@ -120,12 +123,12 @@ static void outliner_item_drag_handle(
 
 		/* mouse doesn't hover any item (ignoring x axis), so it's either above list bounds or below. */
 		if (view_mval[1] < last->ys) {
-			te_dragged->drag_data->insert_handle = last;
-			te_dragged->drag_data->insert_type = TE_INSERT_AFTER;
+			*r_te_insert_handle = last;
+			*r_insert_type = TE_INSERT_AFTER;
 		}
 		else if (view_mval[1] > (first->ys + UI_UNIT_Y)) {
-			te_dragged->drag_data->insert_handle = first;
-			te_dragged->drag_data->insert_type = TE_INSERT_BEFORE;
+			*r_te_insert_handle = first;
+			*r_insert_type = TE_INSERT_BEFORE;
 		}
 		else {
 			BLI_assert(0);
@@ -133,28 +136,48 @@ static void outliner_item_drag_handle(
 	}
 }
 
+static void outliner_item_drag_handle(
+        const Scene *scene, SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged)
+{
+	TreeElement *te_insert_handle;
+	TreeElementInsertType insert_type;
+
+	outliner_item_drag_get_insert_data(soops, ar, event, te_dragged, &te_insert_handle, &insert_type);
+
+	if ((te_dragged != te_insert_handle) &&
+	    te_dragged->reinsert_poll &&
+	    !te_dragged->reinsert_poll(scene, te_dragged, &te_insert_handle, &insert_type))
+	{
+		te_insert_handle = NULL;
+	}
+	te_dragged->drag_data->insert_type = insert_type;
+	te_dragged->drag_data->insert_handle = te_insert_handle;
+}
+
 static bool outliner_item_drag_drop_apply(const Scene *scene, TreeElement *dragged_te)
 {
 	TreeElement *insert_handle = dragged_te->drag_data->insert_handle;
+	TreeElementInsertType insert_type = dragged_te->drag_data->insert_type;
 
-	if (insert_handle == dragged_te) {
+	if ((insert_handle == dragged_te) || !insert_handle) {
 		/* No need to do anything */
-		return false;
 	}
-
-	if (dragged_te->reinsert) {
-		/* Not sure yet what the best way to handle reordering elements of different types
-		 * (and stored in different lists). For collection display mode this is enough. */
-		if (!insert_handle || (insert_handle->reinsert == dragged_te->reinsert)) {
-			dragged_te->reinsert(scene, dragged_te, insert_handle, dragged_te->drag_data->insert_type);
-		}
+	else if (dragged_te->reinsert) {
+		BLI_assert(!dragged_te->reinsert_poll || dragged_te->reinsert_poll(scene, 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);
+		dragged_te->reinsert(scene, dragged_te, insert_handle, insert_type);
+		return true;
 	}
 
-	return true;
+	return false;
 }
 
 static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEvent *event)
 {
+	Scene *scene = CTX_data_scene(C);
 	ARegion *ar = CTX_wm_region(C);
 	SpaceOops *soops = CTX_wm_space_outliner(C);
 	TreeElement *te_dragged = op->customdata;
@@ -165,8 +188,9 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv
 	switch (event->type) {
 		case EVT_MODAL_MAP:
 			if (event->val == OUTLINER_ITEM_DRAG_CONFIRM) {
-				outliner_item_drag_drop_apply(CTX_data_scene(C), te_dragged);
-				skip_rebuild = false;
+				if (outliner_item_drag_drop_apply(scene, te_dragged)) {
+					skip_rebuild = false;
+				}
 				retval = OPERATOR_FINISHED;
 			}
 			else if (event->val == OUTLINER_ITEM_DRAG_CANCEL) {
@@ -180,7 +204,7 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv
 			redraw = true;
 			break;
 		case MOUSEMOVE:
-			outliner_item_drag_handle(soops, ar, event, te_dragged);
+			outliner_item_drag_handle(scene, soops, ar, event, te_dragged);
 			redraw = true;
 			break;
 	}
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 68b533ab31e..1e254b21ff5 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -1306,6 +1306,13 @@ static void outliner_layer_collections_reorder(
 		BLI_assert(0);
 	}
 }
+static bool outliner_layer_collections_reorder_poll(
+        const Scene *UNUSED(scene), const TreeElement *UNUSED(insert_element),
+        TreeElement **io_insert_handle, TreeElementInsertType *UNUSED(io_action))
+{
+	const TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle);
+	return ELEM(tselem_handle->type, TSE_LAYER_COLLECTION);
+}
 
 static void outliner_scene_collections_reorder(
         const Scene *scene, TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action)
@@ -1314,16 +1321,7 @@ static void outliner_scene_collections_reorder(
 	SceneCollection *sc_insert = insert_element->directdata;
 	SceneCollection *sc_handle = insert_handle->directdata;
 
-	if (sc_handle == sc_master) {
-		/* exception: Can't insert before/after master selection, has to be one of its childs */
-		if (action == TE_INSERT_BEFORE) {
-			sc_handle = sc_master->scene_collections.first;
-		}
-		else if (action == TE_INSERT_A

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list