[Bf-blender-cvs] [cd374ba] soc-2016-layer_manager: Get layer drag & drop with layer groups to work

Julian Eisel noreply at git.blender.org
Sun Jul 3 22:38:47 CEST 2016


Commit: cd374baef3963f8cd5f4610a3069a45f798c52ad
Author: Julian Eisel
Date:   Sun Jul 3 22:36:49 2016 +0200
Branches: soc-2016-layer_manager
https://developer.blender.org/rBcd374baef3963f8cd5f4610a3069a45f798c52ad

Get layer drag & drop with layer groups to work

Still get some occasional crashes but have to investigate at another time.

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

M	source/blender/blenkernel/BKE_layer.h
M	source/blender/blenkernel/intern/layer.c
M	source/blender/editors/space_layers/layers_ops.c
M	source/blender/makesdna/DNA_scene_types.h

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

diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
index a1d362d..8564490 100644
--- a/source/blender/blenkernel/BKE_layer.h
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -110,7 +110,7 @@ void BKE_layeritem_register(
         const eLayerTreeItem_Type type, const char *name);
 void BKE_layeritem_remove(LayerTreeItem *litem, const bool remove_children);
 
-void BKE_layeritem_move(LayerTreeItem *litem, const int newidx);
+void BKE_layeritem_move(LayerTreeItem *litem, const int newidx, const bool with_childs);
 void BKE_layeritem_group_assign(LayerTreeItem *group, LayerTreeItem *item);
 
 bool BKE_layeritem_iterate_childs(
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index 5cc8e49..8006432 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -32,12 +32,14 @@
  */
 
 #include <stdlib.h>
+#include <string.h>
 
 #include "BKE_context.h"
 #include "BKE_idprop.h"
 #include "BKE_layer.h" /* own include */
 #include "BKE_object.h"
 
+#include "BLI_alloca.h"
 #include "BLI_listbase.h"
 #include "BLI_string.h"
 
@@ -275,41 +277,76 @@ void BKE_layeritem_remove(LayerTreeItem *litem, const bool remove_children)
 	ltree->items_all = MEM_reallocN(ltree->items_all, sizeof(*ltree->items_all) * ltree->tot_items);
 }
 
-static bool layeritem_move_array(LayerTreeItem *litem, const int newidx)
+/* XXX newidx isn't always the index the items are inserted at. */
+static void layeritem_move_array(LayerTreeItem *litem, const int newidx, const int num_items)
 {
-	const bool is_higher = litem->index < newidx;
+	LayerTree *ltree = litem->tree;
+	const int oldidx = litem->index;
+	const bool is_higher = oldidx < newidx;
+	const int insertidx = is_higher ? newidx - num_items + 1 : newidx;
 
-	BLI_assert(litem->tree->tot_items > newidx);
+	BLI_assert(num_items > 0 && ltree->tot_items > (insertidx + num_items - 1));
 	/* Already where we want to move it to. */
-	if (litem->index == newidx)
-		return false;
+	if (oldidx == newidx)
+		return;
+
+	/* Save items to be moved */
+	LayerTreeItem **movechunk = &litem;
+	if (num_items > 1) {
+		movechunk = BLI_array_alloca(movechunk, num_items);
+//		memcpy(movechunk, ltree->items_all[oldidx], sizeof(*ltree->items_all) * num_items); XXX doesn't work
+		for (int i = 0; i < num_items; i++) {
+			movechunk[i] = ltree->items_all[oldidx + i];
+		}
+	}
+	BLI_assert(movechunk[0] == litem);
 
-	for (int i = is_higher ? litem->index + 1 : litem->index - 1;
-	     i < litem->tree->tot_items && i >= 0;
+	/* rearrange items to fill in gaps of items to be moved */
+	for (int i = is_higher ? oldidx + num_items : oldidx - 1;
+	     i < ltree->tot_items && i >= 0;
 	     is_higher ? i++ : i--)
 	{
-		const int iter_new_idx = i + (is_higher ? -1 : 1);
-		litem->tree->items_all[iter_new_idx] = litem->tree->items_all[i];
-		litem->tree->items_all[iter_new_idx]->index = iter_new_idx;
+		const int iter_new_idx = i + (is_higher ? -num_items : num_items);
+		ltree->items_all[iter_new_idx] = ltree->items_all[i];
+		ltree->items_all[iter_new_idx]->index = iter_new_idx;
 		if (i == newidx) {
-			litem->tree->items_all[i] = litem;
-			litem->index = i;
 			break;
 		}
 	}
+	/* move items to new position starting at newidx */
+	for (int i = 0; i < num_items; i++) {
+		ltree->items_all[insertidx + i] = movechunk[i];
+		ltree->items_all[insertidx + i]->index = insertidx + i;
+	}
+	/* TODO can check using gtest */
+	BLI_assert(ltree->items_all[insertidx] == litem && litem->index == insertidx);
+}
 
-	return true;
+/**
+ * Helper to count all children (and grand-children etc.) of a layer item.
+ * \note Recursive.
+ */
+static unsigned int layeritem_childs_count(ListBase *childs)
+{
+	int i = 0;
+	for (LayerTreeItem *child = childs->first; child; child = child->next, i++) {
+		if (!BLI_listbase_is_empty(&child->childs)) {
+			i += layeritem_childs_count(&child->childs);
+		}
+	}
+	return i;
 }
 
 /**
  * Move \a litem that's already in the layer tree to slot \a newidx.
  */
-void BKE_layeritem_move(LayerTreeItem *litem, const int newidx)
+void BKE_layeritem_move(LayerTreeItem *litem, const int newidx, const bool with_childs)
 {
-	/* move in array (return if failed) */
-	if (!layeritem_move_array(litem, newidx)) {
+	const int tot_childs = with_childs ? layeritem_childs_count(&litem->childs) : 0;
+
+	/* Already where we want to move it to. */
+	if (litem->index == newidx)
 		return;
-	}
 
 	/* move in listbase */
 	BLI_remlink(litem->parent ? &litem->parent->childs : &litem->tree->items, litem);
@@ -321,6 +358,9 @@ void BKE_layeritem_move(LayerTreeItem *litem, const int newidx)
 		LayerTreeItem *moved = litem->tree->items_all[newidx + 1];
 		BLI_insertlinkbefore(moved->parent ? &moved->parent->childs : &litem->tree->items, moved, litem);
 	}
+
+	/* move in array (return if failed) */
+	layeritem_move_array(litem, newidx, tot_childs + 1);
 }
 
 /**
@@ -339,7 +379,7 @@ void BKE_layeritem_group_assign(LayerTreeItem *group, LayerTreeItem *item)
 	BLI_addtail(&group->childs, item);
 	/* move in array */
 	/* XXX we could/should limit iterations to one in case multiple elmenents are assigned to a group */
