[Bf-blender-cvs] [8e303aae255] blender2.8: Support drag & drop of collections across multiple hierarchy levels

Julian Eisel noreply at git.blender.org
Fri Mar 10 15:24:59 CET 2017


Commit: 8e303aae255be2ef45d5818af046de7c22312aa4
Author: Julian Eisel
Date:   Fri Mar 10 15:03:06 2017 +0100
Branches: blender2.8
https://developer.blender.org/rB8e303aae255be2ef45d5818af046de7c22312aa4

Support drag & drop of collections across multiple hierarchy levels

Two issues are remaining, they'll be fixed separately:
* Graphical feedback when dragging within the master collection is wrong
* There's some bug where collections swap places instead, Dalai will investigate

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

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 0ba60b21aa7..0b119b5d247 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -1520,34 +1520,14 @@ static void outliner_draw_tree_element(
 	}
 }
 
-/**
- * Count how many visible childs (and open grandchilds, great-grandchilds, ...) \a te has.
- */
-static int outliner_count_visible_childs(const SpaceOops *soops, const TreeElement *te)
-{
-	TreeStoreElem *tselem = TREESTORE(te);
-	int current_count = 0;
-
-	if (TSELEM_OPEN(tselem, soops)) {
-		for (TreeElement *te_child = te->subtree.first; te_child; te_child = te_child->next) {
-			current_count += outliner_count_visible_childs(soops, te_child);
-			current_count++;
-		}
-	}
-
-	return current_count;
-}
-
-static void outliner_draw_tree_element_floating(const SpaceOops *soops, const ARegion *ar,
-                                                const TreeElement *te_floating)
+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 ListBase *lb_parent = te_floating->parent ? &te_floating->parent->subtree : &soops->tree;
-	const TreeElement *te_insert_fallback = te_insert ? te_insert : lb_parent->first;
 	const int line_width = 2;
 
 	unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT);
