mirror of
https://github.com/blender/blender
synced 2026-09-29 04:37:17 +03:00
Grease Pencil: Python: Add LayerGroup.children and root_nodes API
Adaptation of !138738 by @SietseB. Adds two new python API endpoints: * `GreasePencil.root_nodes`: Collection of all the top most nodes in the layer tree. * `LayerGroup.children`: Collection of all the top most children of the layer group. Both of these iterate the nodes in stack order, meaning bottom to top. This matches the internal representation of the Grease Pencil data. Pull Request: https://projects.blender.org/blender/blender/pulls/152913
This commit is contained in:
parent
89de863679
commit
37d0902549
2 changed files with 194 additions and 4 deletions
|
|
@ -13,9 +13,11 @@
|
|||
#include "DNA_grease_pencil_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_define.hh"
|
||||
#include "RNA_enum_types.hh"
|
||||
|
||||
#include "RNA_types.hh"
|
||||
#include "rna_internal.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
|
|
@ -663,6 +665,49 @@ static void rna_GreasePencilLayerGroup_is_expanded_set(PointerRNA *ptr, const bo
|
|||
group->wrap().set_expanded(value);
|
||||
}
|
||||
|
||||
static void rna_GreasePencilLayerGroup_children_begin(CollectionPropertyIterator *iter,
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
LayerGroup *layer_group = static_cast<LayerGroup *>(ptr->data);
|
||||
ListBaseT<GreasePencilLayerTreeNode> *children = &layer_group->children;
|
||||
|
||||
rna_iterator_listbase_begin(iter, ptr, children, nullptr);
|
||||
}
|
||||
|
||||
static void rna_GreasePencilLayerGroup_children_next(CollectionPropertyIterator *iter)
|
||||
{
|
||||
rna_iterator_listbase_next(iter);
|
||||
}
|
||||
|
||||
static PointerRNA rna_GreasePencilLayerGroup_children_get(CollectionPropertyIterator *iter)
|
||||
{
|
||||
return RNA_pointer_create_discrete(
|
||||
iter->parent.owner_id, RNA_GreasePencilTreeNode, rna_iterator_listbase_get(iter));
|
||||
}
|
||||
|
||||
static int rna_GreasePencilLayerGroup_children_length(PointerRNA *ptr)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
TreeNode *node = static_cast<TreeNode *>(ptr->data);
|
||||
|
||||
BLI_assert(node->is_group());
|
||||
|
||||
return node->as_group().num_direct_nodes();
|
||||
}
|
||||
|
||||
static bool rna_GreasePencilLayerGroup_children_lookup_int(PointerRNA *ptr,
|
||||
int index,
|
||||
PointerRNA *r_ptr)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
LayerGroup *layer_group = static_cast<LayerGroup *>(ptr->data);
|
||||
ListBaseT<GreasePencilLayerTreeNode> *lb = &layer_group->children;
|
||||
|
||||
*r_ptr = rna_listbase_lookup_int(ptr, RNA_GreasePencilTreeNode, lb, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void rna_iterator_grease_pencil_layer_groups_begin(CollectionPropertyIterator *iter,
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
|
|
@ -701,6 +746,36 @@ static int rna_iterator_grease_pencil_layer_groups_length(PointerRNA *ptr)
|
|||
return grease_pencil->layer_groups().size();
|
||||
}
|
||||
|
||||
static void rna_iterator_grease_pencil_root_nodes_begin(CollectionPropertyIterator *iter,
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
GreasePencil *grease_pencil = rna_grease_pencil(ptr);
|
||||
|
||||
LayerGroup &root_group = grease_pencil->root_group();
|
||||
ListBaseT<GreasePencilLayerTreeNode> *children = &root_group.children;
|
||||
|
||||
rna_iterator_listbase_begin(iter, ptr, children, nullptr);
|
||||
}
|
||||
|
||||
static void rna_iterator_grease_pencil_root_nodes_next(CollectionPropertyIterator *iter)
|
||||
{
|
||||
rna_iterator_listbase_next(iter);
|
||||
}
|
||||
|
||||
static PointerRNA rna_iterator_grease_pencil_root_nodes_get(CollectionPropertyIterator *iter)
|
||||
{
|
||||
return RNA_pointer_create_discrete(
|
||||
iter->parent.owner_id, RNA_GreasePencilTreeNode, rna_iterator_listbase_get(iter));
|
||||
}
|
||||
|
||||
static int rna_iterator_grease_pencil_root_nodes_length(PointerRNA *ptr)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
GreasePencil *grease_pencil = rna_grease_pencil(ptr);
|
||||
return grease_pencil->root_group().num_direct_nodes();
|
||||
}
|
||||
|
||||
static int rna_group_color_tag_get(PointerRNA *ptr)
|
||||
{
|
||||
using namespace bke::greasepencil;
|
||||
|
|
@ -1262,6 +1337,23 @@ static void rna_def_grease_pencil_layer_group(BlenderRNA *brna)
|
|||
prop = RNA_def_property(srna, "color_tag", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_funcs(prop, "rna_group_color_tag_get", "rna_group_color_tag_set", nullptr);
|
||||
RNA_def_property_enum_items(prop, enum_layergroup_color_items);
|
||||
|
||||
/* Children */
|
||||
prop = RNA_def_property(srna, "children", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "GreasePencilTreeNode");
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_GreasePencilLayerGroup_children_begin",
|
||||
"rna_GreasePencilLayerGroup_children_next",
|
||||
nullptr,
|
||||
"rna_GreasePencilLayerGroup_children_get",
|
||||
"rna_GreasePencilLayerGroup_children_length",
|
||||
"rna_GreasePencilLayerGroup_children_lookup_int",
|
||||
nullptr,
|
||||
nullptr);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Children",
|
||||
"The direct children of this layer group. Ordered by stack order, "
|
||||
"meaning the first child is the bottom most child in the layer tree.");
|
||||
}
|
||||
|
||||
static void rna_def_grease_pencil_layer_groups(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
|
|
@ -1490,6 +1582,23 @@ static void rna_def_grease_pencil_data(BlenderRNA *brna)
|
|||
RNA_def_property_ui_text(prop, "Layer Groups", "Grease Pencil layer groups");
|
||||
rna_def_grease_pencil_layer_groups(brna, prop);
|
||||
|
||||
/* Root nodes. */
|
||||
prop = RNA_def_property(srna, "root_nodes", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "GreasePencilTreeNode");
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_iterator_grease_pencil_root_nodes_begin",
|
||||
"rna_iterator_grease_pencil_root_nodes_next",
|
||||
nullptr,
|
||||
"rna_iterator_grease_pencil_root_nodes_get",
|
||||
"rna_iterator_grease_pencil_root_nodes_length",
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Root Nodes",
|
||||
"The root nodes of the layer tree. Ordered by stack order, meaning the "
|
||||
"first node is the bottom most node in the layer tree.");
|
||||
|
||||
prop = RNA_def_property(srna, "use_autolock_layers", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GREASE_PENCIL_AUTOLOCK_LAYERS);
|
||||
RNA_def_property_ui_text(
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import unittest
|
|||
# -----------------------------------------------------------------------------
|
||||
# Tests
|
||||
|
||||
|
||||
class TestGreasePencil(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.gp = bpy.data.grease_pencils.new("test_grease_pencil")
|
||||
|
|
@ -62,14 +63,14 @@ class TestGreasePencilLayers(unittest.TestCase):
|
|||
|
||||
def test_grease_pencil_layers_move_down(self):
|
||||
# Move the top most layer down
|
||||
self.gp.layers.move(self.gp.layers[-1], 'DOWN')
|
||||
self.gp.layers.move(self.gp.layers[-1], "DOWN")
|
||||
self.assertEqual(self.gp.layers[0].name, "test_layer01")
|
||||
self.assertEqual(self.gp.layers[1].name, "test_layer03")
|
||||
self.assertEqual(self.gp.layers[2].name, "test_layer02")
|
||||
|
||||
def test_grease_pencil_layers_move_up(self):
|
||||
# Move the bottom most layer up
|
||||
self.gp.layers.move(self.gp.layers[0], 'UP')
|
||||
self.gp.layers.move(self.gp.layers[0], "UP")
|
||||
self.assertEqual(self.gp.layers[0].name, "test_layer02")
|
||||
self.assertEqual(self.gp.layers[1].name, "test_layer01")
|
||||
self.assertEqual(self.gp.layers[2].name, "test_layer03")
|
||||
|
|
@ -299,7 +300,87 @@ class TestGreasePencilDrawing(unittest.TestCase):
|
|||
self.assertEqual(len(strokes[0].points), 5)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
class TestGreasePencilRootNodes(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.gp = bpy.data.grease_pencils.new("test_gp")
|
||||
|
||||
self.layer_a = self.gp.layers.new("LayerA")
|
||||
self.group_g = self.gp.layer_groups.new("GroupG")
|
||||
|
||||
self.layer_b = self.gp.layers.new("LayerB")
|
||||
self.layer_c = self.gp.layers.new("LayerC")
|
||||
|
||||
self.gp.layers.move_to_layer_group(self.layer_b, self.group_g)
|
||||
self.gp.layers.move_to_layer_group(self.layer_c, self.group_g)
|
||||
|
||||
self.layer_d = self.gp.layers.new("LayerD")
|
||||
|
||||
def tearDown(self):
|
||||
bpy.data.grease_pencils.remove(self.gp)
|
||||
|
||||
def test_root_nodes_len_and_order(self):
|
||||
nodes = self.gp.root_nodes
|
||||
|
||||
self.assertEqual(len(nodes), 3)
|
||||
self.assertEqual(nodes[0].name, "LayerA")
|
||||
self.assertEqual(nodes[1].name, "GroupG")
|
||||
self.assertEqual(nodes[2].name, "LayerD")
|
||||
|
||||
def test_root_nodes_types(self):
|
||||
nodes = self.gp.root_nodes
|
||||
|
||||
self.assertIsInstance(nodes[0], bpy.types.GreasePencilLayer)
|
||||
self.assertIsInstance(nodes[1], bpy.types.GreasePencilLayerGroup)
|
||||
self.assertIsInstance(nodes[2], bpy.types.GreasePencilLayer)
|
||||
|
||||
|
||||
class TestGreasePencilLayerGroupChildren(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.gp = bpy.data.grease_pencils.new("test_gp")
|
||||
|
||||
self.group = self.gp.layer_groups.new("Group")
|
||||
|
||||
self.layer1 = self.gp.layers.new("Layer1")
|
||||
self.layer2 = self.gp.layers.new("Layer2")
|
||||
|
||||
self.gp.layers.move_to_layer_group(self.layer1, self.group)
|
||||
self.gp.layers.move_to_layer_group(self.layer2, self.group)
|
||||
|
||||
self.subgroup = self.gp.layer_groups.new("SubGroup")
|
||||
self.gp.layer_groups.move_to_layer_group(self.subgroup, self.group)
|
||||
|
||||
self.sublayer = self.gp.layers.new("SubLayer")
|
||||
self.gp.layers.move_to_layer_group(self.sublayer, self.subgroup)
|
||||
|
||||
def tearDown(self):
|
||||
bpy.data.grease_pencils.remove(self.gp)
|
||||
|
||||
def test_children_basic(self):
|
||||
children = self.group.children
|
||||
|
||||
self.assertEqual(len(children), 3)
|
||||
self.assertEqual(children[0].name, "Layer1")
|
||||
self.assertEqual(children[1].name, "Layer2")
|
||||
self.assertEqual(children[2].name, "SubGroup")
|
||||
|
||||
def test_children_not_recursive(self):
|
||||
children = self.group.children
|
||||
names = {child.name for child in children}
|
||||
|
||||
self.assertNotIn("SubLayer", names)
|
||||
|
||||
def test_children_iteration(self):
|
||||
names = []
|
||||
for node in self.group.children:
|
||||
names.append(node.name)
|
||||
|
||||
self.assertEqual(names, ["Layer1", "Layer2", "SubGroup"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
|
||||
|
||||
sys.argv = [__file__] + (
|
||||
sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
|
||||
)
|
||||
unittest.main()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue