[Bf-blender-cvs] [30c92bf] soc-2016-layer_manager: Refactor how LayerTile is bound to LayerTree/LayerTreeItem

Julian Eisel noreply at git.blender.org
Sat May 28 02:30:39 CEST 2016


Commit: 30c92bf2767c8907a477e4838a5f27e9511a76d4
Author: Julian Eisel
Date:   Sat May 28 02:13:25 2016 +0200
Branches: soc-2016-layer_manager
https://developer.blender.org/rB30c92bf2767c8907a477e4838a5f27e9511a76d4

Refactor how LayerTile is bound to LayerTree/LayerTreeItem

Main benefit of this commit is that layer group relations and layer order are stored in LayerTree now (blendkernel struct), not in structs of the layer manager editor.

Two things I'm still not happy with:
* LayerTreeItem (blenkernel struct) now stores the LayerTile (layer manager editor struct) as void pointer. We need this to access the LayerTile from the LayerTreeItem, without expensive lookups. This could be solved by storing a hash table of LayerTiles though.
* Added BKE_layertree_iterate which is a handy util, but we need it pretty often so we also need to add lots of structs for custom data storage. For order/group independent iterations we could use the hashtable mentioned above and iterate over it.

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

M	source/blender/blenkernel/BKE_layer.h
M	source/blender/blenkernel/intern/layer.c
M	source/blender/editors/space_layers/layers_draw.c
M	source/blender/editors/space_layers/layers_intern.h
M	source/blender/editors/space_layers/layers_ops.c
M	source/blender/editors/space_layers/layers_util.c
M	source/blender/editors/space_layers/space_layers.c
M	source/blender/makesdna/DNA_space_types.h

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

diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
index cff3933..eae34f7 100644
--- a/source/blender/blenkernel/BKE_layer.h
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -31,15 +31,15 @@
 #define __BKE_LAYER_H__
 
 struct bContext;
+struct LayerTreeItem;
 struct uiLayout;
 
-typedef struct LayerTree LayerTree;
-typedef struct LayerTreeItem LayerTreeItem;
-
 
 /* -------------------------------------------------------------------- */
 /* Layer Tree */
 
+typedef bool (*LayerTreeIterFunc)(struct LayerTreeItem *, void *);
+
 /**
  * LayerTree.type
  * Defines the type used for the layer tree.
@@ -56,7 +56,9 @@ typedef enum eLayerTree_Type {
 typedef struct LayerTree {
 	eLayerTree_Type type;
 
-	ListBase items; /* LayerTreeItem - TODO check if worth using array instead */
+	/* LayerTreeItem - Only items of the first level in the hierarchy, these may have children then.
+	 * TODO check if worth using array instead */
+	ListBase items;
 
 	/* filtering */
 	short filterflag;
