Grease Pencil: Python: Add base class for layer and layer groups

This adds a base class for `GreasePencilLayer` and
`GreasePencilLayerGroup` called `GreasePencilTreeNode`.

This reflects how the data is structured in DNA. Properties
that are shared among layers and groups are part of the
tree nodes. Examples are `name`, `hide`, `select`, etc.

This should not be a breaking change. Addons are expected
to work as they were before.

With this change, layer groups now also have access to the
`channel_color` and `select` property.

Pull Request: https://projects.blender.org/blender/blender/pulls/134348
This commit is contained in:
Falk David
2025-02-10 17:56:19 +01:00
committed by Falk David
parent 22e5b774c6
commit 3ef2ee7c53

View File

@@ -309,23 +309,6 @@ static void rna_grease_pencil_active_mask_index_range(
*max = max_ii(0, BLI_listbase_count(&layer->masks) - 1);
}
static void rna_iterator_grease_pencil_layers_begin(CollectionPropertyIterator *iter,
PointerRNA *ptr)
{
using namespace blender::bke::greasepencil;
GreasePencil *grease_pencil = rna_grease_pencil(ptr);
blender::Span<Layer *> layers = grease_pencil->layers_for_write();
rna_iterator_array_begin(
iter, ptr, (void *)layers.data(), sizeof(Layer *), layers.size(), false, nullptr);
}
static int rna_iterator_grease_pencil_layers_length(PointerRNA *ptr)
{
GreasePencil *grease_pencil = rna_grease_pencil(ptr);
return grease_pencil->layers().size();
}
static void tree_node_name_get(blender::bke::greasepencil::TreeNode &node, char *dst)
{
if (!node.name().is_empty()) {
@@ -355,32 +338,75 @@ static std::optional<std::string> tree_node_name_path(blender::bke::greasepencil
return fmt::format("{}[\"{}\"]", prefix, name_esc.c_str());
}
static StructRNA *rna_GreasePencilTreeNode_refine(PointerRNA *ptr)
{
GreasePencilLayerTreeNode *node = static_cast<GreasePencilLayerTreeNode *>(ptr->data);
switch (node->type) {
case GP_LAYER_TREE_LEAF:
return &RNA_GreasePencilLayer;
case GP_LAYER_TREE_GROUP:
return &RNA_GreasePencilLayerGroup;
default:
BLI_assert_unreachable();
}
return nullptr;
}
static void rna_GreasePencilTreeNode_name_get(PointerRNA *ptr, char *value)
{
GreasePencilLayerTreeNode *node = static_cast<GreasePencilLayerTreeNode *>(ptr->data);
tree_node_name_get(node->wrap(), value);
}
static int rna_GreasePencilTreeNode_name_length(PointerRNA *ptr)
{
GreasePencilLayerTreeNode *node = static_cast<GreasePencilLayerTreeNode *>(ptr->data);
return tree_node_name_length(node->wrap());
}
static void rna_GreasePencilTreeNode_name_set(PointerRNA *ptr, const char *value)
{
GreasePencil *grease_pencil = rna_grease_pencil(ptr);
GreasePencilLayerTreeNode *node = static_cast<GreasePencilLayerTreeNode *>(ptr->data);
grease_pencil->rename_node(*G_MAIN, node->wrap(), value);
}
static PointerRNA rna_GreasePencilTreeNode_parent_layer_group_get(PointerRNA *ptr)
{
GreasePencil *grease_pencil = rna_grease_pencil(ptr);
GreasePencilLayerTreeNode *node = static_cast<GreasePencilLayerTreeNode *>(ptr->data);
/* Return 'None' when node is in the root group. This group is not meant to be seen. */
if (node->parent == nullptr || node->parent == grease_pencil->root_group_ptr) {
return PointerRNA_NULL;
}
return RNA_pointer_create_with_parent(
*ptr, &RNA_GreasePencilLayerGroup, static_cast<void *>(node->parent));
}
static void rna_iterator_grease_pencil_layers_begin(CollectionPropertyIterator *iter,
PointerRNA *ptr)
{
using namespace blender::bke::greasepencil;
GreasePencil *grease_pencil = rna_grease_pencil(ptr);
blender::Span<Layer *> layers = grease_pencil->layers_for_write();
rna_iterator_array_begin(
iter, ptr, (void *)layers.data(), sizeof(Layer *), layers.size(), false, nullptr);
}
static int rna_iterator_grease_pencil_layers_length(PointerRNA *ptr)
{
GreasePencil *grease_pencil = rna_grease_pencil(ptr);
return grease_pencil->layers().size();
}
static std::optional<std::string> rna_GreasePencilLayer_path(const PointerRNA *ptr)
{
GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(ptr->data);
return tree_node_name_path(layer->wrap().as_node(), "layers");
}
static void rna_GreasePencilLayer_name_get(PointerRNA *ptr, char *value)
{
GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(ptr->data);
tree_node_name_get(layer->wrap().as_node(), value);
}
static int rna_GreasePencilLayer_name_length(PointerRNA *ptr)
{
GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(ptr->data);
return tree_node_name_length(layer->wrap().as_node());
}
static void rna_GreasePencilLayer_name_set(PointerRNA *ptr, const char *value)
{
GreasePencil *grease_pencil = rna_grease_pencil(ptr);
GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(ptr->data);
grease_pencil->rename_node(*G_MAIN, layer->wrap().as_node(), value);
}
static int rna_GreasePencilLayer_pass_index_get(PointerRNA *ptr)
{
using namespace blender;
@@ -537,18 +563,6 @@ static void rna_GreasePencilLayer_matrix_parent_inverse_get(PointerRNA *ptr, flo
std::copy_n(layer.parent_inverse().base_ptr(), 16, values);
}
static PointerRNA rna_GreasePencilLayer_parent_layer_group_get(PointerRNA *ptr)
{
blender::bke::greasepencil::Layer &layer = static_cast<GreasePencilLayer *>(ptr->data)->wrap();
blender::bke::greasepencil::LayerGroup *layer_group = &layer.parent_group();
/* Return None when layer is in the root group. */
if (!layer_group->as_node().parent_group()) {
return PointerRNA_NULL;
}
return RNA_pointer_create_with_parent(
*ptr, &RNA_GreasePencilLayerGroup, static_cast<void *>(layer_group));
}
static PointerRNA rna_GreasePencil_active_layer_get(PointerRNA *ptr)
{
GreasePencil *grease_pencil = rna_grease_pencil(ptr);
@@ -610,26 +624,6 @@ static std::optional<std::string> rna_GreasePencilLayerGroup_path(const PointerR
return tree_node_name_path(group->wrap().as_node(), "layer_groups");
}
static void rna_GreasePencilLayerGroup_name_get(PointerRNA *ptr, char *value)
{
GreasePencilLayerTreeGroup *group = static_cast<GreasePencilLayerTreeGroup *>(ptr->data);
tree_node_name_get(group->wrap().as_node(), value);
}
static int rna_GreasePencilLayerGroup_name_length(PointerRNA *ptr)
{
GreasePencilLayerTreeGroup *group = static_cast<GreasePencilLayerTreeGroup *>(ptr->data);
return tree_node_name_length(group->wrap().as_node());
}
static void rna_GreasePencilLayerGroup_name_set(PointerRNA *ptr, const char *value)
{
GreasePencil *grease_pencil = rna_grease_pencil(ptr);
GreasePencilLayerTreeGroup *group = static_cast<GreasePencilLayerTreeGroup *>(ptr->data);
grease_pencil->rename_node(*G_MAIN, group->wrap().as_node(), value);
}
static void rna_GreasePencilLayerGroup_is_expanded_set(PointerRNA *ptr, const bool value)
{
GreasePencilLayerTreeGroup *group = static_cast<GreasePencilLayerTreeGroup *>(ptr->data);
@@ -866,6 +860,82 @@ static void rna_def_grease_pencil_layer_masks(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_property_ui_text(prop, "Active Layer Mask Index", "Active index in layer mask array");
}
static void rna_def_grease_pencil_tree_node(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "GreasePencilTreeNode", nullptr);
RNA_def_struct_ui_text(
srna, "Tree Node", "Grease Pencil node in the layer tree. Either a layer or a group");
RNA_def_struct_sdna(srna, "GreasePencilLayerTreeNode");
RNA_def_struct_refine_func(srna, "rna_GreasePencilTreeNode_refine");
/* Name. */
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Name", "The name of the tree node");
RNA_def_property_string_funcs(prop,
"rna_GreasePencilTreeNode_name_get",
"rna_GreasePencilTreeNode_name_length",
"rna_GreasePencilTreeNode_name_set");
RNA_def_struct_name_property(srna, prop);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_RENAME, "rna_grease_pencil_update");
/* Visibility. */
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GP_LAYER_TREE_NODE_HIDE);
RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1);
RNA_def_property_ui_text(prop, "Hide", "Set tree node visibility");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
/* Lock. */
prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GP_LAYER_TREE_NODE_LOCKED);
RNA_def_property_ui_icon(prop, ICON_UNLOCKED, 1);
RNA_def_property_ui_text(prop, "Locked", "Protect tree node from editing");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
/* Select. */
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GP_LAYER_TREE_NODE_SELECT);
RNA_def_property_ui_text(prop, "Select", "Tree node is selected");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
/* Onion Skinning. */
prop = RNA_def_property(srna, "use_onion_skinning", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_icon(prop, ICON_ONIONSKIN_OFF, 1);
RNA_def_property_boolean_negative_sdna(
prop, nullptr, "flag", GP_LAYER_TREE_NODE_HIDE_ONION_SKINNING);
RNA_def_property_ui_text(
prop, "Onion Skinning", "Display onion skins before and after the current frame");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
/* Use Masks. */
prop = RNA_def_property(srna, "use_masks", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_icon(prop, ICON_CLIPUV_HLT, -1);
RNA_def_property_boolean_negative_sdna(prop, nullptr, "flag", GP_LAYER_TREE_NODE_HIDE_MASKS);
RNA_def_property_ui_text(
prop,
"Use Masks",
"The visibility of drawings in this tree node is affected by the layers in the masks list");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
/* Channel color. */
prop = RNA_def_property(srna, "channel_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, nullptr, "color");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Channel Color", "Color of the channel in the dope sheet");
RNA_def_property_update(prop, NC_GPENCIL | NA_EDITED, nullptr);
/* Parent group. */
prop = RNA_def_property(srna, "parent_group", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "GreasePencilLayerGroup");
RNA_def_property_pointer_funcs(
prop, "rna_GreasePencilTreeNode_parent_layer_group_get", nullptr, nullptr, nullptr);
RNA_def_property_ui_text(prop, "Parent Layer Group", "The parent group of this layer tree node");
RNA_def_property_clear_flag(prop, PROP_EDITABLE | PROP_ANIMATABLE);
}
static void rna_def_grease_pencil_layer(BlenderRNA *brna)
{
StructRNA *srna;
@@ -882,21 +952,11 @@ static void rna_def_grease_pencil_layer(BlenderRNA *brna)
{GP_LAYER_BLEND_DIVIDE, "DIVIDE", 0, "Divide", ""},
{0, nullptr, 0, nullptr, nullptr}};
srna = RNA_def_struct(brna, "GreasePencilLayer", nullptr);
srna = RNA_def_struct(brna, "GreasePencilLayer", "GreasePencilTreeNode");
RNA_def_struct_sdna(srna, "GreasePencilLayer");
RNA_def_struct_ui_text(srna, "Grease Pencil Layer", "Collection of related drawings");
RNA_def_struct_path_func(srna, "rna_GreasePencilLayer_path");
/* Name */
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Name", "Layer name");
RNA_def_property_string_funcs(prop,
"rna_GreasePencilLayer_name_get",
"rna_GreasePencilLayer_name_length",
"rna_GreasePencilLayer_name_set");
RNA_def_struct_name_property(srna, prop);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_RENAME, "rna_grease_pencil_update");
/* Frames. */
prop = RNA_def_property(srna, "frames", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "GreasePencilFrame");
@@ -919,30 +979,6 @@ static void rna_def_grease_pencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Masks", "List of Masking Layers");
rna_def_grease_pencil_layer_masks(brna, prop);
/* Visibility */
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(
prop, "GreasePencilLayerTreeNode", "flag", GP_LAYER_TREE_NODE_HIDE);
RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1);
RNA_def_property_ui_text(prop, "Hide", "Set layer visibility");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
/* Lock */
prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(
prop, "GreasePencilLayerTreeNode", "flag", GP_LAYER_TREE_NODE_LOCKED);
RNA_def_property_ui_icon(prop, ICON_UNLOCKED, 1);
RNA_def_property_ui_text(
prop, "Locked", "Protect layer from further editing and/or frame changes");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
/* Select. */
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(
prop, "GreasePencilLayerTreeNode", "flag", GP_LAYER_TREE_NODE_SELECT);
RNA_def_property_ui_text(prop, "Select", "Layer is selected for editing in the Dope Sheet");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
/* Lock Frame. */
prop = RNA_def_property(srna, "lock_frame", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(
@@ -958,15 +994,6 @@ static void rna_def_grease_pencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Opacity", "Layer Opacity");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
/* Onion Skinning. */
prop = RNA_def_property(srna, "use_onion_skinning", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_icon(prop, ICON_ONIONSKIN_OFF, 1);
RNA_def_property_boolean_negative_sdna(
prop, "GreasePencilLayerTreeNode", "flag", GP_LAYER_TREE_NODE_HIDE_ONION_SKINNING);
RNA_def_property_ui_text(
prop, "Onion Skinning", "Display onion skins before and after the current frame");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
/* Tint Color. */
prop = RNA_def_property(srna, "tint_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_array(prop, 3);
@@ -998,17 +1025,6 @@ static void rna_def_grease_pencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Radius Offset", "Radius change to apply to current strokes");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
/* Use Masks. */
prop = RNA_def_property(srna, "use_masks", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_icon(prop, ICON_CLIPUV_HLT, -1);
RNA_def_property_boolean_negative_sdna(
prop, "GreasePencilLayerTreeNode", "flag", GP_LAYER_TREE_NODE_HIDE_MASKS);
RNA_def_property_ui_text(
prop,
"Use Masks",
"The visibility of drawings on this layer is affected by the layers in its masks list");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
prop = RNA_def_property(srna, "use_lights", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(
prop, "GreasePencilLayerTreeNode", "flag", GP_LAYER_TREE_NODE_USE_LIGHTS);
@@ -1109,14 +1125,6 @@ static void rna_def_grease_pencil_layer(BlenderRNA *brna)
RNA_def_property_float_funcs(
prop, "rna_GreasePencilLayer_matrix_parent_inverse_get", nullptr, nullptr);
/* Parent layer group. */
prop = RNA_def_property(srna, "parent_group", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "GreasePencilLayerGroup");
RNA_def_property_pointer_funcs(
prop, "rna_GreasePencilLayer_parent_layer_group_get", nullptr, nullptr, nullptr);
RNA_def_property_ui_text(
prop, "Parent Layer Group", "The parent layer group this layer is part of");
prop = RNA_def_property(srna, "channel_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, "GreasePencilLayerTreeNode", "color");
RNA_def_property_array(prop, 3);
@@ -1167,56 +1175,11 @@ static void rna_def_grease_pencil_layer_group(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "GreasePencilLayerGroup", nullptr);
srna = RNA_def_struct(brna, "GreasePencilLayerGroup", "GreasePencilTreeNode");
RNA_def_struct_sdna(srna, "GreasePencilLayerTreeGroup");
RNA_def_struct_ui_text(srna, "Grease Pencil Layer Group", "Group of Grease Pencil layers");
RNA_def_struct_path_func(srna, "rna_GreasePencilLayerGroup_path");
/* Name */
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Name", "Group name");
RNA_def_property_string_funcs(prop,
"rna_GreasePencilLayerGroup_name_get",
"rna_GreasePencilLayerGroup_name_length",
"rna_GreasePencilLayerGroup_name_set");
RNA_def_struct_name_property(srna, prop);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_RENAME, "rna_grease_pencil_update");
/* Visibility */
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(
prop, "GreasePencilLayerTreeNode", "flag", GP_LAYER_TREE_NODE_HIDE);
RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1);
RNA_def_property_ui_text(prop, "Hide", "Set layer group visibility");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
/* Lock */
prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(
prop, "GreasePencilLayerTreeNode", "flag", GP_LAYER_TREE_NODE_LOCKED);
RNA_def_property_ui_icon(prop, ICON_UNLOCKED, 1);
RNA_def_property_ui_text(
prop, "Locked", "Protect group from further editing and/or frame changes");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
/* Use Masks. */
prop = RNA_def_property(srna, "use_masks", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(
prop, "GreasePencilLayerTreeNode", "flag", GP_LAYER_TREE_NODE_HIDE_MASKS);
RNA_def_property_ui_text(prop,
"Use Masks",
"The visibility of drawings in the layers in this group is affected by "
"the layers in the masks lists");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
prop = RNA_def_property(srna, "use_onion_skinning", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_icon(prop, ICON_ONIONSKIN_OFF, 1);
RNA_def_property_boolean_negative_sdna(
prop, "GreasePencilLayerTreeNode", "flag", GP_LAYER_TREE_NODE_HIDE_ONION_SKINNING);
RNA_def_property_ui_text(
prop, "Onion Skinning", "Display onion skins before and after the current frame");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
/* Expanded */
prop = RNA_def_property(srna, "is_expanded", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(
@@ -1227,13 +1190,6 @@ static void rna_def_grease_pencil_layer_group(BlenderRNA *brna)
RNA_def_property_boolean_funcs(prop, nullptr, "rna_GreasePencilLayerGroup_is_expanded_set");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
/* Parent group. */
prop = RNA_def_property(srna, "parent_group", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "GreasePencilLayerGroup");
RNA_def_property_pointer_funcs(
prop, "rna_GreasePencilLayerGroup_parent_group_get", nullptr, nullptr, nullptr);
RNA_def_property_ui_text(prop, "Parent Group", "The parent group this group is part of");
/* Color tag. */
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);
@@ -1501,6 +1457,7 @@ static void rna_def_grease_pencil_data(BlenderRNA *brna)
void RNA_def_grease_pencil(BlenderRNA *brna)
{
rna_def_grease_pencil_data(brna);
rna_def_grease_pencil_tree_node(brna);
rna_def_grease_pencil_layer(brna);
rna_def_grease_pencil_layer_mask(brna);
rna_def_grease_pencil_layer_group(brna);