Blender V4.5
action_edit.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cfloat>
10#include <cmath>
11#include <cstdlib>
12#include <cstring>
13
14#include "BLI_listbase.h"
15#include "BLI_map.hh"
16#include "BLI_string.h"
17#include "BLI_utildefines.h"
18
19#include "BLT_translation.hh"
20
21#include "DEG_depsgraph.hh"
22
23#include "DNA_anim_types.h"
25#include "DNA_mask_types.h"
26#include "DNA_scene_types.h"
27
28#include "RNA_access.hh"
29#include "RNA_define.hh"
30#include "RNA_enum_types.hh"
31
32#include "BKE_animsys.h"
33#include "BKE_context.hh"
34#include "BKE_fcurve.hh"
35#include "BKE_global.hh"
36#include "BKE_gpencil_legacy.h"
37#include "BKE_grease_pencil.hh"
38#include "BKE_nla.hh"
39#include "BKE_report.hh"
40
41#include "UI_interface_icons.hh"
42#include "UI_view2d.hh"
43
44#include "ANIM_action.hh"
45#include "ANIM_animdata.hh"
46#include "ANIM_fcurve.hh"
47#include "ANIM_keyframing.hh"
48#include "ED_anim_api.hh"
49#include "ED_gpencil_legacy.hh"
50#include "ED_grease_pencil.hh"
51#include "ED_keyframes_edit.hh"
52#include "ED_keyframing.hh"
53#include "ED_markers.hh"
54#include "ED_mask.hh"
55#include "ED_screen.hh"
56
57#include "WM_api.hh"
58#include "WM_types.hh"
59
60#include "action_intern.hh"
61
62/* -------------------------------------------------------------------- */
65
66/* ensure that there is:
67 * 1) an active action editor
68 * 2) that the mode will have an active action available
69 * 3) that the set of markers being shown are the scene markers, not the list we're merging
70 * 4) that there are some selected markers
71 */
73{
75
76 /* 1) */
77 if (sact == nullptr) {
78 return false;
79 }
80
81 /* 2) */
82 if (ELEM(sact->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY) == 0) {
83 return false;
84 }
85 if (sact->action == nullptr) {
86 return false;
87 }
88
89 /* 3) */
90 if (sact->flag & SACTION_POSEMARKERS_SHOW) {
91 return false;
92 }
93
94 /* 4) */
96}
97
99{
101
103 bAction *act = (sact) ? sact->action : nullptr;
104
105 TimeMarker *marker, *markern = nullptr;
106
107 /* sanity checks */
108 if (ELEM(nullptr, markers, act)) {
109 return OPERATOR_CANCELLED;
110 }
111
112 /* migrate markers */
113 for (marker = static_cast<TimeMarker *>(markers->first); marker; marker = markern) {
114 markern = marker->next;
115
116 /* move if marker is selected */
117 if (marker->flag & SELECT) {
118 BLI_remlink(markers, marker);
119 BLI_addtail(&act->markers, marker);
120 }
121 }
122
123 /* Now enable the "show pose-markers only" setting,
124 * so that we can see that something did happen. */
126
127 /* notifiers - both sets, as this change affects both */
130
131 return OPERATOR_FINISHED;
132}
133
135{
136 /* identifiers */
137 ot->name = "Make Markers Local";
138 ot->idname = "ACTION_OT_markers_make_local";
139 ot->description = "Move selected scene markers to the active Action as local 'pose' markers";
140
141 /* callbacks */
144
145 /* flags */
147}
148
150
151/* -------------------------------------------------------------------- */
154
155/* Get the min/max keyframes. */
156static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const short onlySel)
157{
158 ListBase anim_data = {nullptr, nullptr};
160 bool found = false;
161
162 /* Get data to filter, from Action or Dope-sheet. */
163 /* XXX: what is sel doing here?!
164 * Commented it, was breaking things (eg. the "auto preview range" tool). */
165 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_SEL */ |
167 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
168
169 /* set large values to try to override */
170 *min = 999999999.0f;
171 *max = -999999999.0f;
172
173 /* check if any channels to set range with */
174 if (anim_data.first) {
175 /* go through channels, finding max extents */
176 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
177 if (ale->datatype == ALE_GPFRAME) {
178 bGPDlayer *gpl = static_cast<bGPDlayer *>(ale->data);
179
180 /* Find GP-frame which is less than or equal to current-frame. */
181 LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
182 if (!onlySel || (gpf->flag & GP_FRAME_SELECT)) {
183 const float framenum = float(gpf->framenum);
184 *min = min_ff(*min, framenum);
185 *max = max_ff(*max, framenum);
186 found = true;
187 }
188 }
189 }
190 else if (ale->datatype == ALE_MASKLAY) {
191 MaskLayer *masklay = static_cast<MaskLayer *>(ale->data);
192 /* Find mask layer which is less than or equal to current-frame. */
193 LISTBASE_FOREACH (MaskLayerShape *, masklay_shape, &masklay->splines_shapes) {
194 const float framenum = float(masklay_shape->frame);
195 *min = min_ff(*min, framenum);
196 *max = max_ff(*max, framenum);
197 found = true;
198 }
199 }
200 else if (ale->datatype == ALE_GREASE_PENCIL_CEL) {
202 static_cast<GreasePencilLayer *>(ale->data)->wrap();
203
204 for (const auto [key, frame] : layer.frames().items()) {
205 if (onlySel && !frame.is_selected()) {
206 continue;
207 }
208 *min = min_ff(*min, float(key));
209 *max = max_ff(*max, float(key));
210 found = true;
211 }
212 }
213 else {
214 FCurve *fcu = (FCurve *)ale->key_data;
215 float tmin, tmax;
216
217 /* get range and apply necessary scaling before processing */
218 if (BKE_fcurve_calc_range(fcu, &tmin, &tmax, onlySel)) {
221
222 /* Try to set cur using these values,
223 * if they're more extreme than previously set values. */
224 *min = min_ff(*min, tmin);
225 *max = max_ff(*max, tmax);
226 found = true;
227 }
228 }
229 }
230
231 if (fabsf(*max - *min) < 0.001f) {
232 *min -= 0.0005f;
233 *max += 0.0005f;
234 }
235
236 /* free memory */
237 ANIM_animdata_freelist(&anim_data);
238 }
239 else {
240 /* set default range */
241 if (ac->scene) {
242 *min = float(ac->scene->r.sfra);
243 *max = float(ac->scene->r.efra);
244 }
245 else {
246 *min = -5;
247 *max = 100;
248 }
249 }
250
251 return found;
252}
253
255
256/* -------------------------------------------------------------------- */
259
261{
262 bAnimContext ac;
263 Scene *scene;
264 float min, max;
265
266 /* get editor data */
267 if (ANIM_animdata_get_context(C, &ac) == 0) {
268 return OPERATOR_CANCELLED;
269 }
270 if (ac.scene == nullptr) {
271 return OPERATOR_CANCELLED;
272 }
273
274 /* set the range directly */
275 if (!get_keyframe_extents(&ac, &min, &max, true)) {
276 return OPERATOR_CANCELLED;
277 }
278 scene = ac.scene;
279 scene->r.flag |= SCER_PRV_RANGE;
280 scene->r.psfra = floorf(min);
281 scene->r.pefra = ceilf(max);
282
283 if (scene->r.psfra == scene->r.pefra) {
284 scene->r.pefra = scene->r.psfra + 1;
285 }
286
287 /* set notifier that things have changed */
288 /* XXX err... there's nothing for frame ranges yet, but this should do fine too */
290
291 return OPERATOR_FINISHED;
292}
293
295{
296 /* identifiers */
297 ot->name = "Set Preview Range to Selected";
298 ot->idname = "ACTION_OT_previewrange_set";
299 ot->description = "Set Preview Range based on extents of selected Keyframes";
300
301 /* API callbacks. */
304
305 /* flags */
307}
308
310
311/* -------------------------------------------------------------------- */
314
322static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *r_min, float *r_max)
323{
324 ListBase anim_data = {nullptr, nullptr};
325 bAnimListElem *ale;
327
328 /* NOTE: not bool, since we want prioritize individual channels over expanders. */
329 short found = 0;
330
331 /* get all items - we need to do it this way */
333 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
334
335 /* loop through all channels, finding the first one that's selected */
336 float ymax = ANIM_UI_get_first_channel_top(&ac->region->v2d);
337 const float channel_step = ANIM_UI_get_channel_step();
338 for (ale = static_cast<bAnimListElem *>(anim_data.first); ale;
339 ale = ale->next, ymax -= channel_step)
340 {
342
343 /* must be selected... */
344 if (acf && acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT) &&
346 {
347 /* update best estimate */
348 *r_min = ymax - ANIM_UI_get_channel_height();
349 *r_max = ymax;
350
351 /* is this high enough priority yet? */
352 found = acf->channel_role;
353
354 /* only stop our search when we've found an actual channel
355 * - data-block expanders get less priority so that we don't abort prematurely
356 */
357 if (found == ACHANNEL_ROLE_CHANNEL) {
358 break;
359 }
360 }
361 }
362
363 /* free all temp data */
364 ANIM_animdata_freelist(&anim_data);
365
366 return (found != 0);
367}
368
369static wmOperatorStatus actkeys_viewall(bContext *C, const bool only_sel)
370{
371 bAnimContext ac;
372 View2D *v2d;
373 float min, max;
374 bool found;
375
376 /* get editor data */
377 if (ANIM_animdata_get_context(C, &ac) == 0) {
378 return OPERATOR_CANCELLED;
379 }
380 v2d = &ac.region->v2d;
381
382 /* set the horizontal range, with an extra offset so that the extreme keys will be in view */
383 found = get_keyframe_extents(&ac, &min, &max, only_sel);
384
385 if (only_sel && (found == false)) {
386 return OPERATOR_CANCELLED;
387 }
388
389 if (fabsf(max - min) < 1.0f) {
390 /* Exception - center the single keyframe. */
391 float xwidth = BLI_rctf_size_x(&v2d->cur);
392
393 v2d->cur.xmin = min - xwidth / 2.0f;
394 v2d->cur.xmax = max + xwidth / 2.0f;
395 }
396 else {
397 /* Normal case - stretch the two keyframes out to fill the space, with extra spacing */
398 v2d->cur.xmin = min;
399 v2d->cur.xmax = max;
400
402 }
403
404 /* set vertical range */
405 if (only_sel == false) {
406 /* view all -> the summary channel is usually the shows everything,
407 * and resides right at the top... */
408 v2d->cur.ymax = 0.0f;
409 v2d->cur.ymin = float(-BLI_rcti_size_y(&v2d->mask));
410 }
411 else {
412 /* locate first selected channel (or the active one), and frame those */
413 float ymin = v2d->cur.ymin;
414 float ymax = v2d->cur.ymax;
415
416 if (actkeys_channels_get_selected_extents(&ac, &ymin, &ymax)) {
417 /* recenter the view so that this range is in the middle */
418 float ymid = (ymax - ymin) / 2.0f + ymin;
419 float x_center;
420
421 UI_view2d_center_get(v2d, &x_center, nullptr);
422 UI_view2d_center_set(v2d, x_center, ymid);
423 }
424 }
425
426 /* do View2D syncing */
428
429 /* just redraw this view */
431
432 return OPERATOR_FINISHED;
433}
434
435/* ......... */
436
438{
439 /* whole range */
440 return actkeys_viewall(C, false);
441}
442
444{
445 /* only selected */
446 return actkeys_viewall(C, true);
447}
448
449/* ......... */
450
452{
453 /* identifiers */
454 ot->name = "Frame All";
455 ot->idname = "ACTION_OT_view_all";
456 ot->description = "Reset viewable area to show full keyframe range";
457
458 /* API callbacks. */
459 ot->exec = actkeys_viewall_exec;
461
462 /* flags */
463 ot->flag = 0;
464}
465
467{
468 /* identifiers */
469 ot->name = "Frame Selected";
470 ot->idname = "ACTION_OT_view_selected";
471 ot->description = "Reset viewable area to show selected keyframes range";
472
473 /* API callbacks. */
474 ot->exec = actkeys_viewsel_exec;
476
477 /* flags */
478 ot->flag = 0;
479}
480
482
483/* -------------------------------------------------------------------- */
486
488{
489 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
490 ANIM_center_frame(C, smooth_viewtx);
491
492 return OPERATOR_FINISHED;
493}
494
496{
497 /* identifiers */
498 ot->name = "Go to Current Frame";
499 ot->idname = "ACTION_OT_view_frame";
500 ot->description = "Move the view to the current frame";
501
502 /* API callbacks. */
505
506 /* flags */
507 ot->flag = 0;
508}
509
511
512/* -------------------------------------------------------------------- */
515
516/* NOTE: the backend code for this is shared with the graph editor */
517
519{
520 ListBase anim_data = {nullptr, nullptr};
522
523 /* filter data */
526 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
527
528 /* copy keyframes */
529 const bool ok = copy_animedit_keys(ac, &anim_data);
530
531 /* clean up */
532 ANIM_animdata_freelist(&anim_data);
533
534 return ok;
535}
536
538 const eKeyPasteOffset offset_mode,
539 const eKeyMergeMode merge_mode,
540 bool flip)
541{
542 /* TODO: deduplicate this function and `paste_graph_keys()` in `graph_edit.cc`, */
543
544 /* Determine paste context. */
545 KeyframePasteContext paste_context{};
546 paste_context.offset_mode = offset_mode;
547 /* Value offset is always None because the user cannot see the effect of it. */
549 paste_context.merge_mode = merge_mode;
550 paste_context.flip = flip;
551
552 /* See how many slots are selected to paste into. This determines how slot matching is done:
553 * - Copied from one slot, paste into multiple: duplicate into each slot.
554 * - Otherwise: match slots by name. */
555 {
556 ListBase anim_data = {nullptr, nullptr};
560 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
561 LISTBASE_FOREACH (const bAnimListElem *, ale, &anim_data) {
562 if (ale->datatype == ALE_ACTION_SLOT) {
563 paste_context.num_slots_selected++;
564 }
565 }
566 ANIM_animdata_freelist(&anim_data);
567 }
568
569 /* Find F-Curves to paste into, in two stages.
570 * - First time we try to filter more strictly, allowing only selected channels
571 * to allow copying animation between channels
572 * - Second time, we loosen things up if nothing was found the first time, allowing
573 * users to just paste keyframes back into the original curve again #31670.
574 */
575 ListBase anim_data = {nullptr, nullptr};
576 {
581 ac, &anim_data, filter | ANIMFILTER_SEL, ac->data, ac->datatype);
582 if (paste_context.num_fcurves_selected == 0) {
583 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
584 }
585 }
586
587 const eKeyPasteError ok = paste_animedit_keys(ac, &anim_data, paste_context);
588
589 /* clean up */
590 ANIM_animdata_freelist(&anim_data);
591
592 return ok;
593}
594
595/* ------------------- */
596
602
604{
605 bAnimContext ac;
606
607 /* get editor data */
608 if (ANIM_animdata_get_context(C, &ac) == 0) {
609 return OPERATOR_CANCELLED;
610 }
611
612 /* copy keyframes */
613 if (ac.datatype == ANIMCONT_GPENCIL) {
614 if (ED_gpencil_anim_copybuf_copy(&ac) == false &&
617 {
618 /* check if anything ended up in the buffer */
619 BKE_report(op->reports, RPT_ERROR, "No keyframes copied to the internal clipboard");
620 return OPERATOR_CANCELLED;
621 }
622 }
623 else if (ac.datatype == ANIMCONT_MASK) {
624 /* FIXME: support this case. */
625 BKE_report(op->reports, RPT_ERROR, "Keyframe pasting is not available for mask mode");
626 return OPERATOR_CANCELLED;
627 }
628 else {
629 /* Both copy function needs to be evaluated to account for mixed selection */
630 const bool kf_ok = copy_action_keys(&ac);
631 const bool gpf_ok = ED_gpencil_anim_copybuf_copy(&ac) ||
634
635 if (!kf_ok && !gpf_ok) {
636 BKE_report(op->reports, RPT_ERROR, "No keyframes copied to the internal clipboard");
637 return OPERATOR_CANCELLED;
638 }
639 }
640
641 return OPERATOR_FINISHED;
642}
643
645{
646 /* identifiers */
647 ot->name = "Copy Keyframes";
648 ot->idname = "ACTION_OT_copy";
649 ot->description = "Copy selected keyframes to the internal clipboard";
650
651 /* API callbacks. */
652 ot->exec = actkeys_copy_exec;
654
655 /* flags */
657}
658
660{
661 bAnimContext ac;
662
663 const eKeyPasteOffset offset_mode = eKeyPasteOffset(RNA_enum_get(op->ptr, "offset"));
664 const eKeyMergeMode merge_mode = eKeyMergeMode(RNA_enum_get(op->ptr, "merge"));
665 const bool flipped = RNA_boolean_get(op->ptr, "flipped");
666
667 bool gpframes_inbuf = false;
668
669 /* get editor data */
670 if (ANIM_animdata_get_context(C, &ac) == 0) {
671 return OPERATOR_CANCELLED;
672 }
673
674 /* ac.reports by default will be the global reports list, which won't show warnings */
675 ac.reports = op->reports;
676
677 /* paste keyframes */
678 if (ac.datatype == ANIMCONT_GPENCIL) {
679 if (ED_gpencil_anim_copybuf_paste(&ac, offset_mode) == false &&
681 &ac, offset_mode, merge_mode, get_grease_pencil_keyframe_clipboard()) == false)
682 {
683 BKE_report(op->reports, RPT_ERROR, "No data in the internal clipboard to paste");
684 return OPERATOR_CANCELLED;
685 }
686 }
687 else if (ac.datatype == ANIMCONT_MASK) {
688 /* FIXME: support this case. */
690 RPT_ERROR,
691 "Keyframe pasting is not available for Grease Pencil or mask mode");
692 return OPERATOR_CANCELLED;
693 }
694 else {
695 /* Both paste function needs to be evaluated to account for mixed selection */
696 const eKeyPasteError kf_empty = paste_action_keys(&ac, offset_mode, merge_mode, flipped);
697 /* non-zero return means an error occurred while trying to paste */
698 gpframes_inbuf = ED_gpencil_anim_copybuf_paste(&ac, offset_mode) ||
700 &ac, offset_mode, merge_mode, get_grease_pencil_keyframe_clipboard());
701
702 /* Only report an error if nothing was pasted, i.e. when both FCurve and GPencil failed. */
703 if (!gpframes_inbuf) {
704 switch (kf_empty) {
706 /* FCurve paste was ok, so it's all good. */
707 break;
708
710 BKE_report(op->reports, RPT_ERROR, "No selected F-Curves to paste into");
711 return OPERATOR_CANCELLED;
712
714 BKE_report(op->reports, RPT_ERROR, "No data in the internal clipboard to paste");
715 return OPERATOR_CANCELLED;
716 }
717 }
718 }
719
720 /* Grease Pencil needs extra update to refresh the added keyframes. */
721 if (ac.datatype == ANIMCONT_GPENCIL || gpframes_inbuf) {
723 }
724 /* set notifier that keyframes have changed */
726
727 return OPERATOR_FINISHED;
728}
729
730static std::string actkeys_paste_get_description(bContext * /*C*/,
731 wmOperatorType * /*ot*/,
733{
734 /* Custom description if the 'flipped' option is used. */
735 if (RNA_boolean_get(ptr, "flipped")) {
736 return BLI_strdup(TIP_("Paste keyframes from mirrored bones if they exist"));
737 }
738
739 /* Use the default description in the other cases. */
740 return "";
741}
742
744{
745 PropertyRNA *prop;
746 /* identifiers */
747 ot->name = "Paste Keyframes";
748 ot->idname = "ACTION_OT_paste";
749 ot->description =
750 "Paste keyframes from the internal clipboard for the selected channels, starting on the "
751 "current "
752 "frame";
753
754 /* API callbacks. */
755 // ot->invoke = WM_operator_props_popup; /* Better wait for action redo panel. */
756 ot->get_description = actkeys_paste_get_description;
757 ot->exec = actkeys_paste_exec;
759
760 /* flags */
762
763 /* props */
764 RNA_def_enum(ot->srna,
765 "offset",
768 "Offset",
769 "Paste time offset of keys");
770 RNA_def_enum(ot->srna,
771 "merge",
774 "Type",
775 "Method of merging pasted keys and existing");
776 prop = RNA_def_boolean(
777 ot->srna, "flipped", false, "Flipped", "Paste keyframes from mirrored bones if they exist");
779}
780
782
783/* -------------------------------------------------------------------- */
786
787/* defines for insert keyframes tool */
789 {1, "ALL", 0, "All Channels", ""},
790 {2, "SEL", 0, "Only Selected Channels", ""},
791 /* XXX not in all cases. */
792 {3, "GROUP", 0, "In Active Group", ""},
793 {0, nullptr, 0, nullptr, nullptr},
794};
795
797 bAnimListElem *ale,
798 const eGP_GetFrame_Mode add_frame_mode,
799 bGPdata **gpd_old)
800{
801 Scene *scene = ac->scene;
802 bGPdata *gpd = (bGPdata *)ale->id;
803 bGPDlayer *gpl = (bGPDlayer *)ale->data;
804 BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, add_frame_mode);
805 /* Check if the gpd changes to tag only once. */
806 if (gpd != *gpd_old) {
807 BKE_gpencil_tag(gpd);
808 *gpd_old = gpd;
809 }
810}
811
813 bAnimListElem *ale,
814 const bool hold_previous)
815{
816 using namespace blender::bke::greasepencil;
817 Layer *layer = static_cast<Layer *>(ale->data);
818 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(ale->id);
819 const int current_frame_number = ac->scene->r.cfra;
820
821 if (layer->frames().contains(current_frame_number)) {
822 return;
823 }
824
825 bool changed = false;
826 if (hold_previous) {
827 const std::optional<int> active_frame_number = layer->start_frame_at(current_frame_number);
828 if (!active_frame_number) {
829 /* There is no active frame to hold to, or it's an end frame. Therefore just insert a blank
830 * frame. */
831 changed |= grease_pencil->insert_frame(*layer, current_frame_number) != nullptr;
832 }
833 else {
834 /* Duplicate the active frame. */
835 changed = grease_pencil->insert_duplicate_frame(
836 *layer, *active_frame_number, current_frame_number, false);
837 }
838 }
839 else {
840 /* Insert a blank frame. */
841 changed |= grease_pencil->insert_frame(*layer, current_frame_number) != nullptr;
842 }
843
844 if (changed) {
845 DEG_id_tag_update(&grease_pencil->id, ID_RECALC_GEOMETRY);
846 }
847}
848
850 bAnimListElem *ale,
851 const AnimationEvalContext anim_eval_context,
853{
854 using namespace blender::animrig;
855 FCurve *fcu = (FCurve *)ale->key_data;
856
858 Scene *scene = ac->scene;
859 ToolSettings *ts = scene->toolsettings;
860
861 /* These asserts are ensuring that the fcurve we're keying lives on an Action,
862 * rather than being e.g. an fcurve a driver or NLA Strip. This should
863 * always hold true for this function, since all the other cases take
864 * different code paths before getting here. */
865 BLI_assert(ale->owner == nullptr);
866 BLI_assert(ale->fcurve_owner_id != nullptr);
868
869 bAction *action = reinterpret_cast<bAction *>(ale->fcurve_owner_id);
870 ID *id = action_slot_get_id_for_keying(*ale->bmain, action->wrap(), ale->slot_handle, ale->id);
871
872 /* If we found an unambiguous ID to use for keying the channel, go through the
873 * normal keyframing code path. Otherwise, just directly key the fcurve
874 * itself. */
875 if (id) {
876 const std::optional<blender::StringRefNull> channel_group = fcu->grp ?
877 std::optional(fcu->grp->name) :
878 std::nullopt;
879 PointerRNA id_rna_pointer = RNA_id_pointer_create(id);
881 &id_rna_pointer,
882 channel_group,
883 {{fcu->rna_path, {}, fcu->array_index}},
884 std::nullopt,
885 anim_eval_context,
887 flag);
888 if (result.get_count(SingleKeyingResult::SUCCESS) == 0) {
889 result.generate_reports(reports);
890 }
891 }
892 else {
893 /* TODO: when layered action strips are allowed to have time offsets, that
894 * mapping will need to be handled here. */
895 assert_baklava_phase_1_invariants(action->wrap());
896
897 /* Adjust current frame for NLA-scaling. */
898 const float cfra = ANIM_nla_tweakedit_remap(
899 ale, anim_eval_context.eval_time, NLATIME_CONVERT_UNMAP);
900
901 const float curval = evaluate_fcurve(fcu, cfra);
903 settings.keyframe_type = eBezTriple_KeyframeType(ts->keyframe_type);
904 insert_vert_fcurve(fcu, {cfra, curval}, settings, eInsertKeyFlags(0));
905 }
906
907 ale->update |= ANIM_UPDATE_DEFAULT;
908}
909
910/* this function is responsible for inserting new keyframes */
911static void insert_action_keys(bAnimContext *ac, short mode)
912{
913 ListBase anim_data = {nullptr, nullptr};
915
916 Scene *scene = ac->scene;
917 ToolSettings *ts = scene->toolsettings;
919
920 eGP_GetFrame_Mode add_frame_mode;
921 bGPdata *gpd_old = nullptr;
922
923 /* filter data */
926 if (mode == 2) {
928 }
929 else if (mode == 3) {
931 }
932
933 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
934
935 /* Init keyframing flag. */
937
938 /* GPLayers specific flags */
940 add_frame_mode = GP_GETFRAME_ADD_COPY;
941 }
942 else {
943 add_frame_mode = GP_GETFRAME_ADD_NEW;
944 }
945 const bool grease_pencil_hold_previous = ((ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) != 0);
946
947 /* insert keyframes */
949 ac->depsgraph, float(scene->r.cfra));
950 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
951 switch (ale->type) {
952 case ANIMTYPE_GPLAYER:
953 insert_gpencil_key(ac, ale, add_frame_mode, &gpd_old);
954 break;
955
957 insert_grease_pencil_key(ac, ale, grease_pencil_hold_previous);
958 break;
959
960 case ANIMTYPE_FCURVE:
961 insert_fcurve_key(ac, ale, anim_eval_context, flag);
962 break;
963
964 default:
965 BLI_assert_msg(false, "Keys cannot be inserted into this animation type.");
966 }
967 }
968
969 ANIM_animdata_update(ac, &anim_data);
970 ANIM_animdata_freelist(&anim_data);
971}
972
973/* ------------------- */
974
976{
977 bAnimContext ac;
978 short mode;
979
980 /* get editor data */
981 if (ANIM_animdata_get_context(C, &ac) == 0) {
982 return OPERATOR_CANCELLED;
983 }
984
985 if (ac.datatype == ANIMCONT_MASK) {
986 BKE_report(op->reports, RPT_ERROR, "Insert Keyframes is not yet implemented for this mode");
987 return OPERATOR_CANCELLED;
988 }
989
990 /* what channels to affect? */
991 mode = RNA_enum_get(op->ptr, "type");
992
994
995 /* insert keyframes */
996 insert_action_keys(&ac, mode);
997
998 /* set notifier that keyframes have changed */
999 if (ac.datatype == ANIMCONT_GPENCIL) {
1001 }
1003
1004 return OPERATOR_FINISHED;
1005}
1006
1008{
1009 /* identifiers */
1010 ot->name = "Insert Keyframes";
1011 ot->idname = "ACTION_OT_keyframe_insert";
1012 ot->description = "Insert keyframes for the specified channels";
1013
1014 /* API callbacks. */
1015 ot->invoke = WM_menu_invoke;
1016 ot->exec = actkeys_insertkey_exec;
1018
1019 /* flags */
1020 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1021
1022 /* id-props */
1023 ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_insertkey_types, 0, "Type", "");
1024}
1025
1027
1028/* -------------------------------------------------------------------- */
1031
1033{
1034 ListBase anim_data = {nullptr, nullptr};
1036 bool changed = false;
1037
1038 /* filter data */
1041 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1042
1043 /* loop through filtered data and delete selected keys */
1044 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1045 if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
1046 changed |= duplicate_fcurve_keys((FCurve *)ale->key_data);
1047 }
1048 else if (ale->type == ANIMTYPE_GPLAYER) {
1050 changed |= ED_gpencil_layer_frame_select_check((bGPDlayer *)ale->data);
1051 }
1052 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1054 *reinterpret_cast<GreasePencil *>(ale->id),
1055 static_cast<GreasePencilLayer *>(ale->data)->wrap());
1056 }
1057 else if (ale->type == ANIMTYPE_MASKLAYER) {
1058 changed |= ED_masklayer_frames_duplicate((MaskLayer *)ale->data);
1059 }
1060 else {
1061 BLI_assert(0);
1062 }
1063
1064 ale->update |= ANIM_UPDATE_DEFAULT;
1065 }
1066
1067 ANIM_animdata_update(ac, &anim_data);
1068 ANIM_animdata_freelist(&anim_data);
1069
1070 return changed;
1071}
1072
1073/* ------------------- */
1074
1076{
1077 bAnimContext ac;
1078
1079 /* get editor data */
1080 if (ANIM_animdata_get_context(C, &ac) == 0) {
1081 return OPERATOR_CANCELLED;
1082 }
1083
1084 /* duplicate keyframes */
1085 if (!duplicate_action_keys(&ac)) {
1086 return OPERATOR_CANCELLED;
1087 }
1088
1089 /* set notifier that keyframes have changed */
1091
1092 return OPERATOR_FINISHED;
1093}
1094
1096{
1097 /* identifiers */
1098 ot->name = "Duplicate Keyframes";
1099 ot->idname = "ACTION_OT_duplicate";
1100 ot->description = "Make a copy of all selected keyframes";
1101
1102 /* API callbacks. */
1103 ot->exec = actkeys_duplicate_exec;
1105
1106 /* flags */
1107 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1108}
1109
1111
1112/* -------------------------------------------------------------------- */
1115
1117{
1118 ListBase anim_data = {nullptr, nullptr};
1120 bool changed_final = false;
1121
1122 /* filter data */
1125 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1126
1127 /* loop through filtered data and delete selected keys */
1128 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1129 bool changed = false;
1130
1131 if (ale->type == ANIMTYPE_GPLAYER) {
1132 changed = ED_gpencil_layer_frames_delete((bGPDlayer *)ale->data);
1133 }
1134 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1135 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(ale->id);
1137 *grease_pencil, static_cast<GreasePencilLayer *>(ale->data)->wrap());
1138
1139 if (changed) {
1140 DEG_id_tag_update(&grease_pencil->id, ID_RECALC_GEOMETRY);
1141 }
1142 }
1143 else if (ale->type == ANIMTYPE_MASKLAYER) {
1144 changed = ED_masklayer_frames_delete((MaskLayer *)ale->data);
1145 }
1146 else {
1147 FCurve *fcu = (FCurve *)ale->key_data;
1148 AnimData *adt = ale->adt;
1149
1150 /* delete selected keyframes only */
1151 changed = BKE_fcurve_delete_keys_selected(fcu);
1152
1153 /* Only delete curve too if it won't be doing anything anymore */
1154 if (BKE_fcurve_is_empty(fcu)) {
1156 ale->key_data = nullptr;
1157 }
1158 }
1159
1160 if (changed) {
1161 ale->update |= ANIM_UPDATE_DEFAULT;
1162 changed_final = true;
1163 }
1164 }
1165
1166 ANIM_animdata_update(ac, &anim_data);
1167 ANIM_animdata_freelist(&anim_data);
1168
1169 return changed_final;
1170}
1171
1172/* ------------------- */
1173
1175{
1176 bAnimContext ac;
1177
1178 /* get editor data */
1179 if (ANIM_animdata_get_context(C, &ac) == 0) {
1180 return OPERATOR_CANCELLED;
1181 }
1182
1183 /* delete keyframes */
1184 if (!delete_action_keys(&ac)) {
1185 return OPERATOR_CANCELLED;
1186 }
1187
1188 /* set notifier that keyframes have changed */
1190
1191 return OPERATOR_FINISHED;
1192}
1193
1195 wmOperator *op,
1196 const wmEvent * /*event*/)
1197{
1198 if (RNA_boolean_get(op->ptr, "confirm")) {
1200 op,
1201 IFACE_("Delete selected keyframes?"),
1202 nullptr,
1203 IFACE_("Delete"),
1205 false);
1206 }
1207 return actkeys_delete_exec(C, op);
1208}
1209
1211{
1212 /* identifiers */
1213 ot->name = "Delete Keyframes";
1214 ot->idname = "ACTION_OT_delete";
1215 ot->description = "Remove all selected keyframes";
1216
1217 /* API callbacks. */
1218 ot->invoke = actkeys_delete_invoke;
1219 ot->exec = actkeys_delete_exec;
1221
1222 /* flags */
1223 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1225}
1226
1228
1229/* -------------------------------------------------------------------- */
1232
1233static void clean_action_keys(bAnimContext *ac, float thresh, bool clean_chan)
1234{
1235 ListBase anim_data = {nullptr, nullptr};
1237
1238 /* filter data */
1241
1242 if (clean_chan) {
1244 }
1245
1246 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1247
1248 const bool only_selected_keys = !clean_chan;
1249 /* loop through filtered data and clean curves */
1250 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1251 clean_fcurve(ale, thresh, clean_chan, only_selected_keys);
1252
1253 ale->update |= ANIM_UPDATE_DEFAULT;
1254 }
1255
1256 ANIM_animdata_update(ac, &anim_data);
1257 ANIM_animdata_freelist(&anim_data);
1258}
1259
1260/* ------------------- */
1261
1263{
1264 bAnimContext ac;
1265 float thresh;
1266 bool clean_chan;
1267
1268 /* get editor data */
1269 if (ANIM_animdata_get_context(C, &ac) == 0) {
1270 return OPERATOR_CANCELLED;
1271 }
1272
1274 BKE_report(op->reports, RPT_ERROR, "Not implemented");
1275 return OPERATOR_PASS_THROUGH;
1276 }
1277
1278 /* get cleaning threshold */
1279 thresh = RNA_float_get(op->ptr, "threshold");
1280 clean_chan = RNA_boolean_get(op->ptr, "channels");
1281
1282 /* clean keyframes */
1283 clean_action_keys(&ac, thresh, clean_chan);
1284
1285 /* set notifier that keyframes have changed */
1287
1288 return OPERATOR_FINISHED;
1289}
1290
1292{
1293 /* identifiers */
1294 ot->name = "Clean Keyframes";
1295 ot->idname = "ACTION_OT_clean";
1296 ot->description = "Simplify F-Curves by removing closely spaced keyframes";
1297
1298 /* API callbacks. */
1299 // ot->invoke = /* XXX we need that number popup for this! */
1300 ot->exec = actkeys_clean_exec;
1302
1303 /* flags */
1304 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1305
1306 /* properties */
1307 ot->prop = RNA_def_float(
1308 ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
1309 RNA_def_boolean(ot->srna, "channels", false, "Channels", "");
1310}
1311
1313
1314/* -------------------------------------------------------------------- */
1317
1318/* Evaluates the curves between each selected keyframe on each frame, and keys the value. */
1320{
1321 ListBase anim_data = {nullptr, nullptr};
1323
1324 /* filter data */
1327 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1328
1329 /* Loop through filtered data and add keys between selected keyframes on every frame. */
1330 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1332
1333 ale->update |= ANIM_UPDATE_DEPS;
1334 }
1335
1336 ANIM_animdata_update(ac, &anim_data);
1337 ANIM_animdata_freelist(&anim_data);
1338}
1339
1340/* ------------------- */
1341
1343{
1344 bAnimContext ac;
1345
1346 /* get editor data */
1347 if (ANIM_animdata_get_context(C, &ac) == 0) {
1348 return OPERATOR_CANCELLED;
1349 }
1350
1352 BKE_report(op->reports, RPT_ERROR, "Not implemented");
1353 return OPERATOR_PASS_THROUGH;
1354 }
1355
1356 /* sample keyframes */
1357 bake_action_keys(&ac);
1358
1359 /* set notifier that keyframes have changed */
1361
1362 return OPERATOR_FINISHED;
1363}
1364
1366{
1367 /* identifiers */
1368 ot->name = "Bake Keyframes";
1369 ot->idname = "ACTION_OT_bake_keys";
1370 ot->description = "Add keyframes on every frame between the selected keyframes";
1371
1372 /* API callbacks. */
1373 ot->exec = actkeys_bake_exec;
1375
1376 /* flags */
1377 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1378}
1379
1381
1382/* -------------------------------------------------------------------- */
1385
1386/* defines for make/clear cyclic extrapolation tools */
1387#define MAKE_CYCLIC_EXPO -1
1388#define CLEAR_CYCLIC_EXPO -2
1389
1390/* defines for set extrapolation-type for selected keyframes tool */
1393 "CONSTANT",
1394 0,
1395 "Constant Extrapolation",
1396 "Values on endpoint keyframes are held"},
1398 "LINEAR",
1399 0,
1400 "Linear Extrapolation",
1401 "Straight-line slope of end segments are extended past the endpoint keyframes"},
1402
1404 "MAKE_CYCLIC",
1405 0,
1406 "Make Cyclic (F-Modifier)",
1407 "Add Cycles F-Modifier if one doesn't exist already"},
1409 "CLEAR_CYCLIC",
1410 0,
1411 "Clear Cyclic (F-Modifier)",
1412 "Remove Cycles F-Modifier if not needed anymore"},
1413 {0, nullptr, 0, nullptr, nullptr},
1414};
1415
1416/* this function is responsible for setting extrapolation mode for keyframes */
1417static void setexpo_action_keys(bAnimContext *ac, short mode)
1418{
1419 ListBase anim_data = {nullptr, nullptr};
1421
1422 /* filter data */
1425 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1426
1427 /* loop through setting mode per F-Curve */
1428 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1429 FCurve *fcu = (FCurve *)ale->data;
1430
1431 if (mode >= 0) {
1432 /* just set mode setting */
1433 fcu->extend = mode;
1434 }
1435 else {
1436 /* shortcuts for managing Cycles F-Modifiers to make it easier to toggle cyclic animation
1437 * without having to go through FModifier UI in Graph Editor to do so
1438 */
1439 if (mode == MAKE_CYCLIC_EXPO) {
1440 /* only add if one doesn't exist */
1442 /* TODO: add some more preset versions which set different extrapolation options? */
1444 }
1445 }
1446 else if (mode == CLEAR_CYCLIC_EXPO) {
1447 /* remove all the modifiers fitting this description */
1448 FModifier *fcm, *fcn = nullptr;
1449
1450 for (fcm = static_cast<FModifier *>(fcu->modifiers.first); fcm; fcm = fcn) {
1451 fcn = fcm->next;
1452
1453 if (fcm->type == FMODIFIER_TYPE_CYCLES) {
1454 remove_fmodifier(&fcu->modifiers, fcm);
1455 }
1456 }
1457 }
1458 }
1459
1460 ale->update |= ANIM_UPDATE_DEFAULT;
1461 }
1462
1463 ANIM_animdata_update(ac, &anim_data);
1464 ANIM_animdata_freelist(&anim_data);
1465}
1466
1467/* ------------------- */
1468
1470{
1471 bAnimContext ac;
1472 short mode;
1473
1474 /* get editor data */
1475 if (ANIM_animdata_get_context(C, &ac) == 0) {
1476 return OPERATOR_CANCELLED;
1477 }
1478
1480 BKE_report(op->reports, RPT_ERROR, "Not implemented");
1481 return OPERATOR_PASS_THROUGH;
1482 }
1483
1484 /* get handle setting mode */
1485 mode = RNA_enum_get(op->ptr, "type");
1486
1487 /* set handle type */
1488 setexpo_action_keys(&ac, mode);
1489
1490 /* set notifier that keyframe properties have changed */
1492
1493 return OPERATOR_FINISHED;
1494}
1495
1497{
1498 /* identifiers */
1499 ot->name = "Set F-Curve Extrapolation";
1500 ot->idname = "ACTION_OT_extrapolation_type";
1501 ot->description = "Set extrapolation mode for selected F-Curves";
1502
1503 /* API callbacks. */
1504 ot->invoke = WM_menu_invoke;
1505 ot->exec = actkeys_expo_exec;
1507
1508 /* flags */
1509 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1510
1511 /* id-props */
1512 ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_expo_types, 0, "Type", "");
1513}
1514
1516
1517/* -------------------------------------------------------------------- */
1520
1522{
1523 bAnimContext ac;
1524 short mode;
1525
1526 /* get editor data */
1527 if (ANIM_animdata_get_context(C, &ac) == 0) {
1528 return OPERATOR_CANCELLED;
1529 }
1530
1532 BKE_report(op->reports, RPT_ERROR, "Not implemented");
1533 return OPERATOR_PASS_THROUGH;
1534 }
1535
1536 /* get handle setting mode */
1537 mode = RNA_enum_get(op->ptr, "type");
1538
1539 /* set handle type */
1545
1546 /* set notifier that keyframe properties have changed */
1548
1549 return OPERATOR_FINISHED;
1550}
1551
1553{
1554 /* identifiers */
1555 ot->name = "Set Keyframe Interpolation";
1556 ot->idname = "ACTION_OT_interpolation_type";
1557 ot->description =
1558 "Set interpolation mode for the F-Curve segments starting from the selected keyframes";
1559
1560 /* API callbacks. */
1561 ot->invoke = WM_menu_invoke;
1562 ot->exec = actkeys_ipo_exec;
1564
1565 /* flags */
1566 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1567
1568 /* id-props */
1569 ot->prop = RNA_def_enum(
1570 ot->srna, "type", rna_enum_beztriple_interpolation_mode_items, 0, "Type", "");
1572}
1573
1575
1576/* -------------------------------------------------------------------- */
1579
1581{
1582 bAnimContext ac;
1583 short mode;
1584
1585 /* get editor data */
1586 if (ANIM_animdata_get_context(C, &ac) == 0) {
1587 return OPERATOR_CANCELLED;
1588 }
1589
1590 /* get handle setting mode */
1591 mode = RNA_enum_get(op->ptr, "type");
1592
1593 /* set handle type */
1599
1600 /* set notifier that keyframe properties have changed */
1602
1603 return OPERATOR_FINISHED;
1604}
1605
1607{
1608 /* identifiers */
1609 ot->name = "Set Keyframe Easing Type";
1610 ot->idname = "ACTION_OT_easing_type";
1611 ot->description =
1612 "Set easing type for the F-Curve segments starting from the selected keyframes";
1613
1614 /* API callbacks. */
1615 ot->invoke = WM_menu_invoke;
1616 ot->exec = actkeys_easing_exec;
1618
1619 /* flags */
1620 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1621
1622 /* id-props */
1623 ot->prop = RNA_def_enum(
1624 ot->srna, "type", rna_enum_beztriple_interpolation_easing_items, 0, "Type", "");
1625}
1626
1628
1629/* -------------------------------------------------------------------- */
1632
1633/* this function is responsible for setting handle-type of selected keyframes */
1634static void sethandles_action_keys(bAnimContext *ac, short mode)
1635{
1636 ListBase anim_data = {nullptr, nullptr};
1638
1641
1642 /* filter data */
1645 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1646
1647 /* Loop through setting flags for handles
1648 * NOTE: we do not supply KeyframeEditData to the looper yet.
1649 * Currently that's not necessary here.
1650 */
1651 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1652 FCurve *fcu = (FCurve *)ale->key_data;
1653
1654 /* any selected keyframes for editing? */
1655 if (ANIM_fcurve_keyframes_loop(nullptr, fcu, nullptr, sel_cb, nullptr)) {
1656 /* change type of selected handles */
1657 ANIM_fcurve_keyframes_loop(nullptr, fcu, nullptr, edit_cb, BKE_fcurve_handles_recalc);
1658
1659 ale->update |= ANIM_UPDATE_DEFAULT;
1660 }
1661 }
1662
1663 ANIM_animdata_update(ac, &anim_data);
1664 ANIM_animdata_freelist(&anim_data);
1665}
1666
1667/* ------------------- */
1668
1670{
1671 bAnimContext ac;
1672 short mode;
1673
1674 /* get editor data */
1675 if (ANIM_animdata_get_context(C, &ac) == 0) {
1676 return OPERATOR_CANCELLED;
1677 }
1678
1680 BKE_report(op->reports, RPT_ERROR, "Not implemented");
1681 return OPERATOR_PASS_THROUGH;
1682 }
1683
1684 /* get handle setting mode */
1685 mode = RNA_enum_get(op->ptr, "type");
1686
1687 /* set handle type */
1688 sethandles_action_keys(&ac, mode);
1689
1690 /* set notifier that keyframe properties have changed */
1692
1693 return OPERATOR_FINISHED;
1694}
1695
1697{
1698 /* identifiers */
1699 ot->name = "Set Keyframe Handle Type";
1700 ot->idname = "ACTION_OT_handle_type";
1701 ot->description = "Set type of handle for selected keyframes";
1702
1703 /* API callbacks. */
1704 ot->invoke = WM_menu_invoke;
1707
1708 /* flags */
1709 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1710
1711 /* id-props */
1712 ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_keyframe_handle_type_items, 0, "Type", "");
1713}
1714
1716
1717/* -------------------------------------------------------------------- */
1720
1721/* this function is responsible for setting keyframe type for keyframes */
1723{
1724 ListBase anim_data = {nullptr, nullptr};
1727
1728 /* filter data */
1731 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1732
1733 /* Loop through setting BezTriple interpolation
1734 * NOTE: we do not supply KeyframeEditData to the looper yet.
1735 * Currently that's not necessary here.
1736 */
1737 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1738 switch (ale->type) {
1739 case ANIMTYPE_GPLAYER:
1740 ED_gpencil_layer_frames_keytype_set(static_cast<bGPDlayer *>(ale->data), mode);
1741 ale->update |= ANIM_UPDATE_DEPS;
1742 break;
1743
1746 static_cast<GreasePencilLayer *>(ale->data)->wrap(), mode);
1747 ale->update |= ANIM_UPDATE_DEPS;
1748 break;
1749
1750 case ANIMTYPE_FCURVE:
1752 nullptr, static_cast<FCurve *>(ale->key_data), nullptr, set_cb, nullptr);
1753 ale->update |= ANIM_UPDATE_DEPS | ANIM_UPDATE_HANDLES;
1754 break;
1755
1756 default:
1757 BLI_assert_msg(false, "Keytype cannot be set into this animation type.");
1758 }
1759 }
1760
1761 ANIM_animdata_update(ac, &anim_data);
1762 ANIM_animdata_freelist(&anim_data);
1763}
1764
1765/* ------------------- */
1766
1768{
1769 bAnimContext ac;
1770
1771 /* get editor data */
1772 if (ANIM_animdata_get_context(C, &ac) == 0) {
1773 return OPERATOR_CANCELLED;
1774 }
1775
1776 if (ac.datatype == ANIMCONT_MASK) {
1777 BKE_report(op->reports, RPT_ERROR, "Not implemented for Masks");
1778 return OPERATOR_PASS_THROUGH;
1779 }
1780
1781 const int mode = RNA_enum_get(op->ptr, "type");
1783
1784 /* set notifier that keyframe properties have changed */
1786
1787 return OPERATOR_FINISHED;
1788}
1789
1791{
1792 /* identifiers */
1793 ot->name = "Set Keyframe Type";
1794 ot->idname = "ACTION_OT_keyframe_type";
1795 ot->description = "Set type of keyframe for the selected keyframes";
1796
1797 /* API callbacks. */
1798 ot->invoke = WM_menu_invoke;
1799 ot->exec = actkeys_keytype_exec;
1801
1802 /* flags */
1803 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1804
1805 /* id-props */
1806 ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_beztriple_keyframe_type_items, 0, "Type", "");
1807}
1808
1810
1811/* -------------------------------------------------------------------- */
1814
1816{
1817 /* prevent changes during render */
1818 if (G.is_rendering) {
1819 return false;
1820 }
1821
1823}
1824
1825/* snap current-frame indicator to 'average time' of selected keyframe */
1827{
1828 bAnimContext ac;
1829 ListBase anim_data = {nullptr, nullptr};
1831 KeyframeEditData ked = {{nullptr}};
1832
1833 /* get editor data */
1834 if (ANIM_animdata_get_context(C, &ac) == 0) {
1835 return OPERATOR_CANCELLED;
1836 }
1837
1838 /* init edit data */
1839 /* loop over action data, averaging values */
1841 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
1842
1843 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1844 switch (ale->datatype) {
1845 case ALE_GPFRAME: {
1846 bGPDlayer *gpl = static_cast<bGPDlayer *>(ale->data);
1847
1848 LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
1849 /* only if selected */
1850 if (!(gpf->flag & GP_FRAME_SELECT)) {
1851 continue;
1852 }
1853 /* store average time in float 1 (only do rounding at last step) */
1854 ked.f1 += gpf->framenum;
1855
1856 /* increment number of items */
1857 ked.i1++;
1858 }
1859 break;
1860 }
1861
1862 case ALE_GREASE_PENCIL_CEL: {
1863 using namespace blender::bke::greasepencil;
1864 const Layer &layer = *static_cast<Layer *>(ale->data);
1865 for (auto [frame_number, frame] : layer.frames().items()) {
1866 if (!frame.is_selected()) {
1867 continue;
1868 }
1869 ked.f1 += frame_number;
1870 ked.i1++;
1871 }
1872 break;
1873 }
1874
1875 case ALE_FCURVE: {
1876 FCurve *fcurve = static_cast<FCurve *>(ale->key_data);
1877 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcurve, false, true);
1878 ANIM_fcurve_keyframes_loop(&ked, fcurve, nullptr, bezt_calc_average, nullptr);
1879 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcurve, true, true);
1880 break;
1881 }
1882
1883 default:
1884 BLI_assert_msg(false, "Cannot jump to keyframe into this animation type.");
1885 }
1886 }
1887
1888 ANIM_animdata_freelist(&anim_data);
1889
1890 /* set the new current frame value, based on the average time */
1891 if (ked.i1) {
1892 Scene *scene = ac.scene;
1893 scene->r.cfra = round_fl_to_int(ked.f1 / ked.i1);
1894 scene->r.subframe = 0.0f;
1895 }
1896
1897 /* set notifier that things have changed */
1899
1900 return OPERATOR_FINISHED;
1901}
1902
1904{
1905 /* identifiers */
1906 ot->name = "Jump to Keyframes";
1907 ot->idname = "ACTION_OT_frame_jump";
1908 ot->description = "Set the current frame to the average frame value of selected keyframes";
1909
1910 /* API callbacks. */
1911 ot->exec = actkeys_framejump_exec;
1912 ot->poll = actkeys_framejump_poll;
1913
1914 /* flags */
1915 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1916}
1917
1919
1920/* -------------------------------------------------------------------- */
1923
1924/* defines for snap keyframes tool */
1927 "CFRA",
1928 0,
1929 "Selection to Current Frame",
1930 "Snap selected keyframes to the current frame"},
1932 "NEAREST_FRAME",
1933 0,
1934 "Selection to Nearest Frame",
1935 "Snap selected keyframes to the nearest (whole) frame "
1936 "(use to fix accidental subframe offsets)"},
1938 "NEAREST_SECOND",
1939 0,
1940 "Selection to Nearest Second",
1941 "Snap selected keyframes to the nearest second"},
1943 "NEAREST_MARKER",
1944 0,
1945 "Selection to Nearest Marker",
1946 "Snap selected keyframes to the nearest marker"},
1947 {0, nullptr, 0, nullptr, nullptr},
1948};
1949
1950/* this function is responsible for snapping keyframes to frame-times */
1951static void snap_action_keys(bAnimContext *ac, short mode)
1952{
1953 ListBase anim_data = {nullptr, nullptr};
1955
1956 KeyframeEditData ked = {{nullptr}};
1957 KeyframeEditFunc edit_cb;
1958
1959 /* filter data */
1962 }
1963 else {
1966 }
1967 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1968
1969 /* get beztriple editing callbacks */
1970 edit_cb = ANIM_editkeyframes_snap(mode);
1971
1972 ked.scene = ac->scene;
1973 if (mode == ACTKEYS_SNAP_NEAREST_MARKER) {
1974 ked.list.first = (ac->markers) ? ac->markers->first : nullptr;
1975 ked.list.last = (ac->markers) ? ac->markers->last : nullptr;
1976 }
1977
1978 /* snap keyframes */
1979 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1980 if (ale->type == ANIMTYPE_GPLAYER) {
1981 ED_gpencil_layer_snap_frames(static_cast<bGPDlayer *>(ale->data), ac->scene, mode);
1982 }
1983 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1984 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(ale->id);
1985 GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(ale->data);
1986
1988 *grease_pencil, layer->wrap(), *(ac->scene), static_cast<eEditKeyframes_Snap>(mode));
1989
1990 if (changed) {
1991 DEG_id_tag_update(&grease_pencil->id, ID_RECALC_GEOMETRY);
1992 }
1993 }
1994 else if (ale->type == ANIMTYPE_MASKLAYER) {
1995 ED_masklayer_snap_frames(static_cast<MaskLayer *>(ale->data), ac->scene, mode);
1996 }
1997 else {
1998 FCurve *fcurve = static_cast<FCurve *>(ale->key_data);
1999 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcurve, false, false);
2000 ANIM_fcurve_keyframes_loop(&ked, fcurve, nullptr, edit_cb, BKE_fcurve_handles_recalc);
2002 fcurve, SELECT, false); /* only use handles in graph editor */
2003 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcurve, true, false);
2004 }
2005
2007 }
2008
2009 ANIM_animdata_update(ac, &anim_data);
2010 ANIM_animdata_freelist(&anim_data);
2011}
2012
2013/* ------------------- */
2014
2016{
2017 bAnimContext ac;
2018 short mode;
2019
2020 /* get editor data */
2021 if (ANIM_animdata_get_context(C, &ac) == 0) {
2022 return OPERATOR_CANCELLED;
2023 }
2024
2025 /* get snapping mode */
2026 mode = RNA_enum_get(op->ptr, "type");
2027
2028 /* snap keyframes */
2029 snap_action_keys(&ac, mode);
2030
2031 /* set notifier that keyframes have changed */
2033
2034 return OPERATOR_FINISHED;
2035}
2036
2038{
2039 /* identifiers */
2040 ot->name = "Snap Keys";
2041 ot->idname = "ACTION_OT_snap";
2042 ot->description = "Snap selected keyframes to the times specified";
2043
2044 /* API callbacks. */
2045 ot->invoke = WM_menu_invoke;
2046 ot->exec = actkeys_snap_exec;
2048
2049 /* flags */
2050 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2051
2052 /* id-props */
2053 ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_snap_types, 0, "Type", "");
2054}
2055
2057
2058/* -------------------------------------------------------------------- */
2061
2062/* defines for mirror keyframes tool */
2065 "CFRA",
2066 0,
2067 "By Times Over Current Frame",
2068 "Flip times of selected keyframes using the current frame as the mirror line"},
2070 "XAXIS",
2071 0,
2072 "By Values Over Zero Value",
2073 "Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"},
2075 "MARKER",
2076 0,
2077 "By Times Over First Selected Marker",
2078 "Flip times of selected keyframes using the first selected marker as the reference point"},
2079 {0, nullptr, 0, nullptr, nullptr},
2080};
2081
2082/* this function is responsible for mirroring keyframes */
2083static void mirror_action_keys(bAnimContext *ac, short mode)
2084{
2085 ListBase anim_data = {nullptr, nullptr};
2087
2088 KeyframeEditData ked = {{nullptr}};
2089 KeyframeEditFunc edit_cb;
2090
2091 /* get beztriple editing callbacks */
2092 edit_cb = ANIM_editkeyframes_mirror(mode);
2093
2094 ked.scene = ac->scene;
2095
2096 /* for 'first selected marker' mode, need to find first selected marker first! */
2097 /* XXX should this be made into a helper func in the API? */
2098 if (mode == ACTKEYS_MIRROR_MARKER) {
2100
2101 if (marker) {
2102 ked.f1 = float(marker->frame);
2103 }
2104 else {
2105 return;
2106 }
2107 }
2108
2109 /* filter data */
2112 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
2113
2114 /* mirror keyframes */
2115 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
2116 if (ale->type == ANIMTYPE_GPLAYER) {
2117 ED_gpencil_layer_mirror_frames(static_cast<bGPDlayer *>(ale->data), ac->scene, mode);
2118 }
2119 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
2120 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(ale->id);
2121 GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(ale->data);
2122
2124 *grease_pencil, layer->wrap(), *(ac->scene), static_cast<eEditKeyframes_Mirror>(mode));
2125
2126 if (changed) {
2127 DEG_id_tag_update(&grease_pencil->id, ID_RECALC_GEOMETRY);
2128 }
2129 }
2130 else if (ale->type == ANIMTYPE_MASKLAYER) {
2131 /* TODO */
2132 }
2133 else {
2134 FCurve *fcurve = static_cast<FCurve *>(ale->key_data);
2135 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcurve, false, false);
2136 ANIM_fcurve_keyframes_loop(&ked, fcurve, nullptr, edit_cb, BKE_fcurve_handles_recalc);
2137 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcurve, true, false);
2138 }
2139
2140 ale->update |= ANIM_UPDATE_DEFAULT;
2141 }
2142
2143 ANIM_animdata_update(ac, &anim_data);
2144 ANIM_animdata_freelist(&anim_data);
2145}
2146
2147/* ------------------- */
2148
2150{
2151 bAnimContext ac;
2152 short mode;
2153
2154 /* get editor data */
2155 if (ANIM_animdata_get_context(C, &ac) == 0) {
2156 return OPERATOR_CANCELLED;
2157 }
2158
2159 /* get mirroring mode */
2160 mode = RNA_enum_get(op->ptr, "type");
2161
2162 /* mirror keyframes */
2163 mirror_action_keys(&ac, mode);
2164
2165 /* set notifier that keyframes have changed */
2167
2168 return OPERATOR_FINISHED;
2169}
2170
2172{
2173 /* identifiers */
2174 ot->name = "Mirror Keys";
2175 ot->idname = "ACTION_OT_mirror";
2176 ot->description = "Flip selected keyframes over the selected mirror line";
2177
2178 /* API callbacks. */
2179 ot->invoke = WM_menu_invoke;
2180 ot->exec = actkeys_mirror_exec;
2182
2183 /* flags */
2184 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2185
2186 /* id-props */
2187 ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_mirror_types, 0, "Type", "");
2188}
2189
Functions and classes to work with Actions.
Functions to work with AnimData.
Functions to modify FCurves.
Functions to insert, delete or modify keyframes.
AnimationEvalContext BKE_animsys_eval_context_construct(struct Depsgraph *depsgraph, float eval_time) ATTR_WARN_UNUSED_RESULT
Definition anim_sys.cc:735
bScreen * CTX_wm_screen(const bContext *C)
SpaceAction * CTX_wm_space_action(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
void BKE_fcurve_handles_recalc(FCurve *fcu)
FModifier * add_fmodifier(ListBase *modifiers, int type, FCurve *owner_fcu)
bool remove_fmodifier(ListBase *modifiers, FModifier *fcm)
bool list_has_suitable_fmodifier(const ListBase *modifiers, int mtype, short acttype)
bool BKE_fcurve_is_empty(const FCurve *fcu)
bool BKE_fcurve_delete_keys_selected(FCurve *fcu)
float evaluate_fcurve(const FCurve *fcu, float evaltime)
void BKE_fcurve_merge_duplicate_keys(FCurve *fcu, const int sel_flag, const bool use_handle)
bool BKE_fcurve_calc_range(const FCurve *fcu, float *r_min, float *r_max, bool selected_keys_only)
struct bGPDframe * BKE_gpencil_layer_frame_get(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
void BKE_gpencil_tag(struct bGPdata *gpd)
eGP_GetFrame_Mode
@ GP_GETFRAME_ADD_NEW
@ GP_GETFRAME_ADD_COPY
Low-level operations for grease pencil.
@ NLATIME_CONVERT_MAP
Definition BKE_nla.hh:543
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:540
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define LISTBASE_FOREACH(type, var, list)
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
MINLINE int round_fl_to_int(float a)
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:202
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.cc:41
#define ELEM(...)
#define BLT_I18NCONTEXT_ID_ACTION
#define TIP_(msgid)
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
@ ID_AC
@ SACTCONT_ACTION
@ SACTCONT_SHAPEKEY
@ SACTION_POSEMARKERS_SHOW
eInsertKeyFlags
@ FMODIFIER_TYPE_CYCLES
@ FCURVE_EXTRAPOLATE_CONSTANT
@ FCURVE_EXTRAPOLATE_LINEAR
eBezTriple_KeyframeType
@ SCER_PRV_RANGE
@ GP_TOOL_FLAG_RETAIN_LAST
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_PASS_THROUGH
@ ANIMTYPE_NLACURVE
@ ANIMTYPE_GPLAYER
@ ANIMTYPE_MASKLAYER
@ ANIMTYPE_FCURVE
@ ANIMTYPE_GREASE_PENCIL_LAYER
@ ACHANNEL_ROLE_CHANNEL
#define ANIM_UPDATE_DEFAULT
@ ALE_GREASE_PENCIL_CEL
@ ALE_GPFRAME
@ ALE_FCURVE
@ ALE_ACTION_SLOT
@ ALE_MASKLAY
@ ANIM_UPDATE_DEPS
@ ANIM_UPDATE_HANDLES
eAnimCont_Types
@ ANIMCONT_MASK
@ ANIMCONT_GPENCIL
@ ACHANNEL_SETTING_SELECT
eAnimFilter_Flags
@ ANIMFILTER_FOREDIT
@ ANIMFILTER_DATA_VISIBLE
@ ANIMFILTER_LIST_VISIBLE
@ ANIMFILTER_LIST_CHANNELS
@ ANIMFILTER_NODUPLIS
@ ANIMFILTER_FCURVESONLY
@ ANIMFILTER_SEL
@ ANIMFILTER_ACTGROUPED
eEditKeyframes_Mirror
@ KEYFRAME_PASTE_MERGE_MIX
@ KEYFRAME_PASTE_VALUE_OFFSET_NONE
eKeyPasteOffset
@ KEYFRAME_PASTE_OFFSET_CFRA_START
@ BEZT_OK_SELECTED
eEditKeyframes_Snap
short(*)(KeyframeEditData *ked, BezTriple *bezt) KeyframeEditFunc
@ KEYFRAME_PASTE_NOTHING_TO_PASTE
@ KEYFRAME_PASTE_OK
@ KEYFRAME_PASTE_NOWHERE_TO_PASTE
void ED_masklayer_snap_frames(MaskLayer *mask_layer, Scene *scene, short mode)
bool ED_masklayer_frames_duplicate(MaskLayer *mask_layer)
bool ED_masklayer_frames_delete(MaskLayer *mask_layer)
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:714
bool ED_operator_action_active(bContext *C)
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
#define C
Definition RandGen.cpp:29
@ ALERT_ICON_NONE
void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag)
Definition view2d.cc:865
#define V2D_LOCK_COPY
Definition UI_view2d.hh:85
void UI_view2d_center_get(const View2D *v2d, float *r_x, float *r_y)
Definition view2d.cc:1938
void UI_view2d_center_set(View2D *v2d, float x, float y)
Definition view2d.cc:1948
#define ND_DATA
Definition WM_types.hh:506
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NC_ANIMATION
Definition WM_types.hh:385
#define NC_SCENE
Definition WM_types.hh:375
#define NA_ADDED
Definition WM_types.hh:583
#define NA_EDITED
Definition WM_types.hh:581
#define ND_KEYFRAME_PROP
Definition WM_types.hh:492
ReportList * reports
Definition WM_types.hh:1025
#define ND_MARKERS
Definition WM_types.hh:430
#define ND_FRAME
Definition WM_types.hh:431
#define NA_REMOVED
Definition WM_types.hh:584
#define NC_GPENCIL
Definition WM_types.hh:396
#define ND_KEYFRAME
Definition WM_types.hh:491
static wmOperatorStatus actkeys_viewall(bContext *C, const bool only_sel)
void ACTION_OT_view_selected(wmOperatorType *ot)
static bool actkeys_framejump_poll(bContext *C)
static wmOperatorStatus actkeys_viewsel_exec(bContext *C, wmOperator *)
void ACTION_OT_keyframe_type(wmOperatorType *ot)
static wmOperatorStatus actkeys_snap_exec(bContext *C, wmOperator *op)
static std::string actkeys_paste_get_description(bContext *, wmOperatorType *, PointerRNA *ptr)
void ACTION_OT_easing_type(wmOperatorType *ot)
static void bake_action_keys(bAnimContext *ac)
static bool act_markers_make_local_poll(bContext *C)
static bool copy_action_keys(bAnimContext *ac)
static void snap_action_keys(bAnimContext *ac, short mode)
static wmOperatorStatus actkeys_handletype_exec(bContext *C, wmOperator *op)
static wmOperatorStatus actkeys_previewrange_exec(bContext *C, wmOperator *)
static void clean_action_keys(bAnimContext *ac, float thresh, bool clean_chan)
static const EnumPropertyItem prop_actkeys_snap_types[]
static wmOperatorStatus actkeys_keytype_exec(bContext *C, wmOperator *op)
void ACTION_OT_view_all(wmOperatorType *ot)
static bool duplicate_action_keys(bAnimContext *ac)
static wmOperatorStatus actkeys_clean_exec(bContext *C, wmOperator *op)
void ACTION_OT_previewrange_set(wmOperatorType *ot)
void ACTION_OT_duplicate(wmOperatorType *ot)
void ACTION_OT_delete(wmOperatorType *ot)
void ACTION_OT_view_frame(wmOperatorType *ot)
static wmOperatorStatus actkeys_easing_exec(bContext *C, wmOperator *op)
void ACTION_OT_extrapolation_type(wmOperatorType *ot)
static wmOperatorStatus actkeys_copy_exec(bContext *C, wmOperator *op)
void ACTION_OT_keyframe_insert(wmOperatorType *ot)
static void insert_action_keys(bAnimContext *ac, short mode)
static eKeyPasteError paste_action_keys(bAnimContext *ac, const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip)
static bool delete_action_keys(bAnimContext *ac)
void ACTION_OT_snap(wmOperatorType *ot)
static void insert_grease_pencil_key(bAnimContext *ac, bAnimListElem *ale, const bool hold_previous)
static wmOperatorStatus act_markers_make_local_exec(bContext *C, wmOperator *)
static wmOperatorStatus actkeys_view_frame_exec(bContext *C, wmOperator *op)
static wmOperatorStatus actkeys_framejump_exec(bContext *C, wmOperator *)
static wmOperatorStatus actkeys_ipo_exec(bContext *C, wmOperator *op)
void ACTION_OT_bake_keys(wmOperatorType *ot)
#define MAKE_CYCLIC_EXPO
static wmOperatorStatus actkeys_expo_exec(bContext *C, wmOperator *op)
void ACTION_OT_frame_jump(wmOperatorType *ot)
void ACTION_OT_paste(wmOperatorType *ot)
static wmOperatorStatus actkeys_delete_exec(bContext *C, wmOperator *)
static wmOperatorStatus actkeys_paste_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem prop_actkeys_mirror_types[]
static void setkeytype_action_keys(bAnimContext *ac, eBezTriple_KeyframeType mode)
static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *r_min, float *r_max)
static blender::ed::greasepencil::KeyframeClipboard & get_grease_pencil_keyframe_clipboard()
static void sethandles_action_keys(bAnimContext *ac, short mode)
static void insert_fcurve_key(bAnimContext *ac, bAnimListElem *ale, const AnimationEvalContext anim_eval_context, eInsertKeyFlags flag)
static void mirror_action_keys(bAnimContext *ac, short mode)
void ACTION_OT_copy(wmOperatorType *ot)
static wmOperatorStatus actkeys_bake_exec(bContext *C, wmOperator *op)
static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const short onlySel)
static wmOperatorStatus actkeys_mirror_exec(bContext *C, wmOperator *op)
void ACTION_OT_markers_make_local(wmOperatorType *ot)
void ACTION_OT_interpolation_type(wmOperatorType *ot)
void ACTION_OT_handle_type(wmOperatorType *ot)
static wmOperatorStatus actkeys_insertkey_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem prop_actkeys_insertkey_types[]
void ACTION_OT_mirror(wmOperatorType *ot)
static void insert_gpencil_key(bAnimContext *ac, bAnimListElem *ale, const eGP_GetFrame_Mode add_frame_mode, bGPdata **gpd_old)
static wmOperatorStatus actkeys_viewall_exec(bContext *C, wmOperator *)
static void setexpo_action_keys(bAnimContext *ac, short mode)
static wmOperatorStatus actkeys_duplicate_exec(bContext *C, wmOperator *)
static wmOperatorStatus actkeys_delete_invoke(bContext *C, wmOperator *op, const wmEvent *)
void ACTION_OT_clean(wmOperatorType *ot)
#define CLEAR_CYCLIC_EXPO
static const EnumPropertyItem prop_actkeys_expo_types[]
@ ACTKEYS_SNAP_NEAREST_FRAME
@ ACTKEYS_SNAP_NEAREST_SECOND
@ ACTKEYS_SNAP_CFRA
@ ACTKEYS_SNAP_NEAREST_MARKER
@ ACTKEYS_MIRROR_CFRA
@ ACTKEYS_MIRROR_MARKER
@ ACTKEYS_MIRROR_XAXIS
float ANIM_UI_get_channel_step()
float ANIM_UI_get_first_channel_top(View2D *v2d)
float ANIM_UI_get_channel_height()
short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting)
const bAnimChannelType * ANIM_channel_get_typeinfo(const bAnimListElem *ale)
void ANIM_animdata_freelist(ListBase *anim_data)
Definition anim_deps.cc:463
void ANIM_deselect_keys_in_animation_editors(bContext *C)
Definition anim_deps.cc:478
void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
Definition anim_deps.cc:356
void ANIM_nla_mapping_apply_if_needed_fcurve(bAnimListElem *ale, FCurve *fcu, const bool restore, const bool only_keys)
Definition anim_draw.cc:339
void ANIM_center_frame(bContext *C, int smooth_viewtx)
Definition anim_draw.cc:696
rctf ANIM_frame_range_view2d_add_xmargin(const View2D &view_2d, const rctf view_rect)
Definition anim_draw.cc:739
float ANIM_nla_tweakedit_remap(bAnimListElem *ale, const float cframe, const eNlaTime_ConvertModes mode)
Definition anim_draw.cc:262
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, const eAnimFilter_Flags filter_mode, void *data, const eAnimCont_Types datatype)
ListBase * ED_context_get_markers(const bContext *C)
TimeMarker * ED_markers_get_first_selected(ListBase *markers)
const Map< FramesMapKeyT, GreasePencilFrame > & frames() const
std::optional< int > start_frame_at(int frame_number) const
ItemIterator items() const &
Definition BLI_map.hh:902
const Map< FramesMapKeyT, GreasePencilFrame > & frames() const
#define SELECT
#define ceilf(x)
#define floorf(x)
#define fabsf(x)
void ED_gpencil_layer_frames_keytype_set(bGPDlayer *gpl, short type)
void ED_gpencil_layer_frames_duplicate(bGPDlayer *gpl)
bool ED_gpencil_layer_frames_delete(bGPDlayer *gpl)
bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
bool ED_gpencil_layer_frame_select_check(const bGPDlayer *gpl)
void ED_gpencil_layer_mirror_frames(bGPDlayer *gpl, Scene *scene, short mode)
void ED_gpencil_layer_snap_frames(bGPDlayer *gpl, Scene *scene, short mode)
bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac)
#define filter
#define GS(a)
KeyframeEditFunc ANIM_editkeyframes_mirror(short mode)
KeyframeEditFunc ANIM_editkeyframes_easing(short mode)
KeyframeEditFunc ANIM_editkeyframes_ipo(short mode)
short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, FCurve *fcu, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
KeyframeEditFunc ANIM_editkeyframes_keytype(const eBezTriple_KeyframeType keyframe_type)
KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
KeyframeEditFunc ANIM_editkeyframes_snap(short mode)
void ANIM_animdata_keyframe_callback(bAnimContext *ac, eAnimFilter_Flags filter, KeyframeEditFunc callback_fn)
short bezt_calc_average(KeyframeEditData *ked, BezTriple *bezt)
KeyframeEditFunc ANIM_editkeyframes_handles(short mode)
const EnumPropertyItem rna_enum_keyframe_paste_offset_items[]
const EnumPropertyItem rna_enum_keyframe_paste_merge_items[]
bool copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
void clean_fcurve(bAnimListElem *ale, float thresh, bool cleardefault, const bool only_selected_keys)
eKeyPasteError paste_animedit_keys(bAnimContext *ac, ListBase *anim_data, const KeyframePasteContext &paste_context)
bool duplicate_fcurve_keys(FCurve *fcu)
#define G(x, y, z)
void assert_baklava_phase_1_invariants(const Action &action)
void animdata_fcurve_delete(AnimData *adt, FCurve *fcu)
Definition animdata.cc:251
KeyframeSettings get_keyframe_settings(bool from_userprefs)
CombinedKeyingResult insert_keyframes(Main *bmain, PointerRNA *struct_pointer, std::optional< StringRefNull > channel_group, const blender::Span< RNAPath > rna_paths, std::optional< float > scene_frame, const AnimationEvalContext &anim_eval_context, eBezTriple_KeyframeType key_type, eInsertKeyFlags insert_key_flags)
Main key-frame insertion API.
SingleKeyingResult insert_vert_fcurve(FCurve *fcu, const float2 position, const KeyframeSettings &settings, eInsertKeyFlags flag)
Main Key-framing API call.
ID * action_slot_get_id_for_keying(Main &bmain, Action &action, slot_handle_t slot_handle, ID *primary_id)
void bake_fcurve_segments(FCurve *fcu)
eInsertKeyFlags get_keyframing_flags(Scene *scene)
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)
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)
bool duplicate_selected_frames(GreasePencil &grease_pencil, bke::greasepencil::Layer &layer)
bool snap_selected_frames(GreasePencil &grease_pencil, bke::greasepencil::Layer &layer, Scene &scene, const eEditKeyframes_Snap mode)
float wrap(float value, float max, float min)
Definition node_math.h:71
float RNA_float_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_id_pointer_create(ID *id)
const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[]
Definition rna_curve.cc:64
const EnumPropertyItem rna_enum_keyframe_handle_type_items[]
Definition rna_curve.cc:36
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
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_translation_context(PropertyRNA *prop, const char *context)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
const EnumPropertyItem rna_enum_beztriple_interpolation_easing_items[]
const EnumPropertyItem rna_enum_beztriple_keyframe_type_items[]
Definition rna_fcurve.cc:77
#define min(a, b)
Definition sort.cc:36
#define FLT_MAX
Definition stdcycles.h:14
bActionGroup * grp
short extend
ListBase modifiers
struct FModifier * next
Definition DNA_ID.h:404
char name[66]
Definition DNA_ID.h:415
eKeyPasteValueOffset value_offset_mode
eKeyPasteOffset offset_mode
void * last
void * first
ListBase splines_shapes
bool update(Progress &progress)
Definition scene.cpp:592
struct ToolSettings * toolsettings
struct RenderData r
unsigned int flag
struct TimeMarker * next
ListBase markers
bool(* has_setting)(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting)
eAnimChannel_Role channel_role
ListBase * markers
eAnimCont_Types datatype
ReportList * reports
ARegion * region
Depsgraph * depsgraph
int32_t slot_handle
bAnimListElem * next
eBezTriple_KeyframeType keyframe_type
float xmax
float xmin
float ymax
float ymin
struct ReportList * reports
struct PointerRNA * ptr
max
Definition text_draw.cc:251
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4226
wmOperatorType * ot
Definition wm_files.cc:4225
void WM_operator_properties_confirm_or_exec(wmOperatorType *ot)
wmOperatorStatus WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)
int WM_operator_smooth_viewtx_get(const wmOperator *op)
wmOperatorStatus WM_operator_confirm_ex(bContext *C, wmOperator *op, const char *title, const char *message, const char *confirm_text, int icon, bool cancel_default)
uint8_t flag
Definition wm_window.cc:139