Blender V4.5
grease_pencil_layers.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_listbase.h"
10#include "BLI_math_matrix.h"
11#include "BLI_math_matrix.hh"
12#include "BLI_string.h"
13
14#include "BKE_attribute_math.hh"
15#include "BKE_context.hh"
16#include "BKE_grease_pencil.hh"
17#include "BKE_object.hh"
18#include "BKE_report.hh"
19
20#include "BLT_translation.hh"
21
22#include "DEG_depsgraph.hh"
23
24#include "ED_grease_pencil.hh"
25
26#include "RNA_access.hh"
27#include "RNA_define.hh"
28
29#include "UI_interface.hh"
30
31#include "DNA_scene_types.h"
32
33#include "WM_api.hh"
34#include "WM_message.hh"
35
37
38/* This utility function is modified from `BKE_object_get_parent_matrix()`. */
39static float4x4 get_bone_mat(const Object *parent, const char *parsubstr)
40{
41 if (parent->type != OB_ARMATURE) {
42 return float4x4::identity();
43 }
44
45 const bPoseChannel *pchan = BKE_pose_channel_find_name(parent->pose, parsubstr);
46 if (!pchan || !pchan->bone) {
47 return float4x4::identity();
48 }
49
50 if (pchan->bone->flag & BONE_RELATIVE_PARENTING) {
51 return float4x4(pchan->chan_mat);
52 }
53 return float4x4(pchan->pose_mat);
54}
55
57 Object *parent,
58 StringRefNull bone,
59 const bool keep_transform)
60{
61 if (keep_transform) {
62 /* TODO apply current transform to geometry. */
63 }
64
65 layer.parent = parent;
66 layer.parsubstr = BLI_strdup_null(bone.c_str());
67 /* Calculate inverse parent matrix. */
68 if (parent) {
69 float4x4 inverse = parent->world_to_object();
70 if (layer.parsubstr) {
71 const float4x4 bone_mat = get_bone_mat(parent, layer.parsubstr);
72 inverse = math::invert(bone_mat) * inverse;
73 }
74 copy_m4_m4(layer.parentinv, inverse.ptr());
75 }
76 else {
77 unit_m4(layer.parentinv);
78 }
79
80 return true;
81}
82
83void grease_pencil_layer_parent_clear(bke::greasepencil::Layer &layer, const bool keep_transform)
84{
85 if (layer.parent == nullptr) {
86 return;
87 }
88 if (keep_transform) {
89 /* TODO apply current transform to geometry. */
90 }
91
92 layer.parent = nullptr;
94
96}
97
99{
100 using namespace blender::bke::greasepencil;
101
102 if (layer != nullptr) {
103 layer->set_selected(true);
104 }
105
106 if (grease_pencil.get_active_layer() != layer) {
107 grease_pencil.set_active_layer(layer);
109 }
110}
111
113{
114 using namespace blender::bke::greasepencil;
115 Scene *scene = CTX_data_scene(C);
117
118 int new_layer_name_length;
119 char *new_layer_name = RNA_string_get_alloc(
120 op->ptr, "new_layer_name", nullptr, 0, &new_layer_name_length);
121 BLI_SCOPED_DEFER([&] { MEM_SAFE_FREE(new_layer_name); });
122 Layer &new_layer = grease_pencil.add_layer(new_layer_name);
124 CTX_wm_message_bus(C), &grease_pencil.id, &grease_pencil, GreasePencilv3, layers);
125
126 if (grease_pencil.has_active_layer()) {
127 grease_pencil.move_node_after(new_layer.as_node(),
128 grease_pencil.get_active_layer()->as_node());
129 }
130 else if (grease_pencil.has_active_group()) {
131 grease_pencil.move_node_into(new_layer.as_node(), *grease_pencil.get_active_group());
133 &grease_pencil.id,
134 &grease_pencil,
135 GreasePencilv3LayerGroup,
136 active);
137 }
138
139 grease_pencil.set_active_layer(&new_layer);
141 CTX_wm_message_bus(C), &grease_pencil.id, &grease_pencil, GreasePencilv3Layers, active);
142
143 grease_pencil.insert_frame(new_layer, scene->r.cfra);
144
145 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
147
148 return OPERATOR_FINISHED;
149}
150
152 wmOperator *op,
153 const wmEvent *event)
154{
156 op,
157 event,
158 IFACE_("Add New Grease Pencil Layer"),
160}
161
163{
164 /* identifiers */
165 ot->name = "Add New Layer";
166 ot->idname = "GREASE_PENCIL_OT_layer_add";
167 ot->description = "Add a new Grease Pencil layer in the active object";
168
169 /* callbacks */
173
175
177 ot->srna, "new_layer_name", "Layer", INT16_MAX, "Name", "Name of the new layer");
179 ot->prop = prop;
180}
181
183{
184 using namespace blender::bke::greasepencil;
186
187 if (!grease_pencil.has_active_layer()) {
188 return OPERATOR_CANCELLED;
189 }
190
191 grease_pencil.remove_layer(*grease_pencil.get_active_layer());
192
194 CTX_wm_message_bus(C), &grease_pencil.id, &grease_pencil, GreasePencilv3Layers, active);
196 CTX_wm_message_bus(C), &grease_pencil.id, &grease_pencil, GreasePencilv3, layers);
197
198 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
200
201 return OPERATOR_FINISHED;
202}
203
205{
206 /* identifiers */
207 ot->name = "Remove Layer";
208 ot->idname = "GREASE_PENCIL_OT_layer_remove";
209 ot->description = "Remove the active Grease Pencil layer";
210
211 /* callbacks */
214
216}
217
218enum class LayerMoveDirection : int8_t { Up = -1, Down = 1 };
219
221 {int(LayerMoveDirection::Up), "UP", 0, "Up", ""},
222 {int(LayerMoveDirection::Down), "DOWN", 0, "Down", ""},
223 {0, nullptr, 0, nullptr, nullptr},
224};
225
227{
228 using namespace blender::bke::greasepencil;
230 return false;
231 }
232
234 const TreeNode *active_node = grease_pencil.get_active_node();
235
236 if (active_node == nullptr) {
237 return false;
238 }
239
240 const LayerGroup *parent = active_node->parent_group();
241
242 if (parent == nullptr || parent->num_direct_nodes() < 2) {
243 return false;
244 }
245
246 return true;
247}
248
250{
251 using namespace blender::bke::greasepencil;
253
254 const LayerMoveDirection direction = LayerMoveDirection(RNA_enum_get(op->ptr, "direction"));
255
256 TreeNode &active_node = *grease_pencil.get_active_node();
257
258 if (direction == LayerMoveDirection::Up) {
259 grease_pencil.move_node_up(active_node);
260 }
261 else if (direction == LayerMoveDirection::Down) {
262 grease_pencil.move_node_down(active_node);
263 }
264
265 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
266 WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
267
269 CTX_wm_message_bus(C), &grease_pencil.id, &grease_pencil, GreasePencilv3, layers);
270
271 return OPERATOR_FINISHED;
272}
273
275{
276 /* identifiers */
277 ot->name = "Reorder Layer";
278 ot->idname = "GREASE_PENCIL_OT_layer_move";
279 ot->description = "Move the active Grease Pencil layer or Group";
280
281 /* callbacks */
284
286
287 ot->prop = RNA_def_enum(ot->srna, "direction", enum_layer_move_direction, 0, "Direction", "");
288}
289
291{
292 using namespace blender::bke::greasepencil;
294 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
295 int layer_index = RNA_int_get(op->ptr, "layer");
296
297 if (!grease_pencil.layers().index_range().contains(layer_index)) {
298 return OPERATOR_CANCELLED;
299 }
300
301 Layer &layer = grease_pencil.layer(layer_index);
302 if (grease_pencil.is_layer_active(&layer)) {
303 return OPERATOR_CANCELLED;
304 }
305
306 if (grease_pencil.has_active_group()) {
308 &grease_pencil.id,
309 &grease_pencil,
310 GreasePencilv3LayerGroup,
311 active);
312 }
313 grease_pencil.set_active_layer(&layer);
314
316 CTX_wm_message_bus(C), &grease_pencil.id, &grease_pencil, GreasePencilv3Layers, active);
317
319
320 return OPERATOR_FINISHED;
321}
322
324{
325 /* identifiers */
326 ot->name = "Set Active Layer";
327 ot->idname = "GREASE_PENCIL_OT_layer_active";
328 ot->description = "Set the active Grease Pencil layer";
329
330 /* callbacks */
333
335
336 PropertyRNA *prop = RNA_def_int(
337 ot->srna, "layer", 0, 0, INT_MAX, "Grease Pencil Layer", "", 0, INT_MAX);
339}
340
342{
343 using namespace blender::bke::greasepencil;
345
346 int new_layer_group_name_length;
347 char *new_layer_group_name = RNA_string_get_alloc(
348 op->ptr, "new_layer_group_name", nullptr, 0, &new_layer_group_name_length);
349
350 LayerGroup &new_group = grease_pencil.add_layer_group(new_layer_group_name);
352 CTX_wm_message_bus(C), &grease_pencil.id, &grease_pencil, GreasePencilv3, layer_groups);
353
354 if (grease_pencil.has_active_layer()) {
355 grease_pencil.move_node_after(new_group.as_node(),
356 grease_pencil.get_active_layer()->as_node());
358 CTX_wm_message_bus(C), &grease_pencil.id, &grease_pencil, GreasePencilv3Layers, active);
359 }
360 else if (grease_pencil.has_active_group()) {
361 grease_pencil.move_node_into(new_group.as_node(), *grease_pencil.get_active_group());
363 &grease_pencil.id,
364 &grease_pencil,
365 GreasePencilv3LayerGroup,
366 active);
367 }
368
369 MEM_SAFE_FREE(new_layer_group_name);
370 grease_pencil.set_active_node(&new_group.as_node());
371
373 CTX_wm_message_bus(C), &grease_pencil.id, &grease_pencil, GreasePencilv3LayerGroup, active);
374
375 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
376 WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
378
379 return OPERATOR_FINISHED;
380}
381
383{
384 /* identifiers */
385 ot->name = "Add New Layer Group";
386 ot->idname = "GREASE_PENCIL_OT_layer_group_add";
387 ot->description = "Add a new Grease Pencil layer group in the active object";
388
389 /* callbacks */
392
394
396 ot->srna, "new_layer_group_name", nullptr, INT16_MAX, "Name", "Name of the new layer group");
398 ot->prop = prop;
399}
400
402{
403 using namespace blender::bke::greasepencil;
404 const bool keep_children = RNA_boolean_get(op->ptr, "keep_children");
406
407 if (!grease_pencil.has_active_group()) {
408 return OPERATOR_CANCELLED;
409 }
410
411 grease_pencil.remove_group(*grease_pencil.get_active_group(), keep_children);
412
413 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
415
417 CTX_wm_message_bus(C), &grease_pencil.id, &grease_pencil, GreasePencilv3LayerGroup, active);
419 CTX_wm_message_bus(C), &grease_pencil.id, &grease_pencil, GreasePencilv3, layer_groups);
420
421 return OPERATOR_FINISHED;
422}
423
425{
426 /* identifiers */
427 ot->name = "Remove Layer Group";
428 ot->idname = "GREASE_PENCIL_OT_layer_group_remove";
429 ot->description = "Remove Grease Pencil layer group in the active object";
430
431 /* callbacks */
434
436
437 RNA_def_boolean(ot->srna,
438 "keep_children",
439 false,
440 "Keep children nodes",
441 "Keep the children nodes of the group and only delete the group itself");
442}
443
445{
446 using namespace blender::bke::greasepencil;
448 const bool unselected = RNA_boolean_get(op->ptr, "unselected");
449
450 TreeNode *active_node = grease_pencil.get_active_node();
451
452 if (!active_node) {
453 return OPERATOR_CANCELLED;
454 }
455
456 if (unselected) {
457 /* If active node is a layer group, only show parent layer groups and child nodes.
458 * If active node is a layer, only show parent layer groups and active node. */
459
460 for (TreeNode *node : grease_pencil.nodes_for_write()) {
461 bool should_be_visible = false;
462
463 if (active_node->is_group()) {
464 should_be_visible = node->is_child_of(active_node->as_group());
465 if (node->is_group()) {
466 should_be_visible |= active_node->is_child_of(node->as_group());
467 }
468 }
469 else if (node->is_group()) {
470 should_be_visible = active_node->is_child_of(node->as_group());
471 }
472
473 node->set_visible(should_be_visible);
474 }
475 active_node->set_visible(true);
476 }
477 else {
478 /* hide selected/active */
479 active_node->set_visible(false);
480 }
481
482 /* notifiers */
483 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
484 WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
486
487 return OPERATOR_FINISHED;
488}
489
491{
492 /* identifiers */
493 ot->name = "Hide Layer(s)";
494 ot->idname = "GREASE_PENCIL_OT_layer_hide";
495 ot->description = "Hide selected/unselected Grease Pencil layers";
496
497 /* callbacks */
500
501 /* flags */
503
504 /* props */
506 ot->srna, "unselected", false, "Unselected", "Hide unselected rather than selected layers");
508 ot->prop = prop;
509}
510
512{
513 using namespace blender::bke::greasepencil;
515
516 if (!grease_pencil.get_active_node()) {
517 return OPERATOR_CANCELLED;
518 }
519
520 for (TreeNode *node : grease_pencil.nodes_for_write()) {
521 node->set_visible(true);
522 }
523
524 /* notifiers */
525 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
526 WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
528
529 return OPERATOR_FINISHED;
530}
531
533{
534 /* identifiers */
535 ot->name = "Show All Layers";
536 ot->idname = "GREASE_PENCIL_OT_layer_reveal";
537 ot->description = "Show all Grease Pencil layers";
538
539 /* callbacks */
542
543 /* flags */
545}
546
548{
549 using namespace blender::bke::greasepencil;
551 const int affect_visibility = RNA_boolean_get(op->ptr, "affect_visibility");
552 bool isolate = false;
553
554 for (const Layer *layer : grease_pencil.layers()) {
555 if (grease_pencil.is_layer_active(layer)) {
556 continue;
557 }
558 if ((affect_visibility && layer->is_visible()) || !layer->is_locked()) {
559 isolate = true;
560 break;
561 }
562 }
563
564 for (Layer *layer : grease_pencil.layers_for_write()) {
565 if (grease_pencil.is_layer_active(layer) || !isolate) {
566 layer->set_locked(false);
567 if (affect_visibility) {
568 layer->set_visible(true);
569 }
570 }
571 else {
572 layer->set_locked(true);
573 if (affect_visibility) {
574 layer->set_visible(false);
575 }
576 }
577 }
578
579 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
580 WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
582
583 return OPERATOR_FINISHED;
584}
585
587{
588 /* identifiers */
589 ot->name = "Isolate Layers";
590 ot->idname = "GREASE_PENCIL_OT_layer_isolate";
591 ot->description = "Make only active layer visible/editable";
592
593 /* callbacks */
596
597 /* flags */
599
600 /* properties */
602 ot->srna, "affect_visibility", false, "Affect Visibility", "Also affect the visibility");
603}
604
606{
607 using namespace blender::bke::greasepencil;
609 const bool lock_value = RNA_boolean_get(op->ptr, "lock");
610
611 if (grease_pencil.nodes().is_empty()) {
612 return OPERATOR_CANCELLED;
613 }
614
615 for (TreeNode *node : grease_pencil.nodes_for_write()) {
616 node->set_locked(lock_value);
617 }
618
619 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
620 WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
622
623 return OPERATOR_FINISHED;
624}
625
627{
628 /* identifiers */
629 ot->name = "Lock All Layers";
630 ot->idname = "GREASE_PENCIL_OT_layer_lock_all";
631 ot->description =
632 "Lock all Grease Pencil layers to prevent them from being accidentally modified";
633
634 /* callbacks */
637
638 /* flags */
640
641 /* properties */
642 RNA_def_boolean(ot->srna, "lock", true, "Lock Value", "Lock/Unlock all layers");
643}
644
646{
647 using namespace blender::bke::greasepencil;
649 const bool empty_keyframes = RNA_boolean_get(op->ptr, "empty_keyframes");
650
651 if (!grease_pencil.has_active_layer()) {
652 BKE_reportf(op->reports, RPT_ERROR, "No active layer to duplicate");
653 return OPERATOR_CANCELLED;
654 }
655
656 /* Duplicate layer. */
657 Layer &active_layer = *grease_pencil.get_active_layer();
658 Layer &new_layer = grease_pencil.duplicate_layer(active_layer);
659
661 CTX_wm_message_bus(C), &grease_pencil.id, &grease_pencil, GreasePencilv3, layers);
662
663 /* Clear source keyframes and recreate them with duplicated drawings. */
664 new_layer.frames_for_write().clear();
665 for (auto [frame_number, frame] : active_layer.frames().items()) {
666 const int duration = active_layer.get_frame_duration_at(frame_number);
667
668 Drawing *dst_drawing = grease_pencil.insert_frame(
669 new_layer, frame_number, duration, eBezTriple_KeyframeType(frame.type));
670 if (!empty_keyframes) {
671 BLI_assert(dst_drawing != nullptr);
672 /* TODO: This can fail (return `nullptr`) if the drawing is a drawing reference! */
673 const Drawing &src_drawing = *grease_pencil.get_drawing_at(active_layer, frame_number);
674 /* Duplicate the drawing. */
675 *dst_drawing = src_drawing;
676 }
677 }
678
679 grease_pencil.move_node_after(new_layer.as_node(), active_layer.as_node());
680 grease_pencil.set_active_layer(&new_layer);
681
682 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
684
686 CTX_wm_message_bus(C), &grease_pencil.id, &grease_pencil, GreasePencilv3Layers, active);
687
688 return OPERATOR_FINISHED;
689}
690
692{
693 /* identifiers */
694 ot->name = "Duplicate Layer";
695 ot->idname = "GREASE_PENCIL_OT_layer_duplicate";
696 ot->description = "Make a copy of the active Grease Pencil layer";
697
698 /* callbacks */
701
702 /* flags */
704
705 /* properties */
706 RNA_def_boolean(ot->srna, "empty_keyframes", false, "Empty Keyframes", "Add Empty Keyframes");
707}
708
709enum class MergeMode : int8_t {
710 Down = 0,
711 Group = 1,
712 All = 2,
713};
714
716{
717 using namespace blender::bke::greasepencil;
718 Main *bmain = CTX_data_main(C);
720 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
721 const MergeMode mode = MergeMode(RNA_enum_get(op->ptr, "mode"));
722
723 Vector<Vector<int>> src_layer_indices_by_dst_layer;
724 std::string merged_layer_name;
725 if (mode == MergeMode::Down) {
726 if (!grease_pencil.has_active_layer()) {
727 BKE_report(op->reports, RPT_ERROR, "No active layer");
728 return OPERATOR_CANCELLED;
729 }
730 const Layer &active_layer = *grease_pencil.get_active_layer();
731 GreasePencilLayerTreeNode *prev_node = active_layer.as_node().prev;
732 if (prev_node == nullptr || !prev_node->wrap().is_layer()) {
733 /* No layer below the active one. */
734 return OPERATOR_CANCELLED;
735 }
736 const Layer &prev_layer = prev_node->wrap().as_layer();
737 /* Get the indices of the two layers to be merged. */
738 const int prev_layer_index = *grease_pencil.get_layer_index(prev_layer);
739 const int active_layer_index = *grease_pencil.get_layer_index(active_layer);
740
741 /* Map all the other layers to their own index. */
742 const Span<const Layer *> layers = grease_pencil.layers();
743 for (const int layer_i : layers.index_range()) {
744 if (layer_i == active_layer_index) {
745 /* Active layer is merged into previous, skip. */
746 }
747 else if (layer_i == prev_layer_index) {
748 /* Previous layer merges itself and the active layer. */
749 src_layer_indices_by_dst_layer.append({prev_layer_index, active_layer_index});
750 }
751 else {
752 /* Other layers remain unchanged. */
753 src_layer_indices_by_dst_layer.append({layer_i});
754 }
755 }
756
757 /* Store the name of the current active layer as the name of the merged layer. */
758 merged_layer_name = grease_pencil.layer(prev_layer_index).name();
759 }
760 else if (mode == MergeMode::Group) {
761 if (!grease_pencil.has_active_group()) {
762 BKE_report(op->reports, RPT_ERROR, "No active group");
763 return OPERATOR_CANCELLED;
764 }
765 LayerGroup &active_group = *grease_pencil.get_active_group();
766
767 if (active_group.layers().is_empty()) {
768 BKE_report(op->reports, RPT_INFO, "No child layers to merge");
769 return OPERATOR_CANCELLED;
770 }
771
772 /* Remove all sub groups of the active group since they won't be needed anymore, but keep the
773 * layers. */
774 Array<LayerGroup *> groups = active_group.groups_for_write();
775 for (LayerGroup *group : groups) {
776 grease_pencil.remove_group(*group, true);
777 }
778
779 const Span<const Layer *> layers = grease_pencil.layers();
781 for (const int layer_i : layers.index_range()) {
782 const Layer &layer = grease_pencil.layer(layer_i);
783 if (!layer.is_child_of(active_group)) {
784 src_layer_indices_by_dst_layer.append({layer_i});
785 }
786 else {
787 indices.append(layer_i);
788 }
789 }
790 src_layer_indices_by_dst_layer.append(indices);
791
792 /* Store the name of the group as the name of the merged layer. */
793 merged_layer_name = active_group.name();
794
795 /* Remove the active group. */
796 grease_pencil.remove_group(active_group, true);
798 &grease_pencil.id,
799 &grease_pencil,
800 GreasePencilv3LayerGroup,
801 active);
802
803 /* Rename the first node so that the merged layer will have the name of the group. */
804 grease_pencil.rename_node(
805 *bmain, grease_pencil.layer(indices[0]).as_node(), merged_layer_name);
806 }
807 else if (mode == MergeMode::All) {
808 if (grease_pencil.layers().is_empty()) {
809 return OPERATOR_CANCELLED;
810 }
811 /* Remove all groups, keep the layers. */
812 Array<LayerGroup *> groups = grease_pencil.layer_groups_for_write();
813 for (LayerGroup *group : groups) {
814 grease_pencil.remove_group(*group, true);
815 }
816
818 for (const int layer_i : grease_pencil.layers().index_range()) {
819 indices.append(layer_i);
820 }
821 src_layer_indices_by_dst_layer.append(indices);
822
823 merged_layer_name = N_("Layer");
824 grease_pencil.rename_node(
825 *bmain, grease_pencil.layer(indices[0]).as_node(), merged_layer_name);
826 }
827 else {
829 }
830
831 GreasePencil *merged_grease_pencil = BKE_grease_pencil_new_nomain();
832 BKE_grease_pencil_copy_parameters(grease_pencil, *merged_grease_pencil);
834 grease_pencil, src_layer_indices_by_dst_layer, *merged_grease_pencil);
835 BKE_grease_pencil_nomain_to_grease_pencil(merged_grease_pencil, &grease_pencil);
836
838 CTX_wm_message_bus(C), &grease_pencil.id, &grease_pencil, GreasePencilv3, layers);
839
840 /* Try to set the active (merged) layer. */
841 TreeNode *node = grease_pencil.find_node_by_name(merged_layer_name);
842 if (node && node->is_layer()) {
843 Layer &layer = node->as_layer();
844 grease_pencil.set_active_layer(&layer);
845
847 CTX_wm_message_bus(C), &grease_pencil.id, &grease_pencil, GreasePencilv3Layers, active);
848 }
849
850 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
852
853 return OPERATOR_FINISHED;
854}
855
857{
858 static const EnumPropertyItem merge_modes[] = {
859 {int(MergeMode::Down),
860 "ACTIVE",
861 0,
862 "Active",
863 "Combine the active layer with the layer just below (if it exists)"},
864 {int(MergeMode::Group),
865 "GROUP",
866 0,
867 "Group",
868 "Combine layers in the active group into a single layer"},
869 {int(MergeMode::All), "ALL", 0, "All", "Combine all layers into a single layer"},
870 {0, nullptr, 0, nullptr, nullptr},
871 };
872
873 ot->name = "Merge";
874 ot->idname = "GREASE_PENCIL_OT_layer_merge";
875 ot->description = "Combine layers based on the mode into one layer";
876
879
881
882 ot->prop = RNA_def_enum(ot->srna, "mode", merge_modes, int(MergeMode::Down), "Mode", "");
883}
884
886{
887 using namespace blender::bke::greasepencil;
889
890 if (!grease_pencil.has_active_layer()) {
891 return OPERATOR_CANCELLED;
892 }
893 Layer &active_layer = *grease_pencil.get_active_layer();
894
895 int mask_name_length;
896 char *mask_name = RNA_string_get_alloc(op->ptr, "name", nullptr, 0, &mask_name_length);
897 BLI_SCOPED_DEFER([&] { MEM_SAFE_FREE(mask_name); });
898
899 if (TreeNode *node = grease_pencil.find_node_by_name(mask_name)) {
900 if (grease_pencil.is_layer_active(&node->as_layer())) {
901 BKE_report(op->reports, RPT_ERROR, "Cannot add active layer as mask");
902 return OPERATOR_CANCELLED;
903 }
904
905 if (BLI_findstring_ptr(&active_layer.masks,
906 mask_name,
907 offsetof(GreasePencilLayerMask, layer_name)) != nullptr)
908 {
909 BKE_report(op->reports, RPT_ERROR, "Layer already added");
910 return OPERATOR_CANCELLED;
911 }
912
913 LayerMask *new_mask = MEM_new<LayerMask>(__func__, mask_name);
914 BLI_addtail(&active_layer.masks, reinterpret_cast<GreasePencilLayerMask *>(new_mask));
915 /* Make the newly added mask active. */
916 active_layer.active_mask_index = BLI_listbase_count(&active_layer.masks) - 1;
917 }
918 else {
919 BKE_report(op->reports, RPT_ERROR, "Unable to find layer to add");
920 return OPERATOR_CANCELLED;
921 }
922
923 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
925
926 return OPERATOR_FINISHED;
927}
928
930{
931 /* identifiers */
932 ot->name = "Add New Mask Layer";
933 ot->idname = "GREASE_PENCIL_OT_layer_mask_add";
934 ot->description = "Add new layer as masking";
935
937
938 /* callbacks */
941
942 /* properties */
943 RNA_def_string(ot->srna, "name", nullptr, 0, "Layer", "Name of the layer");
944}
945
947{
948 using namespace blender::bke::greasepencil;
950 return false;
951 }
952
954 Layer &active_layer = *grease_pencil.get_active_layer();
955
956 return !BLI_listbase_is_empty(&active_layer.masks);
957}
958
960{
961 using namespace blender::bke::greasepencil;
963
964 if (!grease_pencil.has_active_layer()) {
965 return OPERATOR_CANCELLED;
966 }
967
968 Layer &active_layer = *grease_pencil.get_active_layer();
969 if (GreasePencilLayerMask *mask = reinterpret_cast<GreasePencilLayerMask *>(
970 BLI_findlink(&active_layer.masks, active_layer.active_mask_index)))
971 {
972 BLI_remlink(&active_layer.masks, mask);
973 MEM_delete(reinterpret_cast<LayerMask *>(mask));
974 active_layer.active_mask_index = std::max(active_layer.active_mask_index - 1, 0);
975 }
976 else {
977 return OPERATOR_CANCELLED;
978 }
979
980 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
982
983 return OPERATOR_FINISHED;
984}
985
987{
988 /* identifiers */
989 ot->name = "Remove Mask Layer";
990 ot->idname = "GREASE_PENCIL_OT_layer_mask_remove";
991 ot->description = "Remove Layer Mask";
992
994
995 /* callbacks */
998}
999
1001{
1002 using namespace blender::bke::greasepencil;
1004 return false;
1005 }
1006
1008 Layer &active_layer = *grease_pencil.get_active_layer();
1009
1010 return BLI_listbase_count(&active_layer.masks) > 1;
1011}
1012
1014{
1015 using namespace blender::bke::greasepencil;
1017
1018 if (!grease_pencil.has_active_layer()) {
1019 return OPERATOR_CANCELLED;
1020 }
1021 Layer &active_layer = *grease_pencil.get_active_layer();
1022 const int direction = RNA_enum_get(op->ptr, "direction");
1023
1024 bool changed = false;
1025 if (GreasePencilLayerMask *mask = reinterpret_cast<GreasePencilLayerMask *>(
1026 BLI_findlink(&active_layer.masks, active_layer.active_mask_index)))
1027 {
1028 if (BLI_listbase_link_move(&active_layer.masks, mask, direction)) {
1029 active_layer.active_mask_index = std::max(active_layer.active_mask_index + direction, 0);
1030 changed = true;
1031 }
1032 }
1033 else {
1034 return OPERATOR_CANCELLED;
1035 }
1036
1037 if (changed) {
1038 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
1040 }
1041
1042 return OPERATOR_FINISHED;
1043}
1044
1046{
1047 /* identifiers */
1048 ot->name = "Reorder Grease Pencil Layer Mask";
1049 ot->idname = "GREASE_PENCIL_OT_layer_mask_reorder";
1050 ot->description = "Reorder the active Grease Pencil mask layer up/down in the list";
1051
1052 /* API callbacks. */
1055
1056 /* flags */
1057 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1058
1059 ot->prop = RNA_def_enum(ot->srna, "direction", enum_layer_move_direction, 0, "Direction", "");
1060}
1061
1063 {LAYERGROUP_COLOR_NONE, "NONE", ICON_X, "Set Default icon", ""},
1064 {LAYERGROUP_COLOR_01, "COLOR1", ICON_LAYERGROUP_COLOR_01, "Color tag 1", ""},
1065 {LAYERGROUP_COLOR_02, "COLOR2", ICON_LAYERGROUP_COLOR_02, "Color tag 2", ""},
1066 {LAYERGROUP_COLOR_03, "COLOR3", ICON_LAYERGROUP_COLOR_03, "Color tag 3", ""},
1067 {LAYERGROUP_COLOR_04, "COLOR4", ICON_LAYERGROUP_COLOR_04, "Color tag 4", ""},
1068 {LAYERGROUP_COLOR_05, "COLOR5", ICON_LAYERGROUP_COLOR_05, "Color tag 5", ""},
1069 {LAYERGROUP_COLOR_06, "COLOR6", ICON_LAYERGROUP_COLOR_06, "Color tag 6", ""},
1070 {LAYERGROUP_COLOR_07, "COLOR7", ICON_LAYERGROUP_COLOR_07, "Color tag 7", ""},
1071 {LAYERGROUP_COLOR_08, "COLOR8", ICON_LAYERGROUP_COLOR_08, "Color tag 8", ""},
1072 {0, nullptr, 0, nullptr, nullptr},
1073};
1074
1076{
1077 using namespace blender::bke::greasepencil;
1079
1080 const int color_tag = RNA_enum_get(op->ptr, "color_tag");
1081 LayerGroup *active_group = grease_pencil.get_active_group();
1082 active_group->color_tag = color_tag;
1083
1084 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
1086
1087 return OPERATOR_FINISHED;
1088}
1089
1091{
1092 /* identifiers */
1093 ot->name = "Grease Pencil Group Color Tag";
1094 ot->idname = "GREASE_PENCIL_OT_layer_group_color_tag";
1095 ot->description = "Change layer group icon";
1096
1099
1100 ot->flag = OPTYPE_UNDO;
1101
1102 ot->prop = RNA_def_enum(ot->srna, "color_tag", enum_layergroup_color_items, 0, "Color Tag", "");
1103}
1104
1106 All = 0,
1108};
1109
1110static void duplicate_layer_and_frames(GreasePencil &dst_grease_pencil,
1111 const GreasePencil &src_grease_pencil,
1112 const blender::bke::greasepencil::Layer &src_layer,
1113 const DuplicateCopyMode copy_frame_mode,
1114 const int current_frame)
1115{
1116 using namespace blender::bke::greasepencil;
1117
1118 if (&dst_grease_pencil == &src_grease_pencil) {
1119 /* Duplicating frames is valid if copying from the same object.
1120 * The resulting frames will reference existing drawings, which is more efficient than making
1121 * full copies. */
1122 Layer &dst_layer = dst_grease_pencil.duplicate_layer(src_layer);
1123
1124 dst_layer.frames_for_write().clear();
1125 for (const auto [frame_number, frame] : src_layer.frames().items()) {
1126 if ((copy_frame_mode == DuplicateCopyMode::Active) &&
1127 (&frame != src_layer.frame_at(current_frame)))
1128 {
1129 continue;
1130 }
1131 const int duration = src_layer.get_frame_duration_at(frame_number);
1132
1133 Drawing *dst_drawing = dst_grease_pencil.insert_frame(
1134 dst_layer, frame_number, duration, eBezTriple_KeyframeType(frame.type));
1135 if (dst_drawing != nullptr) {
1136 /* Duplicate drawing. */
1137 const Drawing &src_drawing = *src_grease_pencil.get_drawing_at(src_layer, frame_number);
1138 *dst_drawing = src_drawing;
1139 }
1140 }
1141 }
1142 else {
1143 /* When copying from another object a new layer is created and all drawings are copied. */
1144 const int src_layer_index = *src_grease_pencil.get_layer_index(src_layer);
1145
1146 Layer &dst_layer = dst_grease_pencil.add_layer(src_layer.name());
1147 const int dst_layer_index = dst_grease_pencil.layers().size() - 1;
1148
1149 BKE_grease_pencil_copy_layer_parameters(src_layer, dst_layer);
1150
1151 const bke::AttributeAccessor src_attributes = src_grease_pencil.attributes();
1152 bke::MutableAttributeAccessor dst_attributes = dst_grease_pencil.attributes_for_write();
1153 src_attributes.foreach_attribute([&](const bke::AttributeIter &iter) {
1154 if (iter.domain != bke::AttrDomain::Layer) {
1155 return;
1156 }
1157 bke::GAttributeReader reader = src_attributes.lookup(iter.name, iter.domain, iter.data_type);
1158 BLI_assert(reader);
1159 bke::GAttributeWriter writer = dst_attributes.lookup_or_add_for_write(
1160 iter.name, iter.domain, iter.data_type);
1161 if (writer) {
1162 const CPPType &cpptype = *bke::custom_data_type_to_cpp_type(iter.data_type);
1163 BUFFER_FOR_CPP_TYPE_VALUE(cpptype, buffer);
1164 reader.varray.get(src_layer_index, buffer);
1165 writer.varray.set_by_copy(dst_layer_index, buffer);
1166 }
1167 writer.finish();
1168 });
1169
1170 std::optional<int> frame_select = std::nullopt;
1171 if (copy_frame_mode == DuplicateCopyMode::Active) {
1172 frame_select = current_frame;
1173 }
1174 dst_grease_pencil.copy_frames_from_layer(
1175 dst_layer, src_grease_pencil, src_layer, frame_select);
1176 }
1177}
1178
1180{
1181 using namespace blender::bke::greasepencil;
1182 Object *src_object = CTX_data_active_object(C);
1183 const Scene *scene = CTX_data_scene(C);
1184 const int current_frame = scene->r.cfra;
1185 const GreasePencil &src_grease_pencil = *static_cast<GreasePencil *>(src_object->data);
1186 const bool only_active = RNA_boolean_get(op->ptr, "only_active");
1187 const DuplicateCopyMode copy_frame_mode = DuplicateCopyMode(RNA_enum_get(op->ptr, "mode"));
1188
1189 CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
1190 if (ob == src_object || ob->type != OB_GREASE_PENCIL) {
1191 continue;
1192 }
1193 GreasePencil &dst_grease_pencil = *static_cast<GreasePencil *>(ob->data);
1194
1195 if (only_active) {
1196 const Layer &active_layer = *src_grease_pencil.get_active_layer();
1198 dst_grease_pencil, src_grease_pencil, active_layer, copy_frame_mode, current_frame);
1199 }
1200 else {
1201 for (const Layer *layer : src_grease_pencil.layers()) {
1203 dst_grease_pencil, src_grease_pencil, *layer, copy_frame_mode, current_frame);
1204 }
1205 }
1206
1207 DEG_id_tag_update(&dst_grease_pencil.id, ID_RECALC_GEOMETRY);
1209 }
1211
1212 return OPERATOR_FINISHED;
1213}
1214
1216{
1217 /* identifiers */
1218 ot->name = "Duplicate Layer to New Object";
1219 ot->idname = "GREASE_PENCIL_OT_layer_duplicate_object";
1220 ot->description = "Make a copy of the active Grease Pencil layer to selected object";
1221
1222 /* API callbacks. */
1225
1226 /* flags */
1227 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1228
1229 RNA_def_boolean(ot->srna,
1230 "only_active",
1231 true,
1232 "Only Active",
1233 "Copy only active Layer, uncheck to append all layers");
1234
1235 static const EnumPropertyItem copy_mode[] = {
1236 {int(DuplicateCopyMode::All), "ALL", 0, "All Frames", ""},
1237 {int(DuplicateCopyMode::Active), "ACTIVE", 0, "Active Frame", ""},
1238 {0, nullptr, 0, nullptr, nullptr},
1239 };
1240
1241 ot->prop = RNA_def_enum(ot->srna, "mode", copy_mode, 0, "Mode", "");
1242}
1243
1244} // namespace blender::ed::greasepencil
1245
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
#define CTX_DATA_BEGIN(C, Type, instance, member)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
#define CTX_DATA_END
wmMsgBus * CTX_wm_message_bus(const bContext *C)
Low-level operations for grease pencil.
void BKE_grease_pencil_copy_parameters(const GreasePencil &src, GreasePencil &dst)
void BKE_grease_pencil_nomain_to_grease_pencil(GreasePencil *grease_pencil_src, GreasePencil *grease_pencil_dst)
GreasePencil * BKE_grease_pencil_new_nomain()
void BKE_grease_pencil_copy_layer_parameters(const blender::bke::greasepencil::Layer &src, blender::bke::greasepencil::Layer &dst)
General operations, lookup, etc. for blender objects.
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BUFFER_FOR_CPP_TYPE_VALUE(type, variable_name)
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
void void void bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL()
Definition listbase.cc:436
void * BLI_findstring_ptr(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:651
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
void copy_m4_m4(float m1[4][4], const float m2[4][4])
void unit_m4(float m[4][4])
#define BLI_SCOPED_DEFER(function_to_defer)
char * BLI_strdup_null(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_MALLOC
Definition string.cc:46
#define CTX_IFACE_(context, msgid)
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
@ BONE_RELATIVE_PARENTING
eBezTriple_KeyframeType
@ LAYERGROUP_COLOR_01
@ LAYERGROUP_COLOR_NONE
@ LAYERGROUP_COLOR_06
@ LAYERGROUP_COLOR_04
@ LAYERGROUP_COLOR_05
@ LAYERGROUP_COLOR_03
@ LAYERGROUP_COLOR_08
@ LAYERGROUP_COLOR_07
@ LAYERGROUP_COLOR_02
@ OB_GREASE_PENCIL
@ OB_ARMATURE
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
@ PROP_HIDDEN
Definition RNA_types.hh:324
#define C
Definition RandGen.cpp:29
#define NC_GEOM
Definition WM_types.hh:390
#define ND_DATA
Definition WM_types.hh:506
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NA_EDITED
Definition WM_types.hh:581
#define NC_GPENCIL
Definition WM_types.hh:396
#define NA_SELECTED
Definition WM_types.hh:586
void clear()
Definition BLI_map.hh:1038
ItemIterator items() const &
Definition BLI_map.hh:902
void get(int64_t index, void *r_value) const
void set_by_copy(int64_t index, const void *value)
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr const char * c_str() const
void append(const T &value)
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
GAttributeReader lookup(const StringRef attribute_id) const
GAttributeWriter lookup_or_add_for_write(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
Span< const Layer * > layers() const
const Map< FramesMapKeyT, GreasePencilFrame > & frames() const
const GreasePencilFrame * frame_at(const int frame_number) const
int get_frame_duration_at(const int frame_number) const
Map< FramesMapKeyT, GreasePencilFrame > & frames_for_write()
const LayerGroup & as_group() const
const LayerGroup * parent_group() const
#define offsetof(t, d)
static ushort indices[]
#define INT16_MAX
#define active
MatBase< C, R > inverse(MatBase< C, R >) RET
#define MEM_SAFE_FREE(v)
void ED_operatortypes_grease_pencil_layers()
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
const CPPType * custom_data_type_to_cpp_type(eCustomDataType type)
static void GREASE_PENCIL_OT_layer_lock_all(wmOperatorType *ot)
static wmOperatorStatus grease_pencil_layer_mask_reorder_exec(bContext *C, wmOperator *op)
static wmOperatorStatus grease_pencil_layer_mask_remove_exec(bContext *C, wmOperator *)
static bool grease_pencil_layer_mask_reorder_poll(bContext *C)
static wmOperatorStatus grease_pencil_layer_move_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem enum_layer_move_direction[]
static wmOperatorStatus grease_pencil_layer_hide_exec(bContext *C, wmOperator *op)
static wmOperatorStatus grease_pencil_layer_add_invoke(bContext *C, wmOperator *op, const wmEvent *event)
GreasePencil * from_context(bContext &C)
static void GREASE_PENCIL_OT_layer_group_add(wmOperatorType *ot)
static wmOperatorStatus grease_pencil_layer_group_add_exec(bContext *C, wmOperator *op)
void grease_pencil_layer_parent_clear(bke::greasepencil::Layer &layer, const bool keep_transform)
static wmOperatorStatus grease_pencil_merge_layer_exec(bContext *C, wmOperator *op)
static wmOperatorStatus grease_pencil_layer_active_exec(bContext *C, wmOperator *op)
static void GREASE_PENCIL_OT_layer_group_color_tag(wmOperatorType *ot)
static float4x4 get_bone_mat(const Object *parent, const char *parsubstr)
static void GREASE_PENCIL_OT_layer_remove(wmOperatorType *ot)
static void GREASE_PENCIL_OT_layer_isolate(wmOperatorType *ot)
static wmOperatorStatus grease_pencil_layer_duplicate_object_exec(bContext *C, wmOperator *op)
static void GREASE_PENCIL_OT_layer_hide(wmOperatorType *ot)
static void GREASE_PENCIL_OT_layer_merge(wmOperatorType *ot)
static void GREASE_PENCIL_OT_layer_add(wmOperatorType *ot)
static bool grease_pencil_layer_mask_poll(bContext *C)
static wmOperatorStatus grease_pencil_layer_add_exec(bContext *C, wmOperator *op)
bool editable_grease_pencil_poll(bContext *C)
static void GREASE_PENCIL_OT_layer_mask_add(wmOperatorType *ot)
static wmOperatorStatus grease_pencil_layer_mask_add_exec(bContext *C, wmOperator *op)
static wmOperatorStatus grease_pencil_layer_remove_exec(bContext *C, wmOperator *)
static void GREASE_PENCIL_OT_layer_active(wmOperatorType *ot)
const EnumPropertyItem enum_layergroup_color_items[]
static void GREASE_PENCIL_OT_layer_move(wmOperatorType *ot)
static wmOperatorStatus grease_pencil_layer_lock_all_exec(bContext *C, wmOperator *op)
static void GREASE_PENCIL_OT_layer_duplicate_object(wmOperatorType *ot)
static void GREASE_PENCIL_OT_layer_group_remove(wmOperatorType *ot)
static void GREASE_PENCIL_OT_layer_duplicate(wmOperatorType *ot)
static wmOperatorStatus grease_pencil_layer_group_remove_exec(bContext *C, wmOperator *op)
bool grease_pencil_layer_parent_set(bke::greasepencil::Layer &layer, Object *parent, StringRefNull bone, const bool keep_transform)
bool grease_pencil_context_poll(bContext *C)
static wmOperatorStatus grease_pencil_layer_duplicate_exec(bContext *C, wmOperator *op)
static void GREASE_PENCIL_OT_layer_mask_reorder(wmOperatorType *ot)
void merge_layers(const GreasePencil &src_grease_pencil, const Span< Vector< int > > src_layer_indices_by_dst_layer, GreasePencil &dst_grease_pencil)
bool active_grease_pencil_layer_group_poll(bContext *C)
static wmOperatorStatus grease_pencil_layer_group_color_tag_exec(bContext *C, wmOperator *op)
void select_layer_channel(GreasePencil &grease_pencil, bke::greasepencil::Layer *layer)
static void GREASE_PENCIL_OT_layer_reveal(wmOperatorType *ot)
bool active_grease_pencil_layer_poll(bContext *C)
static wmOperatorStatus grease_pencil_layer_reveal_exec(bContext *C, wmOperator *)
static void GREASE_PENCIL_OT_layer_mask_remove(wmOperatorType *ot)
static void duplicate_layer_and_frames(GreasePencil &dst_grease_pencil, const GreasePencil &src_grease_pencil, const blender::bke::greasepencil::Layer &src_layer, const DuplicateCopyMode copy_frame_mode, const int current_frame)
static wmOperatorStatus grease_pencil_layer_isolate_exec(bContext *C, wmOperator *op)
static bool grease_pencil_layer_move_poll(bContext *C)
CartesianBasis invert(const CartesianBasis &basis)
MatBase< float, 4, 4 > float4x4
int RNA_int_get(PointerRNA *ptr, const char *name)
char * RNA_string_get_alloc(PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen, int *r_len)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
struct GreasePencilLayerTreeNode * prev
struct bPose * pose
struct RenderData r
struct Bone * bone
float chan_mat[4][4]
float pose_mat[4][4]
struct ReportList * reports
struct PointerRNA * ptr
#define N_(msgid)
void WM_main_add_notifier(uint type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4225
#define WM_msg_publish_rna_prop(mbus, id_, data_, type_, prop_)
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))
wmOperatorStatus WM_operator_props_popup_confirm_ex(bContext *C, wmOperator *op, const wmEvent *, std::optional< std::string > title, std::optional< std::string > confirm_text, const bool cancel_default)