GPv3: Add layer masks operators and UI #119433
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
import bpy
|
||||
from bpy.types import Panel, Menu
|
||||
from bpy.types import Panel, Menu, UIList
|
||||
from rna_prop_ui import PropertyPanel
|
||||
|
||||
|
||||
|
@ -27,6 +27,39 @@ class LayerDataButtonsPanel:
|
|||
return grease_pencil and grease_pencil.layers.active
|
||||
|
||||
|
||||
class GREASE_PENCIL_UL_masks(UIList):
|
||||
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
|
||||
mask = item
|
||||
if self.layout_type in {'DEFAULT', 'COMPACT'}:
|
||||
row = layout.row(align=True)
|
||||
row.prop(mask, "name", text="", emboss=False, icon_value=icon)
|
||||
row.prop(mask, "invert", text="", emboss=False)
|
||||
row.prop(mask, "hide", text="", emboss=False)
|
||||
elif self.layout_type == 'GRID':
|
||||
layout.alignment = 'CENTER'
|
||||
layout.prop(mask, "name", text="", emboss=False, icon_value=icon)
|
||||
|
||||
|
||||
class GREASE_PENCIL_MT_layer_mask_add(Menu):
|
||||
bl_label = "Add Mask"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
grease_pencil = context.grease_pencil
|
||||
active_layer = grease_pencil.layers.active
|
||||
found = False
|
||||
for layer in grease_pencil.layers:
|
||||
if layer == active_layer or layer.name in active_layer.mask_layers:
|
||||
continue
|
||||
|
||||
found = True
|
||||
layout.operator("grease_pencil.layer_mask_add", text=layer.name).name = layer.name
|
||||
|
||||
if not found:
|
||||
layout.label(text="No layers to add")
|
||||
|
||||
|
||||
class DATA_PT_context_grease_pencil(DataButtonsPanel, Panel):
|
||||
bl_label = ""
|
||||
bl_options = {'HIDE_HEADER'}
|
||||
|
@ -101,6 +134,45 @@ class DATA_PT_grease_pencil_layers(DataButtonsPanel, Panel):
|
|||
row.prop(layer, "opacity", text="Opacity", slider=True)
|
||||
|
||||
|
||||
class DATA_PT_grease_pencil_layer_masks(LayerDataButtonsPanel, Panel):
|
||||
bl_label = "Masks"
|
||||
bl_parent_id = "DATA_PT_grease_pencil_layers"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw_header(self, context):
|
||||
grease_pencil = context.grease_pencil
|
||||
layer = grease_pencil.layers.active
|
||||
|
||||
self.layout.prop(layer, "use_masks", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
grease_pencil = context.grease_pencil
|
||||
layer = grease_pencil.layers.active
|
||||
|
||||
layout = self.layout
|
||||
layout.enabled = layer.use_masks
|
||||
|
||||
if not layer:
|
||||
return
|
||||
|
||||
rows = 4
|
||||
row = layout.row()
|
||||
col = row.column()
|
||||
col.template_list("GREASE_PENCIL_UL_masks", "", layer, "mask_layers", layer.mask_layers,
|
||||
"active_mask_index", rows=rows, sort_lock=True)
|
||||
|
||||
col = row.column(align=True)
|
||||
col.menu("GREASE_PENCIL_MT_layer_mask_add", icon='ADD', text="")
|
||||
col.operator("grease_pencil.layer_mask_remove", icon='REMOVE', text="")
|
||||
|
||||
col.separator()
|
||||
|
||||
sub = col.column(align=True)
|
||||
sub.operator("grease_pencil.layer_mask_reorder", icon='TRIA_UP', text="").direction = 'UP'
|
||||
sub.operator("grease_pencil.layer_mask_reorder", icon='TRIA_DOWN', text="").direction = 'DOWN'
|
||||
|
||||
|
||||
class DATA_PT_grease_pencil_layer_transform(LayerDataButtonsPanel, Panel):
|
||||
bl_label = "Transform"
|
||||
bl_parent_id = "DATA_PT_grease_pencil_layers"
|
||||
|
@ -159,8 +231,11 @@ class DATA_PT_grease_pencil_custom_props(DataButtonsPanel, PropertyPanel, Panel)
|
|||
|
||||
|
||||
classes = (
|
||||
GREASE_PENCIL_UL_masks,
|
||||
GREASE_PENCIL_MT_layer_mask_add,
|
||||
DATA_PT_context_grease_pencil,
|
||||
DATA_PT_grease_pencil_layers,
|
||||
DATA_PT_grease_pencil_layer_masks,
|
||||
DATA_PT_grease_pencil_layer_transform,
|
||||
DATA_PT_grease_pencil_layer_relations,
|
||||
DATA_PT_grease_pencil_custom_props,
|
||||
|
|
|
@ -148,6 +148,7 @@ class Layer;
|
|||
bool is_selected() const; \
|
||||
void set_selected(bool selected); \
|
||||
bool use_onion_skinning() const; \
|
||||
bool use_masks() const; \
|
||||
bool is_child_of(const LayerGroup &group) const;
|
||||
|
||||
/* Implements the forwarding of the methods defined by #TREENODE_COMMON_METHODS. */
|
||||
|
@ -192,6 +193,10 @@ class Layer;
|
|||
{ \
|
||||
return this->as_node().use_onion_skinning(); \
|
||||
} \
|
||||
inline bool class_name::use_masks() const \
|
||||
{ \
|
||||
return this->as_node().use_masks(); \
|
||||
} \
|
||||
inline bool class_name::is_child_of(const LayerGroup &group) const \
|
||||
{ \
|
||||
return this->as_node().is_child_of(group); \
|
||||
|
@ -685,6 +690,11 @@ inline bool TreeNode::use_onion_skinning() const
|
|||
{
|
||||
return ((this->flag & GP_LAYER_TREE_NODE_USE_ONION_SKINNING) != 0);
|
||||
}
|
||||
inline bool TreeNode::use_masks() const
|
||||
{
|
||||
return ((this->flag & GP_LAYER_TREE_NODE_USE_MASKS) != 0) &&
|
||||
filedescriptor marked this conversation as resolved
Outdated
|
||||
(!this->parent_group() || this->parent_group()->as_node().use_masks());
|
||||
}
|
||||
inline bool TreeNode::is_child_of(const LayerGroup &group) const
|
||||
{
|
||||
if (const LayerGroup *parent = this->parent_group()) {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_anim_data.hh"
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_customdata.hh"
|
||||
#include "BKE_deform.hh"
|
||||
|
@ -628,14 +629,12 @@ LayerMask::LayerMask()
|
|||
|
||||
LayerMask::LayerMask(StringRefNull name) : LayerMask()
|
||||
{
|
||||
this->layer_name = BLI_strdup(name.c_str());
|
||||
this->layer_name = BLI_strdup_null(name.c_str());
|
||||
}
|
||||
|
||||
LayerMask::LayerMask(const LayerMask &other) : LayerMask()
|
||||
{
|
||||
if (other.layer_name) {
|
||||
this->layer_name = BLI_strdup(other.layer_name);
|
||||
}
|
||||
this->layer_name = BLI_strdup_null(other.layer_name);
|
||||
this->flag = other.flag;
|
||||
}
|
||||
|
||||
|
@ -675,6 +674,7 @@ Layer::Layer()
|
|||
this->viewlayername = nullptr;
|
||||
|
||||
BLI_listbase_clear(&this->masks);
|
||||
this->active_mask_index = 0;
|
||||
|
||||
this->runtime = MEM_new<LayerRuntime>(__func__);
|
||||
}
|
||||
|
@ -688,7 +688,11 @@ Layer::Layer(const Layer &other) : Layer()
|
|||
{
|
||||
new (&this->base) TreeNode(other.base.wrap());
|
||||
|
||||
/* TODO: duplicate masks. */
|
||||
LISTBASE_FOREACH (GreasePencilLayerMask *, other_mask, &other.masks) {
|
||||
LayerMask *new_mask = MEM_new<LayerMask>(__func__, *reinterpret_cast<LayerMask *>(other_mask));
|
||||
BLI_addtail(&this->masks, reinterpret_cast<GreasePencilLayerMask *>(new_mask));
|
||||
}
|
||||
this->active_mask_index = other.active_mask_index;
|
||||
|
||||
this->blend_mode = other.blend_mode;
|
||||
this->opacity = other.opacity;
|
||||
|
@ -719,9 +723,9 @@ Layer::~Layer()
|
|||
MEM_SAFE_FREE(this->frames_storage.values);
|
||||
|
||||
LISTBASE_FOREACH_MUTABLE (GreasePencilLayerMask *, mask, &this->masks) {
|
||||
MEM_SAFE_FREE(mask->layer_name);
|
||||
MEM_freeN(mask);
|
||||
MEM_delete(reinterpret_cast<LayerMask *>(mask));
|
||||
}
|
||||
BLI_listbase_clear(&this->masks);
|
||||
|
||||
MEM_SAFE_FREE(this->parsubstr);
|
||||
MEM_SAFE_FREE(this->viewlayername);
|
||||
|
@ -2525,8 +2529,21 @@ void GreasePencil::rename_node(blender::bke::greasepencil::TreeNode &node,
|
|||
if (node.name() == new_name) {
|
||||
return;
|
||||
}
|
||||
node.set_name(node.is_layer() ? unique_layer_name(*this, new_name) :
|
||||
unique_layer_group_name(*this, new_name));
|
||||
std::string old_name = node.name();
|
||||
if (node.is_layer()) {
|
||||
node.set_name(unique_layer_name(*this, new_name));
|
||||
BKE_animdata_fix_paths_rename_all(&this->id, "layers", old_name.c_str(), node.name().c_str());
|
||||
for (bke::greasepencil::Layer *layer : this->layers_for_write()) {
|
||||
LISTBASE_FOREACH (GreasePencilLayerMask *, mask, &layer->masks) {
|
||||
if (STREQ(mask->layer_name, old_name.c_str())) {
|
||||
mask->layer_name = BLI_strdup(node.name().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (node.is_group()) {
|
||||
node.set_name(unique_layer_group_name(*this, new_name));
|
||||
}
|
||||
}
|
||||
|
||||
static void shrink_customdata(CustomData &data, const int index_to_remove, const int size)
|
||||
|
|
|
@ -426,6 +426,8 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b
|
|||
SET_FLAG_FROM_TEST(new_layer.base.flag,
|
||||
(gpl->onion_flag & GP_LAYER_ONIONSKIN),
|
||||
GP_LAYER_TREE_NODE_USE_ONION_SKINNING);
|
||||
SET_FLAG_FROM_TEST(
|
||||
new_layer.base.flag, (gpl->flag & GP_LAYER_USE_MASK), GP_LAYER_TREE_NODE_USE_MASKS);
|
||||
|
||||
new_layer.blend_mode = int8_t(gpl->blend_mode);
|
||||
|
||||
|
@ -440,7 +442,7 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b
|
|||
|
||||
/* Convert the layer masks. */
|
||||
LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &gpl->mask_layers) {
|
||||
LayerMask *new_mask = MEM_new<LayerMask>(mask->name);
|
||||
LayerMask *new_mask = MEM_new<LayerMask>(__func__, mask->name);
|
||||
new_mask->flag = mask->flag;
|
||||
BLI_addtail(&new_layer.masks, new_mask);
|
||||
}
|
||||
|
|
|
@ -524,6 +524,169 @@ static void GREASE_PENCIL_OT_layer_duplicate(wmOperatorType *ot)
|
|||
/* properties */
|
||||
RNA_def_boolean(ot->srna, "empty_keyframes", false, "Empty Keyframes", "Add Empty Keyframes");
|
||||
}
|
||||
|
||||
static int grease_pencil_layer_mask_add_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
using namespace ::blender::bke::greasepencil;
|
||||
Object *object = CTX_data_active_object(C);
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
|
||||
|
||||
if (!grease_pencil.has_active_layer()) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
Layer &active_layer = *grease_pencil.get_active_layer();
|
||||
|
||||
int mask_name_length;
|
||||
char *mask_name = RNA_string_get_alloc(op->ptr, "name", nullptr, 0, &mask_name_length);
|
||||
BLI_SCOPED_DEFER([&] { MEM_SAFE_FREE(mask_name); });
|
||||
|
||||
if (TreeNode *node = grease_pencil.find_node_by_name(mask_name)) {
|
||||
if (grease_pencil.is_layer_active(&node->as_layer())) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Cannot add active layer as mask");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if (BLI_findstring(&active_layer.masks,
|
||||
mask_name,
|
||||
offsetof(GreasePencilLayerMask, layer_name)) != nullptr)
|
||||
{
|
||||
BKE_report(op->reports, RPT_ERROR, "Layer already added");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
LayerMask *new_mask = MEM_new<LayerMask>(__func__, mask_name);
|
||||
BLI_addtail(&active_layer.masks, reinterpret_cast<GreasePencilLayerMask *>(new_mask));
|
||||
/* Make the newly added mask active. */
|
||||
active_layer.active_mask_index = BLI_listbase_count(&active_layer.masks) - 1;
|
||||
}
|
||||
else {
|
||||
BKE_report(op->reports, RPT_ERROR, "Unable to find layer to add");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, &grease_pencil);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void GREASE_PENCIL_OT_layer_mask_add(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Add New Mask Layer";
|
||||
ot->idname = "GREASE_PENCIL_OT_layer_mask_add";
|
||||
ot->description = "Add new layer as masking";
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = grease_pencil_layer_mask_add_exec;
|
||||
ot->poll = active_grease_pencil_layer_poll;
|
||||
|
||||
/* properties */
|
||||
RNA_def_string(ot->srna, "name", nullptr, 0, "Layer", "Name of the layer");
|
||||
}
|
||||
|
||||
static int grease_pencil_layer_mask_remove_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
using namespace ::blender::bke::greasepencil;
|
||||
Object *object = CTX_data_active_object(C);
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
|
||||
|
||||
if (!grease_pencil.has_active_layer()) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
Layer &active_layer = *grease_pencil.get_active_layer();
|
||||
if (GreasePencilLayerMask *mask = reinterpret_cast<GreasePencilLayerMask *>(
|
||||
BLI_findlink(&active_layer.masks, active_layer.active_mask_index)))
|
||||
{
|
||||
BLI_remlink(&active_layer.masks, mask);
|
||||
MEM_delete(reinterpret_cast<LayerMask *>(mask));
|
||||
active_layer.active_mask_index = std::max(active_layer.active_mask_index - 1, 0);
|
||||
}
|
||||
else {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, &grease_pencil);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void GREASE_PENCIL_OT_layer_mask_remove(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Remove Mask Layer";
|
||||
ot->idname = "GREASE_PENCIL_OT_layer_mask_remove";
|
||||
ot->description = "Remove Layer Mask";
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = grease_pencil_layer_mask_remove_exec;
|
||||
ot->poll = active_grease_pencil_layer_poll;
|
||||
}
|
||||
|
||||
enum class LayerMaskMoveDirection : int8_t { Up = -1, Down = 1 };
|
||||
|
||||
static int grease_pencil_layer_mask_reorder_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
using namespace ::blender::bke::greasepencil;
|
||||
Object *object = CTX_data_active_object(C);
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
|
||||
|
||||
if (!grease_pencil.has_active_layer()) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
Layer &active_layer = *grease_pencil.get_active_layer();
|
||||
const int direction = RNA_enum_get(op->ptr, "direction");
|
||||
|
||||
bool changed = false;
|
||||
if (GreasePencilLayerMask *mask = reinterpret_cast<GreasePencilLayerMask *>(
|
||||
BLI_findlink(&active_layer.masks, active_layer.active_mask_index)))
|
||||
{
|
||||
if (BLI_listbase_link_move(&active_layer.masks, mask, direction)) {
|
||||
active_layer.active_mask_index = std::max(active_layer.active_mask_index + direction, 0);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, &grease_pencil);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void GREASE_PENCIL_OT_layer_mask_reorder(wmOperatorType *ot)
|
||||
{
|
||||
static const EnumPropertyItem enum_direction[] = {
|
||||
{int(LayerMaskMoveDirection::Up), "UP", 0, "Up", ""},
|
||||
{int(LayerMaskMoveDirection::Down), "DOWN", 0, "Down", ""},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
/* identifiers */
|
||||
ot->name = "Reorder Grease Pencil Layer Mask";
|
||||
ot->idname = "GREASE_PENCIL_OT_layer_mask_reorder";
|
||||
ot->description = "Reorder the active Grease Pencil mask layer up/down in the list";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = grease_pencil_layer_mask_reorder_exec;
|
||||
ot->poll = active_grease_pencil_layer_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
ot->prop = RNA_def_enum(ot->srna, "direction", enum_direction, 0, "Direction", "");
|
||||
}
|
||||
|
||||
} // namespace blender::ed::greasepencil
|
||||
|
||||
void ED_operatortypes_grease_pencil_layers()
|
||||
|
@ -540,4 +703,8 @@ void ED_operatortypes_grease_pencil_layers()
|
|||
WM_operatortype_append(GREASE_PENCIL_OT_layer_duplicate);
|
||||
|
||||
WM_operatortype_append(GREASE_PENCIL_OT_layer_group_add);
|
||||
|
||||
WM_operatortype_append(GREASE_PENCIL_OT_layer_mask_add);
|
||||
WM_operatortype_append(GREASE_PENCIL_OT_layer_mask_remove);
|
||||
WM_operatortype_append(GREASE_PENCIL_OT_layer_mask_reorder);
|
||||
}
|
||||
|
|
|
@ -255,6 +255,27 @@ class LayerViewItem : public AbstractTreeViewItem {
|
|||
PointerRNA layer_ptr = RNA_pointer_create(&grease_pencil_.id, &RNA_GreasePencilLayer, &layer_);
|
||||
|
||||
uiBlock *block = uiLayoutGetBlock(&row);
|
||||
|
||||
const int icon = (layer_.base.flag & GP_LAYER_TREE_NODE_USE_MASKS) != 0 ? ICON_CLIPUV_DEHLT :
|
||||
ICON_CLIPUV_HLT;
|
||||
but = uiDefIconButR(block,
|
||||
UI_BTYPE_ICON_TOGGLE,
|
||||
0,
|
||||
icon,
|
||||
0,
|
||||
0,
|
||||
UI_UNIT_X,
|
||||
UI_UNIT_Y,
|
||||
&layer_ptr,
|
||||
"use_masks",
|
||||
0,
|
||||
0.0f,
|
||||
0.0f,
|
||||
nullptr);
|
||||
if (layer_.parent_group().use_masks()) {
|
||||
UI_but_flag_enable(but, UI_BUT_INACTIVE);
|
||||
}
|
||||
|
||||
but = uiDefIconButR(block,
|
||||
UI_BTYPE_ICON_TOGGLE,
|
||||
0,
|
||||
|
@ -359,6 +380,9 @@ class LayerGroupViewItem : public AbstractTreeViewItem {
|
|||
PointerRNA group_ptr = RNA_pointer_create(
|
||||
&grease_pencil_.id, &RNA_GreasePencilLayerGroup, &group_);
|
||||
|
||||
const int icon = (group_.base.flag & GP_LAYER_TREE_NODE_USE_MASKS) != 0 ? ICON_CLIPUV_DEHLT :
|
||||
ICON_CLIPUV_HLT;
|
||||
uiItemR(&row, &group_ptr, "use_masks", UI_ITEM_R_ICON_ONLY, nullptr, icon);
|
||||
uiItemR(&row, &group_ptr, "hide", UI_ITEM_R_ICON_ONLY, nullptr, ICON_NONE);
|
||||
uiItemR(&row, &group_ptr, "lock", UI_ITEM_R_ICON_ONLY, nullptr, ICON_NONE);
|
||||
}
|
||||
|
|
|
@ -240,6 +240,7 @@ typedef enum GreasePencilLayerTreeNodeFlag {
|
|||
GP_LAYER_TREE_NODE_USE_LIGHTS = (1 << 4),
|
||||
GP_LAYER_TREE_NODE_USE_ONION_SKINNING = (1 << 5),
|
||||
GP_LAYER_TREE_NODE_EXPANDED = (1 << 6),
|
||||
GP_LAYER_TREE_NODE_USE_MASKS = (1 << 7),
|
||||
} GreasePencilLayerTreeNodeFlag;
|
||||
|
||||
struct GreasePencilLayerTreeGroup;
|
||||
|
@ -292,6 +293,8 @@ typedef struct GreasePencilLayer {
|
|||
* List of `GreasePencilLayerMask`.
|
||||
*/
|
||||
ListBase masks;
|
||||
int active_mask_index;
|
||||
char _pad2[4];
|
||||
/**
|
||||
* Layer parent object. Can be an armature in which case the `parsubstr` is the bone name.
|
||||
*/
|
||||
|
@ -302,7 +305,7 @@ typedef struct GreasePencilLayer {
|
|||
* Use the functions is the `bke::greasepencil::Layer` class instead.
|
||||
*/
|
||||
float translation[3], rotation[3], scale[3];
|
||||
char _pad2[4];
|
||||
char _pad3[4];
|
||||
/** Name of the view layer used to filter render output. */
|
||||
char *viewlayername;
|
||||
/**
|
||||
|
|
|
@ -64,6 +64,60 @@ static void rna_grease_pencil_dependency_update(Main *bmain, Scene * /*scene*/,
|
|||
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, rna_grease_pencil(ptr));
|
||||
}
|
||||
|
||||
static void rna_grease_pencil_layer_mask_name_get(PointerRNA *ptr, char *dst)
|
||||
{
|
||||
using namespace blender;
|
||||
GreasePencilLayerMask *mask = static_cast<GreasePencilLayerMask *>(ptr->data);
|
||||
if (mask->layer_name != nullptr) {
|
||||
strcpy(dst, mask->layer_name);
|
||||
}
|
||||
else {
|
||||
dst[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static int rna_grease_pencil_layer_mask_name_length(PointerRNA *ptr)
|
||||
{
|
||||
using namespace blender;
|
||||
GreasePencilLayerMask *mask = static_cast<GreasePencilLayerMask *>(ptr->data);
|
||||
if (mask->layer_name != nullptr) {
|
||||
return strlen(mask->layer_name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rna_grease_pencil_layer_mask_name_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
using namespace blender;
|
||||
GreasePencil *grease_pencil = rna_grease_pencil(ptr);
|
||||
GreasePencilLayerMask *mask = static_cast<GreasePencilLayerMask *>(ptr->data);
|
||||
|
||||
const std::string oldname(mask->layer_name);
|
||||
if (bke::greasepencil::TreeNode *node = grease_pencil->find_node_by_name(oldname)) {
|
||||
grease_pencil->rename_node(*node, value);
|
||||
}
|
||||
}
|
||||
|
||||
static int rna_grease_pencil_active_mask_index_get(PointerRNA *ptr)
|
||||
{
|
||||
GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(ptr->data);
|
||||
return layer->active_mask_index;
|
||||
}
|
||||
|
||||
static void rna_grease_pencil_active_mask_index_set(PointerRNA *ptr, int value)
|
||||
{
|
||||
GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(ptr->data);
|
||||
layer->active_mask_index = value;
|
||||
}
|
||||
|
||||
static void rna_grease_pencil_active_mask_index_range(
|
||||
PointerRNA *ptr, int *min, int *max, int * /*softmin*/, int * /*softmax*/)
|
||||
{
|
||||
GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(ptr->data);
|
||||
*min = 0;
|
||||
*max = max_ii(0, BLI_listbase_count(&layer->masks) - 1);
|
||||
}
|
||||
|
||||
static void rna_iterator_grease_pencil_layers_begin(CollectionPropertyIterator *iter,
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
|
@ -229,6 +283,60 @@ static int rna_iterator_grease_pencil_layer_groups_length(PointerRNA *ptr)
|
|||
|
||||
#else
|
||||
|
||||
static void rna_def_grease_pencil_layers_mask_api(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
RNA_def_property_srna(cprop, "GreasePencilLayerMasks");
|
||||
srna = RNA_def_struct(brna, "GreasePencilLayerMasks", nullptr);
|
||||
RNA_def_struct_sdna(srna, "GreasePencilLayer");
|
||||
RNA_def_struct_ui_text(
|
||||
srna, "Grease Pencil Mask Layers", "Collection of grease pencil masking layers");
|
||||
|
||||
prop = RNA_def_property(srna, "active_mask_index", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_int_funcs(prop,
|
||||
"rna_grease_pencil_active_mask_index_get",
|
||||
"rna_grease_pencil_active_mask_index_set",
|
||||
"rna_grease_pencil_active_mask_index_range");
|
||||
RNA_def_property_ui_text(prop, "Active Layer Mask Index", "Active index in layer mask array");
|
||||
}
|
||||
|
||||
static void rna_def_grease_pencil_layer_mask(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "GreasePencilLayerMask", nullptr);
|
||||
RNA_def_struct_sdna(srna, "GreasePencilLayerMask");
|
||||
RNA_def_struct_ui_text(srna, "Grease Pencil Masking Layers", "List of Mask Layers");
|
||||
// RNA_def_struct_path_func(srna, "rna_GreasePencilLayerMask_path");
|
||||
|
||||
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Layer", "Mask layer name");
|
||||
RNA_def_property_string_sdna(prop, nullptr, "layer_name");
|
||||
RNA_def_property_string_funcs(prop,
|
||||
"rna_grease_pencil_layer_mask_name_get",
|
||||
"rna_grease_pencil_layer_mask_name_length",
|
||||
"rna_grease_pencil_layer_mask_name_set");
|
||||
RNA_def_struct_name_property(srna, prop);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_RENAME, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GP_LAYER_MASK_HIDE);
|
||||
RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1);
|
||||
RNA_def_property_ui_text(prop, "Hide", "Set mask Visibility");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "invert", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GP_LAYER_MASK_INVERT);
|
||||
RNA_def_property_ui_icon(prop, ICON_SELECT_INTERSECT, 1);
|
||||
RNA_def_property_ui_text(prop, "Invert", "Invert mask");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
}
|
||||
|
||||
static void rna_def_grease_pencil_layer(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
|
@ -251,6 +359,13 @@ static void rna_def_grease_pencil_layer(BlenderRNA *brna)
|
|||
RNA_def_struct_name_property(srna, prop);
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_RENAME, "rna_grease_pencil_update");
|
||||
|
||||
/* Mask Layers */
|
||||
prop = RNA_def_property(srna, "mask_layers", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_collection_sdna(prop, nullptr, "masks", nullptr);
|
||||
RNA_def_property_struct_type(prop, "GreasePencilLayerMask");
|
||||
RNA_def_property_ui_text(prop, "Masks", "List of Masking Layers");
|
||||
rna_def_grease_pencil_layers_mask_api(brna, prop);
|
||||
|
||||
/* Visibility */
|
||||
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(
|
||||
|
@ -282,6 +397,16 @@ static void rna_def_grease_pencil_layer(BlenderRNA *brna)
|
|||
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_boolean_sdna(
|
||||
prop, "GreasePencilLayerTreeNode", "flag", GP_LAYER_TREE_NODE_USE_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");
|
||||
|
||||
/* pass index for compositing and modifiers */
|
||||
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_ui_text(prop, "Pass Index", "Index number for the \"Layer Index\" pass");
|
||||
|
@ -392,6 +517,16 @@ static void rna_def_grease_pencil_layer_group(BlenderRNA *brna)
|
|||
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_sdna(
|
||||
prop, "GreasePencilLayerTreeNode", "flag", GP_LAYER_TREE_NODE_USE_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");
|
||||
}
|
||||
|
||||
static void rna_def_grease_pencil_data(BlenderRNA *brna)
|
||||
|
@ -468,6 +603,7 @@ void RNA_def_grease_pencil(BlenderRNA *brna)
|
|||
{
|
||||
rna_def_grease_pencil_data(brna);
|
||||
rna_def_grease_pencil_layer(brna);
|
||||
rna_def_grease_pencil_layer_mask(brna);
|
||||
rna_def_grease_pencil_layer_group(brna);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Is this flag the correct way around? Looks like it checks that
GP_LAYER_TREE_NODE_USE_MASKS
is not set.Good catch! Thank you.