@@ -67,6 +69,8 @@ typedef struct LayerTree {
 struct LayerTree *BKE_layertree_new(const eLayerTree_Type type);
 void BKE_layertree_delete(struct LayerTree *ltree);
 
+bool BKE_layertree_iterate(const LayerTree *ltree, LayerTreeIterFunc foreach, void *customdata);
+
 /* -------------------------------------------------------------------- */
 /* Layer Tree Item */
 
@@ -93,6 +97,7 @@ typedef struct LayerTreeItem {
 
 	LayerTree *tree; /* pointer back to layer tree - TODO check if needed */
 	struct LayerTreeItem *parent; /* the group this item belongs to */
+	ListBase childs;
 
 	/* item is grayed out if this check fails */
 	LayerItemPollFunc poll;
@@ -100,13 +105,16 @@ typedef struct LayerTreeItem {
 	LayerItemDrawFunc draw;
 	/* drawing of the expanded layer settings (gear wheel icon) */
 	LayerItemDrawSettingsFunc draw_settings;
+
+	/* Ugly, but we use this to store LayerTile data for drawing in layer manager editor. */
+	void *drawdata;
 } LayerTreeItem;
 
 struct LayerTreeItem *BKE_layeritem_add(
-        struct LayerTree *tree, struct LayerTreeItem *parent,
+        LayerTree *tree, LayerTreeItem *parent,
         const eLayerTreeItem_Type type, const char *name,
         const LayerItemPollFunc poll, LayerItemDrawFunc draw, LayerItemDrawSettingsFunc draw_settings);
-void BKE_layeritem_remove(struct LayerTree *tree, struct LayerTreeItem *litem);
+void BKE_layeritem_remove(LayerTreeItem *litem, const bool remove_children);
 
 void BKE_layeritem_group_assign(LayerTreeItem *group, LayerTreeItem *item);
 
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index eaa9372..c7c8c8c 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -61,13 +61,42 @@ void BKE_layertree_delete(LayerTree *ltree)
 {
 	for (LayerTreeItem *litem = ltree->items.first, *next_litem; litem; litem = next_litem) {
 		next_litem = litem->next;
-		BKE_layeritem_remove(ltree, litem);
+		BKE_layeritem_remove(litem, true);
 	}
 	BLI_assert(BLI_listbase_is_empty(&ltree->items));
 
 	MEM_freeN(ltree);
 }
 
+/**
+ * Iterate over \a itemlist and all of its children, wrapped by #BKE_layertree_iterate.
+ * \note Recursive
+ */
+static bool layertree_iterate_list(const ListBase *itemlist, LayerTreeIterFunc foreach, void *customdata)
+{
+	for (LayerTreeItem *litem = itemlist->first, *litem_next; litem; litem = litem_next) {
+		litem_next = litem->next; /* in case list order is changed in callback */
+		if (foreach(litem, customdata) == false || /* execute callback for current item */
+		    layertree_iterate_list(&litem->childs, foreach, customdata) == false) /* iterate over childs */
+		{
+			return false;
+		}
+	}
+	return true;
+}
+
+/**
+ * Iterate over all items (including children) in the layer tree, executing \a foreach callback for each element.
+ * (Pre-order traversal)
+ *
+ * \param foreach: Callback that can return false to stop the iteration.
+ * \return if the iteration has been stopped because of a callback returning false.
+ */
+bool BKE_layertree_iterate(const LayerTree *ltree, LayerTreeIterFunc foreach, void *customdata)
+{
+	return layertree_iterate_list(&ltree->items, foreach, customdata);
+}
+
 /** \} */ /* Layer Tree */
 
 
@@ -94,12 +123,8 @@ LayerTreeItem *BKE_layeritem_add(
 {
 	LayerTreeItem *litem = MEM_callocN(sizeof(LayerTreeItem), __func__);
 
-	BLI_assert(!parent || ELEM(parent->type, LAYER_ITEMTYPE_GROUP));
-	BLI_assert(!parent || parent->tree == tree);
-
 	litem->type = type;
 	litem->height = LAYERITEM_DEFAULT_HEIGHT;
-	litem->parent = parent;
 	litem->tree = tree;
 	BLI_strncpy(litem->name, name, sizeof(litem->name));
 
@@ -108,17 +133,41 @@ LayerTreeItem *BKE_layeritem_add(
 	litem->draw = draw;
 	litem->draw_settings = draw_settings;
 
-	BLI_addhead(&tree->items, litem);
+	if (parent) {
+		BLI_assert(ELEM(parent->type, LAYER_ITEMTYPE_GROUP));
+		BLI_assert(parent->tree == tree);
+
+		litem->parent = parent;
+		/* add to child list of parent, not to item list of tree */
+		BLI_addtail(&parent->childs, litem);
+	}
+	else {
+		BLI_addhead(&tree->items, litem);
+	}
 
 	return litem;
 }
 
 /**
- * Free and unlink \a litem from \a tree.
+ * Free and unlink \a litem from the list it's stored in.
+ *
+ * \param remove_children: Free and unlink all children (and their children, etc) of \a litem as well.
+ * \note Recursive
  */
-void BKE_layeritem_remove(LayerTree *tree, LayerTreeItem *litem)
+void BKE_layeritem_remove(LayerTreeItem *litem, const bool remove_children)
 {
-	BLI_remlink(&tree->items, litem);
+	BLI_remlink(litem->parent ? &litem->parent->childs : &litem->tree->items, litem);
+	if (litem->drawdata) {
+		MEM_freeN(litem->drawdata);
+	}
+
+	if (remove_children) {
+		for (LayerTreeItem *child = litem->childs.first, *child_next; child; child = child_next) {
+			child_next = child->next;
+			BKE_layeritem_remove(child, true);
+		}
+	}
+
 	MEM_freeN(litem);
 }
 
@@ -127,8 +176,14 @@ void BKE_layeritem_remove(LayerTree *tree, LayerTreeItem *litem)
  */
 void BKE_layeritem_group_assign(LayerTreeItem *group, LayerTreeItem *item)
 {
+	ListBase *oldlist = item->parent ? &item->parent->childs : &item->tree->items;
+
 	BLI_assert(group->type == LAYER_ITEMTYPE_GROUP);
+	BLI_assert(BLI_findindex(oldlist, item) != -1);
+
 	item->parent = group;
+	BLI_remlink(oldlist, item);
+	BLI_addtail(&group->childs, item);
 }
 
 /** \} */ /* Layer Tree Item */
diff --git a/source/blender/editors/space_layers/layers_draw.c b/source/blender/editors/space_layers/layers_draw.c
index 0388fb7..f48bf0b 100644
--- a/source/blender/editors/space_layers/layers_draw.c
+++ b/source/blender/editors/space_layers/layers_draw.c
@@ -47,9 +47,9 @@
 #define LAYERITEM_INDENT_SIZE UI_DPI_ICON_SIZE
 
 
-static int layer_tile_indent_level_get(const LayerTile *tile)
+static int layer_tile_indent_level_get(const LayerTreeItem *litem)
 {
-	LayerTreeItem *parent = tile->litem->parent;
+	LayerTreeItem *parent = litem->parent;
 	int indent_level = 0;
 
 	while (parent) {
@@ -60,18 +60,28 @@ static int layer_tile_indent_level_get(const LayerTile *tile)
 	return indent_level;
 }
 
-static void layer_tile_draw(
-        LayerTile *tile, const bContext *C, ARegion *ar,
-        uiBlock *block, uiStyle *style,
-        const float ofs_y)
+typedef struct TileDrawInfo {
+	const bContext *C;
+	ARegion *ar;
+	uiBlock *block;
+	uiStyle *style;
+
+	float size_y;
+} TileDrawInfo;
+
+static bool layer_tile_draw_cb(LayerTreeItem *litem, void *userdata)
 {
-	View2D *v2d = &ar->v2d;
-	LayerTreeItem *litem = tile->litem;
+	TileDrawInfo *drawinfo = userdata;
+	View2D *v2d = &drawinfo->ar->v2d;
+	LayerTile *tile = litem->drawdata;
 	const float padx = 4.0f * UI_DPI_FAC;
-	const float ofs_x = layer_tile_indent_level_get(tile) * LAYERITEM_INDENT_SIZE;
-	rctf rect = {padx + ofs_x, ar->winx - padx, -v2d->cur.ymin - ofs_y - litem->height};
+
+	const float ofs_x = layer_tile_indent_level_get(litem) * LAYERITEM_INDENT_SIZE;
+	const float ofs_y = drawinfo->size_y;
+	rctf rect = {padx + ofs_x, drawinfo->ar->winx - padx, -v2d->cur.ymin - ofs_y - litem->height};
 	rect.ymax = rect.ymin + litem->height;
 
+
 	/* draw selection */
 	if (tile->flag & LAYERTILE_SELECTED) {
 		UI_draw_roundbox_corner_set(UI_CNR_ALL);
@@ -80,9 +90,10 @@ static void layer_tile_draw(
 	}
 	/* draw item itself */
 	if (litem->draw) {
+		uiBlock *block = drawinfo->block;
 		uiLayout *layout = UI_block_layout(
 		                       block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER,
-		                       -v2d->cur.xmin + ofs_x, -v2d->cur.ymin - ofs_y, litem->height, 0, 0, style);
+		                       -v2d->cur.xmin + ofs_x, -v2d->cur.ymin - ofs_y, litem->height, 0, 0, drawinfo->style);
 		if (tile->flag & LAYERTILE_RENAME) {
 			uiBut *but = uiDefBut(
 			        block, UI_BTYPE_TEXT, 1, "", rect.xmin, rect.ymin,
@@ -92,11 +103,11 @@ static void layer_tile_draw(
 			UI_but_flag_disable(but, UI_BUT_UNDO);
 
 			/* returns false if button got removed */
-			if (UI_but_active_only(C, ar, block, but) == false) {
+			if (UI_but_active_only(drawinfo->C, drawinfo->ar, block, but) == false) {
 				tile->flag &= ~LAYERTILE_RENAME;
 				/* Yuk! Sending notifier during draw. Need to
 				 * do that so item uses regular drawing again. */
-				WM_event_add_notifier(C, NC_SPACE | ND_SPACE_LAYERS, NULL);
+				WM_event_add_notifier(drawinfo->C, NC_SPACE | ND_SPACE_LAYERS, NULL);
 			}
 		}
 		else {
@@ -105,25 +116,25 @@ static void layer_tile_draw(
 		uiItemL(layout, "", 0); /* XXX without this editing last item causes crashes */
 		UI_block_layout_resolve(block, NULL, NULL);
 	}
+	drawinfo->size_y += litem->height;
+
+	return true;
 }
 
 void layers_tiles_draw(const bContext *C, ARegion *ar)
 {
 	SpaceLayers *slayer = CTX_wm_space_layers(C);
-	uiStyle *style = UI_style_get_dpi();
-	float size_y = 0.0f;
 
 	uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
-	/* draw items */
-	for (LayerTile *tile = slayer->layer_tiles.first; tile; tile = tile->next) {
-		layer_tile_draw(tile, C, ar, block, style, size_y);
-		size_y += tile->litem->height;
-	}
+	TileDrawInfo drawinfo = {C, ar, block, UI_style_get_dpi()};
+
+	BKE_layertree_iterate(slayer->act_tree, layer_t

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list