42 if (frame.is_selected()) {
43 frame.type = key_type;
44 layer.tag_frames_map_changed();
58 float secf = (scene.r.frs_sec / scene.r.frs_sec_base);
59 return floorf(frame_number / secf + 0.5f) * secf;
76 for (
auto [frame_number, frame] : layer.frames().items()) {
77 if (!frame.is_selected()) {
82 if (snapped != frame_number) {
83 frame_number_destinations.
add(frame_number, snapped);
89 grease_pencil.move_frames(layer, frame_number_destinations);
102 return 2 * scene.r.cfra - frame_number;
105 return -frame_number;
107 if (first_selected_marker ==
nullptr) {
110 return 2 * first_selected_marker->
frame - frame_number;
122 bool changed =
false;
130 for (
auto [frame_number, frame] : layer.frames().items()) {
131 if (!frame.is_selected()) {
136 frame_number, scene, mode, first_selected_marker);
138 if (mirrored_frame_number != frame_number) {
139 frame_number_destinations.
add(frame_number, mirrored_frame_number);
145 grease_pencil.move_frames(layer, frame_number_destinations);
153 using namespace bke::greasepencil;
154 bool changed =
false;
155 LayerTransformData &trans_data = layer.
runtime->trans_data_;
157 for (
auto [frame_number, frame] : layer.frames_for_write().items()) {
158 if (!frame.is_selected()) {
163 const Drawing *drawing = grease_pencil.get_editable_drawing_at(layer, frame_number);
164 if (drawing ==
nullptr) {
167 const int duplicated_drawing_index = grease_pencil.drawings().size();
168 grease_pencil.add_duplicate_drawings(1, *drawing);
173 trans_data.duplicated_frames_buffer.add_overwrite(frame_number, frame_duplicate);
182 layer.tag_frames_map_changed();
191 for (
auto [frame_number, frame] : layer.frames().items()) {
192 if (!frame.is_selected()) {
195 frames_to_remove.
append(frame_number);
197 return grease_pencil.remove_frames(layer, frames_to_remove.
as_span());
202 switch (select_mode) {
207 frame.
flag &= ~GP_FRAME_SELECTED;
216 const int frame_number,
217 const short select_mode)
221 if (frame ==
nullptr) {
225 layer.tag_frames_map_changed();
230 const int frame_number,
231 const short select_mode)
235 if (node.is_group()) {
238 else if (node.is_layer()) {
246 for (
auto item : layer.frames_for_write().items()) {
248 layer.tag_frames_map_changed();
254 for (
const auto &[frame_number, frame] : layer.frames().items()) {
255 if (frame.is_selected()) {
265 const short select_mode)
267 if (node.is_layer()) {
268 for (
auto [frame_number, frame] : node.as_layer().frames_for_write().items()) {
287 node.as_layer().tag_frames_map_changed();
290 else if (node.is_group()) {
300 const short select_mode)
303 if (node.is_layer()) {
304 for (
auto [frame_number, frame] : node.as_layer().frames_for_write().items()) {
307 node.as_layer().tag_frames_map_changed();
311 else if (node.is_group()) {
319 const int frame_number,
322 CfraElem *ce = MEM_cnew<CfraElem>(__func__);
324 ce->
sel = frame.is_selected();
333 for (
const auto &[frame_number, frame] : layer.frames().items()) {
334 if (frame.is_selected()) {
343 const bool duplicate_previous_key,
344 bool &r_inserted_keyframe)
346 const int current_frame = scene.r.cfra;
353 const bool is_first = layer.is_empty() || (layer.sorted_keys().first() > current_frame);
354 const std::optional<int> previous_key_frame_start = layer.start_frame_at(current_frame);
355 const bool has_previous_key = previous_key_frame_start.has_value();
356 const bool needs_new_drawing = is_first || !has_previous_key ||
357 (previous_key_frame_start < current_frame);
359 const bool use_additive_drawing = (scene.toolsettings->gpencil_flags &
361 if (has_previous_key && (use_additive_drawing || duplicate_previous_key)) {
363 grease_pencil.insert_duplicate_frame(layer, *previous_key_frame_start, current_frame,
false);
367 grease_pencil.insert_frame(layer, current_frame);
369 r_inserted_keyframe =
true;
372 BLI_assert(layer.has_drawing_at(current_frame));
382 const int current_frame = scene->r.cfra;
386 bool changed =
false;
388 for (
Layer *layer : grease_pencil.layers_for_write()) {
389 if (!layer->is_editable()) {
392 changed |= grease_pencil.insert_frame(*layer, current_frame, duration) !=
nullptr;
396 if (!grease_pencil.has_active_layer()) {
399 changed |= grease_pencil.insert_frame(
400 *grease_pencil.get_active_layer(), current_frame, duration) !=
nullptr;
426 if (attrs_span_a.
data() == attrs_span_b.
data()) {
438 const std::optional<T> value_a = attributes_a.
get_if_single();
439 const std::optional<T> value_b = attributes_b.
get_if_single();
440 if (value_a.has_value() && value_b.has_value()) {
441 return value_a.value() == value_b.value();
448 attrs_span_a.
begin(), attrs_span_a.
end(), attrs_span_b.
begin(), attrs_span_b.
end());
471 if (ids_a != ids_b) {
487 bool attributes_are_equal =
true;
489 attribute_math::convert_to_static_type(attrs_a.
varray.
type(), [&](
auto dummy) {
490 using T = decltype(dummy);
492 const VArray attributes_a = attrs_a.varray.typed<T>();
493 const VArray attributes_b = attrs_b.varray.typed<T>();
495 attributes_are_equal = attributes_elements_are_equal(attributes_a, attributes_b);
498 if (!attributes_are_equal) {
513 bool changed =
false;
515 for (
Layer *layer : grease_pencil.layers_for_write()) {
516 if (!layer->is_editable()) {
521 for (
const FramesMapKeyT key : layer->sorted_keys()) {
523 if (selected && !frame->is_selected()) {
526 if (frame->is_end()) {
529 start_frame_numbers.
append(
int(key));
534 const int current = start_frame_numbers[i];
535 const int next = start_frame_numbers[i + 1];
537 Drawing *drawing = grease_pencil.get_drawing_at(*layer, current);
538 Drawing *drawing_next = grease_pencil.get_drawing_at(*layer,
next);
540 if (!drawing || !drawing_next) {
554 grease_pencil.remove_frames(*layer, frame_numbers_to_delete.
as_span());
573 ot->
name =
"Insert Blank Frame";
574 ot->
idname =
"GREASE_PENCIL_OT_insert_blank_frame";
575 ot->
description =
"Insert a blank frame on the current scene frame";
585 ot->
srna,
"all_layers",
false,
"All Layers",
"Insert a blank frame in all editable layers");
595 ot->
name =
"Delete Duplicate Frames";
596 ot->
idname =
"GREASE_PENCIL_OT_frame_clean_duplicate";
597 ot->
description =
"Remove any keyframe that is a duplicate of the previous one";
607 ot->
srna,
"selected",
false,
"Selected",
"Only delete selected keyframes");
613 using namespace bke::greasepencil;
620 ListBase anim_data = {
nullptr,
nullptr};
633 Layer *layer =
reinterpret_cast<Layer *
>(ale->data);
635 FramesMapKeyT layer_first_frame = std::numeric_limits<int>::max();
636 FramesMapKeyT layer_last_frame = std::numeric_limits<int>::min();
637 for (
auto [frame_number, frame] : layer->frames().items()) {
638 if (frame.is_selected()) {
639 const Drawing *drawing = grease_pencil->get_drawing_at(*layer, frame_number);
640 const int duration = layer->get_frame_duration_at(frame_number);
645 if (frame_number < layer_first_frame) {
646 layer_first_frame = frame_number;
648 if (frame_number > layer_last_frame) {
649 layer_last_frame = frame_number;
655 clipboard.
copy_buffer.add_new(layer->name(), {buf, layer_first_frame, layer_last_frame});
660 if (layer_last_frame > clipboard.
last_frame) {
681 switch (offset_mode) {
689 offset = (cfra - clipboard.
cfra);
703 using namespace bke::greasepencil;
714 ListBase anim_data = {
nullptr,
nullptr};
720 const bool from_single_channel = clipboard.
copy_buffer.size() == 1;
728 Layer &layer = *
reinterpret_cast<Layer *
>(ale->data);
729 const std::string layer_name = layer.name();
730 if (!from_single_channel && !clipboard.
copy_buffer.contains(layer_name)) {
734 from_single_channel ? *clipboard.
copy_buffer.values().begin() :
736 bool changed =
false;
739 switch (merge_mode) {
747 for (
auto frame_number : layer.frames().keys()) {
748 frames_to_remove.
append(frame_number);
750 grease_pencil->remove_frames(layer, frames_to_remove);
756 int frame_min, frame_max;
770 if (frame_min < frame_max) {
772 for (
auto frame_number : layer.frames().keys()) {
773 if (frame_min < frame_number && frame_number < frame_max) {
774 frames_to_remove.
append(frame_number);
777 grease_pencil->remove_frames(layer, frames_to_remove);
784 const int target_frame_number = item.frame_number + offset;
785 if (layer.frames().contains(target_frame_number)) {
786 grease_pencil->remove_frames(layer, {target_frame_number});
788 Drawing &dst_drawing = *grease_pencil->insert_frame(
789 layer, target_frame_number, item.duration, item.keytype);
790 dst_drawing = item.drawing;
812 const int current_frame = scene->r.cfra;
813 bool changed =
false;
816 if (!grease_pencil.has_active_layer()) {
819 Layer &active_layer = *grease_pencil.get_active_layer();
820 const std::optional<int> active_frame_number = active_layer.
start_frame_at(current_frame);
821 changed |= grease_pencil.insert_duplicate_frame(
822 active_layer, active_frame_number.value(), current_frame,
false);
825 for (
Layer *layer : grease_pencil.layers_for_write()) {
826 const std::optional<int> active_frame_number = layer->start_frame_at(current_frame);
827 changed |= grease_pencil.insert_duplicate_frame(
828 *layer, active_frame_number.value(), current_frame,
false);
845 ot->
name =
"Duplicate active Frame(s)";
846 ot->
idname =
"GREASE_PENCIL_OT_frame_duplicate";
847 ot->
description =
"Make a copy of the active Grease Pencil frame(s)";
857 ot->
srna,
"all",
false,
"Duplicate all",
"Duplicate active keyframes of all layer");
867 const int current_frame = scene->r.cfra;
868 bool changed =
false;
871 if (!grease_pencil.has_active_layer()) {
875 Layer &active_layer = *grease_pencil.get_active_layer();
876 if (std::optional<int> active_frame_number = active_layer.
start_frame_at(current_frame)) {
877 changed |= grease_pencil.remove_frames(active_layer, {active_frame_number.value()});
881 for (
Layer *layer : grease_pencil.layers_for_write()) {
882 if (std::optional<int> active_frame_number = layer->start_frame_at(current_frame)) {
883 changed |= grease_pencil.remove_frames(*layer, {active_frame_number.value()});
901 ot->
name =
"Delete active Frame(s)";
902 ot->
idname =
"GREASE_PENCIL_OT_active_frame_delete";
903 ot->
description =
"Delete the active Grease Pencil frame(s)";
Functions to insert, delete or modify keyframes.
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Low-level operations for curves.
Low-level operations for grease pencil.
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
MINLINE int round_fl_to_int(float a)
#define IN_RANGE(a, b, c)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ GP_TOOL_FLAG_RETAIN_LAST
@ ANIMTYPE_GREASE_PENCIL_LAYER
@ ANIMFILTER_DATA_VISIBLE
@ ANIMFILTER_LIST_VISIBLE
@ KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL
@ KEYFRAME_PASTE_MERGE_OVER_RANGE
@ KEYFRAME_PASTE_MERGE_OVER
@ KEYFRAME_PASTE_MERGE_MIX
@ KEYFRAME_PASTE_OFFSET_NONE
@ KEYFRAME_PASTE_OFFSET_CFRA_END
@ KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE
@ KEYFRAME_PASTE_OFFSET_CFRA_START
void ANIM_animdata_freelist(ListBase *anim_data)
size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, const eAnimFilter_Flags filter_mode, void *data, const eAnimCont_Types datatype)
int ED_markers_find_nearest_marker_time(ListBase *markers, float x)
TimeMarker * ED_markers_get_first_selected(ListBase *markers)
const void * data() const
GSpan get_internal_span() const
const CPPType & type() const
constexpr IndexRange drop_back(int64_t n) const
bool add(const Key &key, const Value &value)
constexpr const T * end() const
constexpr const T * begin() const
std::optional< T > get_if_single() const
void append(const T &value)
IndexRange index_range() const
Span< T > as_span() const
GAttributeReader lookup(const StringRef attribute_id) const
Set< StringRefNull > all_ids() const
Span< int > offsets() const
AttributeAccessor attributes() const
bke::CurvesGeometry & strokes_for_write()
std::optional< int > start_frame_at(int frame_number) const
draw_view in_light_buf[] float
void ED_operatortypes_grease_pencil_frames()
bool keyframe_region_lasso_test(const KeyframeEdit_LassoData *data_lasso, const float xy[2])
bool keyframe_region_circle_test(const KeyframeEdit_CircleData *data_circle, const float xy[2])
bool is_autokey_on(const Scene *scene)
void select_frames_at(bke::greasepencil::LayerGroup &layer_group, const int frame_number, const short select_mode)
static int insert_blank_frame_exec(bContext *C, wmOperator *op)
bool active_grease_pencil_poll(bContext *C)
static void GREASE_PENCIL_OT_active_frame_delete(wmOperatorType *ot)
bool remove_all_selected_frames(GreasePencil &grease_pencil, bke::greasepencil::Layer &layer)
bool grease_pencil_copy_keyframes(bAnimContext *ac, KeyframeClipboard &clipboard)
bool grease_pencil_paste_keyframes(bAnimContext *ac, const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, const KeyframeClipboard &clipboard)
bool ensure_active_keyframe(const Scene &scene, GreasePencil &grease_pencil, bke::greasepencil::Layer &layer, const bool duplicate_previous_key, bool &r_inserted_keyframe)
static float get_snapped_frame_number(const float frame_number, Scene &scene, const eEditKeyframes_Snap mode)
void set_selected_frames_type(bke::greasepencil::Layer &layer, const eBezTriple_KeyframeType key_type)
bool mirror_selected_frames(GreasePencil &grease_pencil, bke::greasepencil::Layer &layer, Scene &scene, const eEditKeyframes_Mirror mode)
void select_frames_range(bke::greasepencil::TreeNode &node, const float min, const float max, const short select_mode)
static bool curves_geometry_is_equal(const bke::CurvesGeometry &curves_a, const bke::CurvesGeometry &curves_b)
static int get_mirrored_frame_number(const int frame_number, const Scene &scene, const eEditKeyframes_Mirror mode, const TimeMarker *first_selected_marker)
static void select_frame(GreasePencilFrame &frame, const short select_mode)
void create_keyframe_edit_data_selected_frames_list(KeyframeEditData *ked, const bke::greasepencil::Layer &layer)
void select_frames_region(KeyframeEditData *ked, bke::greasepencil::TreeNode &node, const short tool, const short select_mode)
bool has_any_frame_selected(const bke::greasepencil::Layer &layer)
static int grease_pencil_active_frame_delete_exec(bContext *C, wmOperator *op)
static bool attributes_varrays_not_equal(const bke::GAttributeReader &attrs_a, const bke::GAttributeReader &attrs_b)
static void GREASE_PENCIL_OT_frame_clean_duplicate(wmOperatorType *ot)
static bool attributes_elements_are_equal(const VArray< T > &attributes_a, const VArray< T > &attributes_b)
void select_all_frames(bke::greasepencil::Layer &layer, const short select_mode)
static int grease_pencil_frame_duplicate_exec(bContext *C, wmOperator *op)
static void append_frame_to_key_edit_data(KeyframeEditData *ked, const int frame_number, const GreasePencilFrame &frame)
static void GREASE_PENCIL_OT_insert_blank_frame(wmOperatorType *ot)
static void GREASE_PENCIL_OT_frame_duplicate(wmOperatorType *ot)
bool duplicate_selected_frames(GreasePencil &grease_pencil, bke::greasepencil::Layer &layer)
static int calculate_offset(const eKeyPasteOffset offset_mode, const int cfra, const KeyframeClipboard &clipboard)
static bool attributes_varrays_span_data_equal(const bke::GAttributeReader &attrs_a, const bke::GAttributeReader &attrs_b)
bool select_frame_at(bke::greasepencil::Layer &layer, const int frame_number, const short select_mode)
static int frame_clean_duplicate_exec(bContext *C, wmOperator *op)
bool snap_selected_frames(GreasePencil &grease_pencil, bke::greasepencil::Layer &layer, Scene &scene, const eEditKeyframes_Snap mode)
int RNA_int_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
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)
GreasePencilRuntimeHandle * runtime
blender::bke::greasepencil::FramesMapKeyT last_frame
Vector< DrawingBufferItem > drawing_buffers
blender::bke::greasepencil::FramesMapKeyT first_frame
Map< std::string, LayerBufferItem > copy_buffer
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))