-	layeritem_move_array(item, (item->prev ? item->prev->index : item->parent->index) + 1);
+	layeritem_move_array(item, (item->prev ? item->prev->index : item->parent->index) + 1, 1);
 }
 
 /**
diff --git a/source/blender/editors/space_layers/layers_ops.c b/source/blender/editors/space_layers/layers_ops.c
index 891d3e3..5e6cdcb 100644
--- a/source/blender/editors/space_layers/layers_ops.c
+++ b/source/blender/editors/space_layers/layers_ops.c
@@ -86,6 +86,7 @@ typedef struct {
 	int init_mval_y;
 	bool is_dragging;
 	bool is_cancel;
+	bool needs_reopen;
 
 	/* anim data */
 	wmTimer *anim_timer;
@@ -254,7 +255,8 @@ static int layer_group_add_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
 		LayerTile *tile = BLI_ghash_lookup(slayer->tiles, litem);
 		if (tile->flag & LAYERTILE_SELECTED) {
 			if (is_first) {
-				BKE_layeritem_move(new_group, litem->index);
+				BLI_assert(BLI_listbase_is_empty(&new_group->childs));
+				BKE_layeritem_move(new_group, litem->index, false);
 				is_first = false;
 			}
 			BKE_layeritem_group_assign(new_group, litem);
@@ -438,8 +440,11 @@ static int layer_drag_modal(bContext *C, wmOperator *op, const wmEvent *event)
 			case LAYERDRAG_CONFIRM:
 				ldrag->is_dragging = false;
 				layer_drag_drop_anim_start(C, ldrag, event);
+				if (ldrag->needs_reopen) {
+					ldrag->dragged.tile->flag &= ~LAYERTILE_CLOSED;
+				}
 				/* apply new position before animation is done */
-				BKE_layeritem_move(ldrag->dragged.tile->litem, ldrag->insert_idx);
+				BKE_layeritem_move(ldrag->dragged.tile->litem, ldrag->insert_idx, true);
 				if (ldrag->insert_idx != ldrag->dragged.tile->litem->index) {
 					WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL);
 				}
@@ -481,6 +486,10 @@ static int layer_drag_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 
 	op->customdata = ldrag;
 	tile->flag |= LAYERTILE_FLOATING;
+	if (!BLI_listbase_is_empty(&tile->litem->childs) && !(tile->flag & LAYERTILE_CLOSED)) {
+		tile->flag |= LAYERTILE_CLOSED;
+		ldrag->needs_reopen = true;
+	}
 
 	WM_event_add_modal_handler(C, op);
 
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 6248baf..9f0280f 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -89,7 +89,10 @@ typedef struct LayerTree {
 	/* LayerTreeItem - Only items of the first level in the hierarchy, these may have children then.
 	 * TODO check if worth using array instead */
 	ListBase items;
-	/* Array of all layer tree items, including all childs. Using array in hope it speeds up iterations. */
+	/* Array of all layer tree items, including all childs. Using array in hope it speeds up iterations.
+	 * NOTE: We currently assume that all children (or grand-children, etc) are placed after their parent, even though
+	 * it's quite easy to break it. It could be supported but might lower performance a bit (maybe uber-picky).
+	 * XXX Check if this can be made safer */
 	struct LayerTreeItem **items_all;
 } LayerTree;
 
@@ -105,7 +108,7 @@ typedef struct LayerTreeItem {
 	int index, pad; /* index of the item - stored to avoid loockups */
 	char name[64];  /* MAX_NAME */
 
-	struct LayerTree *tree; /* pointer back to layer tree - TODO check if needed */
+	LayerTree *tree; /* pointer back to layer tree - TODO check if needed */
 	struct LayerTreeItem *parent; /* the group this item belongs to */
 	ListBase childs; /* LayerTreeItem */




More information about the Bf-blender-cvs mailing list