-	int coord_y = (te_insert ? te_insert->ys : (te_insert_fallback->ys + UI_UNIT_Y)) - (int)(line_width * 0.5f);
+	int coord_y = te_insert->ys;
 	unsigned char col[4];
 
 	if (te_insert == te_floating) {
@@ -1555,15 +1535,14 @@ static void outliner_draw_tree_element_floating(const SpaceOops *soops, const AR
 		return;
 	}
 
-	if (te_insert) {
-		coord_y -= UI_UNIT_Y * outliner_count_visible_childs(soops, te_insert);
-	}
-
 	UI_GetThemeColorShade4ubv(TH_BACK, -40, col);
 	immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
 	glEnable(GL_BLEND);
 
-	if (!te_insert || (te_floating->drag_data->insert_type == TE_INSERT_AFTER)) {
+	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;
+		}
 		immUniformColor4ubv(col);
 		glLineWidth(line_width);
 
@@ -1793,7 +1772,7 @@ static void outliner_draw_tree(
 		                           startx, &starty, te_edit, &te_floating);
 	}
 	if (te_floating) {
-		outliner_draw_tree_element_floating(soops, ar, te_floating);
+		outliner_draw_tree_element_floating(ar, te_floating);
 	}
 
 	if (has_restrict_icons) {
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index 4cee0e44fca..cad34c96db4 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -50,7 +50,7 @@ struct wmKeyConfig;
 
 
 typedef enum TreeElementInsertType {
-	/* no INSERT_BEFORE needed for now */
+	TE_INSERT_BEFORE,
 	TE_INSERT_AFTER,
 	TE_INSERT_INTO,
 } TreeElementInsertType;
@@ -91,7 +91,7 @@ typedef struct TreeElement {
 
 	struct {
 		TreeElementInsertType insert_type;
-		/* the element after which we may insert the dragged one (NULL to insert at top) */
+		/* the element before/after/into which we may insert the dragged one (NULL to insert at top) */
 		struct TreeElement *insert_handle;
 	} *drag_data;
 } TreeElement;
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index 3db0b6ffa08..6fc088e0f48 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -52,11 +52,6 @@ enum {
 	OUTLINER_ITEM_DRAG_CONFIRM,
 };
 
-typedef struct OutlinerItemDrag {
-	TreeElement *dragged_te;
-	int init_mouse_xy[2];
-} OutlinerItemDrag;
-
 static int outliner_item_drag_drop_poll(bContext *C)
 {
 	SpaceOops *soops = CTX_wm_space_outliner(C);
@@ -67,70 +62,69 @@ static int outliner_item_drag_drop_poll(bContext *C)
 
 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 OutlinerItemDrag *outliner_item_drag_data_create(TreeElement *dragged_te, const int mouse_xy[2])
-{
-	OutlinerItemDrag *drag_data = MEM_mallocN(sizeof(*drag_data), __func__);
-
-	drag_data->dragged_te = dragged_te;
-	copy_v2_v2_int(drag_data->init_mouse_xy, mouse_xy);
-
-	return drag_data;
-}
-
-static void outliner_item_drag_end(OutlinerItemDrag *op_drag_data)
+static void outliner_item_drag_end(TreeElement *dragged_te)
 {
-	MEM_SAFE_FREE(op_drag_data->dragged_te->drag_data);
-	MEM_freeN(op_drag_data);
+	MEM_SAFE_FREE(dragged_te->drag_data);
 }
 
-static void outliner_item_drag_handle(ARegion *ar, const wmEvent *event, OutlinerItemDrag *op_drag_data)
+static void outliner_item_drag_handle(
+        SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged)
 {
-	TreeElement *dragged_te = op_drag_data->dragged_te;
-	const int delta_mouse_y = event->y - op_drag_data->init_mouse_xy[1];
-	const int cmp_coord = (int)UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]);
-	const float margin = UI_UNIT_Y * (1.0f / 3);
-
-	/* by default we don't change the item position */
-	dragged_te->drag_data->insert_handle = dragged_te;
-
-	if (delta_mouse_y > 0) {
-		for (TreeElement *te = dragged_te->prev; te && (cmp_coord >= (te->ys + margin)); te = te->prev) {
-			if (cmp_coord > (te->ys + (2 * margin))) {
-				dragged_te->drag_data->insert_type = TE_INSERT_AFTER;
-				/* will be NULL if we want to insert as first element */
-				dragged_te->drag_data->insert_handle = te->prev;
+	TreeStoreElem *tselem_dragged = TREESTORE(te_dragged);
+	TreeElement *insert_handle;
+	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_dragged->drag_data->insert_handle = NULL;
+	if (insert_handle) {
+		TreeStoreElem *tselem_handle = TREESTORE(insert_handle);
+		if (tselem_handle->type == tselem_dragged->type) {
+			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)) {
+				te_dragged->drag_data->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 {
-				dragged_te->drag_data->insert_type = TE_INSERT_INTO;
-				dragged_te->drag_data->insert_handle = te;
+				te_dragged->drag_data->insert_type = TE_INSERT_INTO;
 			}
 		}
 	}
 	else {
-		for (TreeElement *te = dragged_te->next; te && (cmp_coord <= (te->ys + UI_UNIT_Y - margin)); te = te->next) {
-			if (cmp_coord < (te->ys + margin)) {
-				dragged_te->drag_data->insert_type = TE_INSERT_AFTER;
-				dragged_te->drag_data->insert_handle = te;
-				BLI_assert(te->prev != NULL);
-			}
-			else {
-				dragged_te->drag_data->insert_type = TE_INSERT_INTO;
-				dragged_te->drag_data->insert_handle = te;
-			}
+		TreeElement *first = soops->tree.first;
+		TreeElement *last = soops->tree.last;
+
+		/* 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;
+		}
+		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;
+		}
+		else {
+			BLI_assert(0);
 		}
 	}
 }
 
-static bool outliner_item_drag_drop_apply(const Scene *scene, OutlinerItemDrag *op_drag_data)
+static bool outliner_item_drag_drop_apply(const Scene *scene, TreeElement *dragged_te)
 {
-	TreeElement *dragged_te = op_drag_data->dragged_te;
-	TreeElement *insert_after = dragged_te->drag_data->insert_handle;
+	TreeElement *insert_handle = dragged_te->drag_data->insert_handle;
 
-	if (insert_after == dragged_te) {
+	if (insert_handle == dragged_te) {
 		/* No need to do anything */
 		return false;
 	}
@@ -138,8 +132,8 @@ static bool outliner_item_drag_drop_apply(const Scene *scene, OutlinerItemDrag *
 	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_after || (insert_after->reinsert == dragged_te->reinsert)) {
-			dragged_te->reinsert(scene, dragged_te, insert_after, dragged_te->drag_data->insert_type);
+		if (!insert_handle || (insert_handle->reinsert == dragged_te->reinsert)) {
+			dragged_te->reinsert(scene, dragged_te, insert_handle, dragged_te->drag_data->insert_type);
 		}
 	}
 
@@ -150,7 +144,7 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv
 {
 	ARegion *ar = CTX_wm_region(C);
 	SpaceOops *soops = CTX_wm_space_outliner(C);
-	OutlinerItemDrag *op_drag_data = op->customdata;
+	TreeElement *te_dragged = op->customdata;
 	int retval = OPERATOR_RUNNING_MODAL;
 	bool redraw = false;
 	bool skip_rebuild = true;
@@ -158,7 +152,7 @@ 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), op_drag_data);
+				outliner_item_drag_drop_apply(CTX_data_scene(C), te_dragged);
 				skip_rebuild = false;
 				retval = OPERATOR_FINISHED;
 			}
@@ -169,11 +163,11 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv
 				BLI_assert(0);
 			}
 			WM_event_add_mousemove(C); /* update highlight */
-			outliner_item_drag_end(op_drag_data);
+			outliner_it

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list