[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