Blender V5.0
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_math_base.h"
17#include "BLI_string.h"
18#include "BLI_utildefines.h"
19
20#include "BLT_translation.hh"
21
22#include "DEG_depsgraph.hh"
23
24#include "DNA_anim_types.h"
26#include "DNA_mask_types.h"
27#include "DNA_scene_types.h"
28
29#include "RNA_access.hh"
30#include "RNA_define.hh"
31#include "RNA_enum_types.hh"
32
33#include "BKE_animsys.h"
34#include "BKE_context.hh"
35#include "BKE_fcurve.hh"
36#include "BKE_global.hh"
37#include "BKE_gpencil_legacy.h"
38#include "BKE_grease_pencil.hh"
39#include "BKE_nla.hh"
40#include "BKE_report.hh"
41
42#include "UI_interface_icons.hh"
43#include "UI_view2d.hh"
44
45#include "ANIM_action.hh"
46#include "ANIM_animdata.hh"
47#include "ANIM_fcurve.hh"
48#include "ANIM_keyframing.hh"
49#include "ED_anim_api.hh"
50#include "ED_gpencil_legacy.hh"
51#include "ED_grease_pencil.hh"
52#include "ED_keyframes_edit.hh"
53#include "ED_keyframing.hh"
54#include "ED_markers.hh"
55#include "ED_mask.hh"
56#include "ED_screen.hh"
57
58#include "WM_api.hh"
59#include "WM_types.hh"
60
61#include "action_intern.hh"
62
63/* -------------------------------------------------------------------- */
66
67/* ensure that there is:
68 * 1) an active action editor
69 * 2) that the set of markers being shown are the scene markers, not the list we're merging
70 * 3) that the mode will have an active action available
71 * 4) that there are some selected markers
72 */
74{
76
77 /* 1) */
78 if (sact == nullptr) {
79 return false;
80 }
81
82 /* 2) */
83 if (sact->flag & SACTION_POSEMARKERS_SHOW) {
84 return false;
85 }
86
87 /* 3) */
90 if (!active_action) {
91 return false;
92 }
93
94 /* 4) */
96}
97
99{
103
104 TimeMarker *marker, *markern = nullptr;
105
106 /* sanity checks */
107 if (ELEM(nullptr, markers, act)) {
108 return OPERATOR_CANCELLED;
109 }
110
111 /* migrate markers */
112 for (marker = static_cast<TimeMarker *>(markers->first); marker; marker = markern) {
113 markern = marker->next;
114
115 /* move if marker is selected */
116 if (marker->flag & SELECT) {
117 BLI_remlink(markers, marker);
118 BLI_addtail(&act->markers, marker);
119 }
120 }
121
122 /* Now enable the "show pose-markers only" setting,
123 * 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
857 ReportList *reports = ac->reports;
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 = static_cast<FCurve *>(ale->key_data);
1148 changed = BKE_fcurve_delete_keys_selected(fcu);
1149
1150 if (changed && BKE_fcurve_is_empty(fcu)) {
1151 ED_anim_ale_fcurve_delete(*ac, *ale);
1152 ale->key_data = nullptr;
1153 }
1154 }
1155
1156 if (changed) {
1157 ale->update |= ANIM_UPDATE_DEFAULT;
1158 changed_final = true;
1159 }
1160 }
1161
1162 ANIM_animdata_update(ac, &anim_data);
1163 ANIM_animdata_freelist(&anim_data);
1164
1165 return changed_final;
1166}
1167
1168/* ------------------- */
1169
1171{
1172 bAnimContext ac;
1173
1174 /* get editor data */
1175 if (ANIM_animdata_get_context(C, &ac) == 0) {
1176 return OPERATOR_CANCELLED;
1177 }
1178
1179 /* delete keyframes */
1180 if (!delete_action_keys(&ac)) {
1181 return OPERATOR_CANCELLED;
1182 }
1183
1184 /* set notifier that keyframes have changed */
1186
1187 return OPERATOR_FINISHED;
1188}
1189
1191 wmOperator *op,
1192 const wmEvent * /*event*/)
1193{
1194 if (RNA_boolean_get(op->ptr, "confirm")) {
1196 op,
1197 IFACE_("Delete selected keyframes?"),
1198 nullptr,
1199 IFACE_("Delete"),
1201 false);
1202 }
1203 return actkeys_delete_exec(C, op);
1204}
1205
1207{
1208 /* identifiers */
1209 ot->name = "Delete Keyframes";
1210 ot->idname = "ACTION_OT_delete";
1211 ot->description = "Remove all selected keyframes";
1212
1213 /* API callbacks. */
1214 ot->invoke = actkeys_delete_invoke;
1215 ot->exec = actkeys_delete_exec;
1217
1218 /* flags */
1219 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1221}
1222
1224
1225/* -------------------------------------------------------------------- */
1228
1229static void clean_action_keys(bAnimContext *ac, float thresh, bool clean_chan)
1230{
1231 ListBase anim_data = {nullptr, nullptr};
1233
1234 /* filter data */
1237
1238 if (clean_chan) {
1240 }
1241
1242 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1243
1244 const bool only_selected_keys = !clean_chan;
1245 /* loop through filtered data and clean curves */
1246 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1247 clean_fcurve(ale, thresh, clean_chan, only_selected_keys);
1248
1249 ale->update |= ANIM_UPDATE_DEFAULT;
1250 }
1251
1252 ANIM_animdata_update(ac, &anim_data);
1253 ANIM_animdata_freelist(&anim_data);
1254}
1255
1256/* ------------------- */
1257
1259{
1260 bAnimContext ac;
1261 float thresh;
1262 bool clean_chan;
1263
1264 /* get editor data */
1265 if (ANIM_animdata_get_context(C, &ac) == 0) {
1266 return OPERATOR_CANCELLED;
1267 }
1268
1270 BKE_report(op->reports, RPT_ERROR, "Not implemented");
1271 return OPERATOR_PASS_THROUGH;
1272 }
1273
1274 /* get cleaning threshold */
1275 thresh = RNA_float_get(op->ptr, "threshold");
1276 clean_chan = RNA_boolean_get(op->ptr, "channels");
1277
1278 /* clean keyframes */
1279 clean_action_keys(&ac, thresh, clean_chan);
1280
1281 /* set notifier that keyframes have changed */
1283
1284 return OPERATOR_FINISHED;
1285}
1286
1288{
1289 /* identifiers */
1290 ot->name = "Clean Keyframes";
1291 ot->idname = "ACTION_OT_clean";
1292 ot->description = "Simplify F-Curves by removing closely spaced keyframes";
1293
1294 /* API callbacks. */
1295 // ot->invoke = /* XXX we need that number popup for this! */
1296 ot->exec = actkeys_clean_exec;
1298
1299 /* flags */
1300 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1301
1302 /* properties */
1303 ot->prop = RNA_def_float(
1304 ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
1305 RNA_def_boolean(ot->srna, "channels", false, "Channels", "");
1306}
1307
1309
1310/* -------------------------------------------------------------------- */
1313
1314/* Evaluates the curves between each selected keyframe on each frame, and keys the value. */
1316{
1317 ListBase anim_data = {nullptr, nullptr};
1319
1320 /* filter data */
1323 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1324
1325 /* Loop through filtered data and add keys between selected keyframes on every frame. */
1326 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1328
1329 ale->update |= ANIM_UPDATE_DEPS;
1330 }
1331
1332 ANIM_animdata_update(ac, &anim_data);
1333 ANIM_animdata_freelist(&anim_data);
1334}
1335
1336/* ------------------- */
1337
1339{
1340 bAnimContext ac;
1341
1342 /* get editor data */
1343 if (ANIM_animdata_get_context(C, &ac) == 0) {
1344 return OPERATOR_CANCELLED;
1345 }
1346
1348 BKE_report(op->reports, RPT_ERROR, "Not implemented");
1349 return OPERATOR_PASS_THROUGH;
1350 }
1351
1352 /* sample keyframes */
1353 bake_action_keys(&ac);
1354
1355 /* set notifier that keyframes have changed */
1357
1358 return OPERATOR_FINISHED;
1359}
1360
1362{
1363 /* identifiers */
1364 ot->name = "Bake Keyframes";
1365 ot->idname = "ACTION_OT_bake_keys";
1366 ot->description = "Add keyframes on every frame between the selected keyframes";
1367
1368 /* API callbacks. */
1369 ot->exec = actkeys_bake_exec;
1371
1372 /* flags */
1373 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1374}
1375
1377
1378/* -------------------------------------------------------------------- */
1381
1382/* defines for make/clear cyclic extrapolation tools */
1383#define MAKE_CYCLIC_EXPO -1
1384#define CLEAR_CYCLIC_EXPO -2
1385
1386/* defines for set extrapolation-type for selected keyframes tool */
1389 "CONSTANT",
1390 0,
1391 "Constant Extrapolation",
1392 "Values on endpoint keyframes are held"},
1394 "LINEAR",
1395 0,
1396 "Linear Extrapolation",
1397 "Straight-line slope of end segments are extended past the endpoint keyframes"},
1398
1400 "MAKE_CYCLIC",
1401 0,
1402 "Make Cyclic (F-Modifier)",
1403 "Add Cycles F-Modifier if one does not exist already"},
1405 "CLEAR_CYCLIC",
1406 0,
1407 "Clear Cyclic (F-Modifier)",
1408 "Remove Cycles F-Modifier if not needed anymore"},
1409 {0, nullptr, 0, nullptr, nullptr},
1410};
1411
1412/* this function is responsible for setting extrapolation mode for keyframes */
1413static void setexpo_action_keys(bAnimContext *ac, short mode)
1414{
1415 ListBase anim_data = {nullptr, nullptr};
1417
1418 /* filter data */
1421 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1422
1423 /* loop through setting mode per F-Curve */
1424 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1425 FCurve *fcu = (FCurve *)ale->data;
1426
1427 if (mode >= 0) {
1428 /* just set mode setting */
1429 fcu->extend = mode;
1430 }
1431 else {
1432 /* shortcuts for managing Cycles F-Modifiers to make it easier to toggle cyclic animation
1433 * without having to go through FModifier UI in Graph Editor to do so
1434 */
1435 if (mode == MAKE_CYCLIC_EXPO) {
1436 /* only add if one doesn't exist */
1438 /* TODO: add some more preset versions which set different extrapolation options? */
1440 }
1441 }
1442 else if (mode == CLEAR_CYCLIC_EXPO) {
1443 /* remove all the modifiers fitting this description */
1444 FModifier *fcm, *fcn = nullptr;
1445
1446 for (fcm = static_cast<FModifier *>(fcu->modifiers.first); fcm; fcm = fcn) {
1447 fcn = fcm->next;
1448
1449 if (fcm->type == FMODIFIER_TYPE_CYCLES) {
1450 remove_fmodifier(&fcu->modifiers, fcm);
1451 }
1452 }
1453 }
1454 }
1455
1456 ale->update |= ANIM_UPDATE_DEFAULT;
1457 }
1458
1459 ANIM_animdata_update(ac, &anim_data);
1460 ANIM_animdata_freelist(&anim_data);
1461}
1462
1463/* ------------------- */
1464
1466{
1467 bAnimContext ac;
1468 short mode;
1469
1470 /* get editor data */
1471 if (ANIM_animdata_get_context(C, &ac) == 0) {
1472 return OPERATOR_CANCELLED;
1473 }
1474
1476 BKE_report(op->reports, RPT_ERROR, "Not implemented");
1477 return OPERATOR_PASS_THROUGH;
1478 }
1479
1480 /* get handle setting mode */
1481 mode = RNA_enum_get(op->ptr, "type");
1482
1483 /* set handle type */
1484 setexpo_action_keys(&ac, mode);
1485
1486 /* set notifier that keyframe properties have changed */
1488
1489 return OPERATOR_FINISHED;
1490}
1491
1493{
1494 /* identifiers */
1495 ot->name = "Set F-Curve Extrapolation";
1496 ot->idname = "ACTION_OT_extrapolation_type";
1497 ot->description = "Set extrapolation mode for selected F-Curves";
1498
1499 /* API callbacks. */
1500 ot->invoke = WM_menu_invoke;
1501 ot->exec = actkeys_expo_exec;
1503
1504 /* flags */
1505 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1506
1507 /* id-props */
1508 ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_expo_types, 0, "Type", "");
1509}
1510
1512
1513/* -------------------------------------------------------------------- */
1516
1518{
1519 bAnimContext ac;
1520 short mode;
1521
1522 /* get editor data */
1523 if (ANIM_animdata_get_context(C, &ac) == 0) {
1524 return OPERATOR_CANCELLED;
1525 }
1526
1528 BKE_report(op->reports, RPT_ERROR, "Not implemented");
1529 return OPERATOR_PASS_THROUGH;
1530 }
1531
1532 /* get handle setting mode */
1533 mode = RNA_enum_get(op->ptr, "type");
1534
1535 /* set handle type */
1541
1542 /* set notifier that keyframe properties have changed */
1544
1545 return OPERATOR_FINISHED;
1546}
1547
1549{
1550 /* identifiers */
1551 ot->name = "Set Keyframe Interpolation";
1552 ot->idname = "ACTION_OT_interpolation_type";
1553 ot->description =
1554 "Set interpolation mode for the F-Curve segments starting from the selected keyframes";
1555
1556 /* API callbacks. */
1557 ot->invoke = WM_menu_invoke;
1558 ot->exec = actkeys_ipo_exec;
1560
1561 /* flags */
1562 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1563
1564 /* id-props */
1565 ot->prop = RNA_def_enum(
1566 ot->srna, "type", rna_enum_beztriple_interpolation_mode_items, 0, "Type", "");
1568}
1569
1571
1572/* -------------------------------------------------------------------- */
1575
1577{
1578 bAnimContext ac;
1579 short mode;
1580
1581 /* get editor data */
1582 if (ANIM_animdata_get_context(C, &ac) == 0) {
1583 return OPERATOR_CANCELLED;
1584 }
1585
1586 /* get handle setting mode */
1587 mode = RNA_enum_get(op->ptr, "type");
1588
1589 /* set handle type */
1595
1596 /* set notifier that keyframe properties have changed */
1598
1599 return OPERATOR_FINISHED;
1600}
1601
1603{
1604 /* identifiers */
1605 ot->name = "Set Keyframe Easing Type";
1606 ot->idname = "ACTION_OT_easing_type";
1607 ot->description =
1608 "Set easing type for the F-Curve segments starting from the selected keyframes";
1609
1610 /* API callbacks. */
1611 ot->invoke = WM_menu_invoke;
1612 ot->exec = actkeys_easing_exec;
1614
1615 /* flags */
1616 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1617
1618 /* id-props */
1619 ot->prop = RNA_def_enum(
1620 ot->srna, "type", rna_enum_beztriple_interpolation_easing_items, 0, "Type", "");
1621}
1622
1624
1625/* -------------------------------------------------------------------- */
1628
1629/* this function is responsible for setting handle-type of selected keyframes */
1630static void sethandles_action_keys(bAnimContext *ac, short mode)
1631{
1632 ListBase anim_data = {nullptr, nullptr};
1634
1637
1638 /* filter data */
1641 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1642
1643 /* Loop through setting flags for handles
1644 * NOTE: we do not supply KeyframeEditData to the looper yet.
1645 * Currently that's not necessary here.
1646 */
1647 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1648 FCurve *fcu = (FCurve *)ale->key_data;
1649
1650 /* any selected keyframes for editing? */
1651 if (ANIM_fcurve_keyframes_loop(nullptr, fcu, nullptr, sel_cb, nullptr)) {
1652 /* change type of selected handles */
1653 ANIM_fcurve_keyframes_loop(nullptr, fcu, nullptr, edit_cb, BKE_fcurve_handles_recalc);
1654
1655 ale->update |= ANIM_UPDATE_DEFAULT;
1656 }
1657 }
1658
1659 ANIM_animdata_update(ac, &anim_data);
1660 ANIM_animdata_freelist(&anim_data);
1661}
1662
1663/* ------------------- */
1664
1666{
1667 bAnimContext ac;
1668 short mode;
1669
1670 /* get editor data */
1671 if (ANIM_animdata_get_context(C, &ac) == 0) {
1672 return OPERATOR_CANCELLED;
1673 }
1674
1676 BKE_report(op->reports, RPT_ERROR, "Not implemented");
1677 return OPERATOR_PASS_THROUGH;
1678 }
1679
1680 /* get handle setting mode */
1681 mode = RNA_enum_get(op->ptr, "type");
1682
1683 /* set handle type */
1684 sethandles_action_keys(&ac, mode);
1685
1686 /* set notifier that keyframe properties have changed */
1688
1689 return OPERATOR_FINISHED;
1690}
1691
1693{
1694 /* identifiers */
1695 ot->name = "Set Keyframe Handle Type";
1696 ot->idname = "ACTION_OT_handle_type";
1697 ot->description = "Set type of handle for selected keyframes";
1698
1699 /* API callbacks. */
1700 ot->invoke = WM_menu_invoke;
1703
1704 /* flags */
1705 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1706
1707 /* id-props */
1708 ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_keyframe_handle_type_items, 0, "Type", "");
1709}
1710
1712
1713/* -------------------------------------------------------------------- */
1716
1717/* this function is responsible for setting keyframe type for keyframes */
1719{
1720 ListBase anim_data = {nullptr, nullptr};
1723
1724 /* filter data */
1727 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1728
1729 /* Loop through setting BezTriple interpolation
1730 * NOTE: we do not supply KeyframeEditData to the looper yet.
1731 * Currently that's not necessary here.
1732 */
1733 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1734 switch (ale->type) {
1735 case ANIMTYPE_GPLAYER:
1736 ED_gpencil_layer_frames_keytype_set(static_cast<bGPDlayer *>(ale->data), mode);
1737 ale->update |= ANIM_UPDATE_DEPS;
1738 break;
1739
1742 static_cast<GreasePencilLayer *>(ale->data)->wrap(), mode);
1743 ale->update |= ANIM_UPDATE_DEPS;
1744 break;
1745
1746 case ANIMTYPE_FCURVE:
1748 nullptr, static_cast<FCurve *>(ale->key_data), nullptr, set_cb, nullptr);
1749 ale->update |= ANIM_UPDATE_DEPS | ANIM_UPDATE_HANDLES;
1750 break;
1751
1752 default:
1753 BLI_assert_msg(false, "Keytype cannot be set into this animation type.");
1754 }
1755 }
1756
1757 ANIM_animdata_update(ac, &anim_data);
1758 ANIM_animdata_freelist(&anim_data);
1759}
1760
1761/* ------------------- */
1762
1764{
1765 bAnimContext ac;
1766
1767 /* get editor data */
1768 if (ANIM_animdata_get_context(C, &ac) == 0) {
1769 return OPERATOR_CANCELLED;
1770 }
1771
1772 if (ac.datatype == ANIMCONT_MASK) {
1773 BKE_report(op->reports, RPT_ERROR, "Not implemented for Masks");
1774 return OPERATOR_PASS_THROUGH;
1775 }
1776
1777 const int mode = RNA_enum_get(op->ptr, "type");
1779
1780 /* set notifier that keyframe properties have changed */
1782
1783 return OPERATOR_FINISHED;
1784}
1785
1787{
1788 /* identifiers */
1789 ot->name = "Set Keyframe Type";
1790 ot->idname = "ACTION_OT_keyframe_type";
1791 ot->description = "Set type of keyframe for the selected keyframes";
1792
1793 /* API callbacks. */
1794 ot->invoke = WM_menu_invoke;
1795 ot->exec = actkeys_keytype_exec;
1797
1798 /* flags */
1799 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1800
1801 /* id-props */
1802 ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_beztriple_keyframe_type_items, 0, "Type", "");
1803}
1804
1806
1807/* -------------------------------------------------------------------- */
1810
1812{
1813 /* prevent changes during render */
1814 if (G.is_rendering) {
1815 return false;
1816 }
1817
1819}
1820
1821/* snap current-frame indicator to 'average time' of selected keyframe */
1823{
1824 bAnimContext ac;
1825 ListBase anim_data = {nullptr, nullptr};
1827 KeyframeEditData ked = {{nullptr}};
1828
1829 /* get editor data */
1830 if (ANIM_animdata_get_context(C, &ac) == 0) {
1831 return OPERATOR_CANCELLED;
1832 }
1833
1834 /* init edit data */
1835 /* loop over action data, averaging values */
1837 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
1838
1839 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1840 switch (ale->datatype) {
1841 case ALE_GPFRAME: {
1842 bGPDlayer *gpl = static_cast<bGPDlayer *>(ale->data);
1843
1844 LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
1845 /* only if selected */
1846 if (!(gpf->flag & GP_FRAME_SELECT)) {
1847 continue;
1848 }
1849 /* store average time in float 1 (only do rounding at last step) */
1850 ked.f1 += gpf->framenum;
1851
1852 /* increment number of items */
1853 ked.i1++;
1854 }
1855 break;
1856 }
1857
1858 case ALE_GREASE_PENCIL_CEL: {
1859 using namespace blender::bke::greasepencil;
1860 const Layer &layer = *static_cast<Layer *>(ale->data);
1861 for (auto [frame_number, frame] : layer.frames().items()) {
1862 if (!frame.is_selected()) {
1863 continue;
1864 }
1865 ked.f1 += frame_number;
1866 ked.i1++;
1867 }
1868 break;
1869 }
1870
1871 case ALE_FCURVE: {
1872 FCurve *fcurve = static_cast<FCurve *>(ale->key_data);
1873 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcurve, false, true);
1874 ANIM_fcurve_keyframes_loop(&ked, fcurve, nullptr, bezt_calc_average, nullptr);
1875 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcurve, true, true);
1876 break;
1877 }
1878
1879 default:
1880 BLI_assert_msg(false, "Cannot jump to keyframe into this animation type.");
1881 }
1882 }
1883
1884 ANIM_animdata_freelist(&anim_data);
1885
1886 /* set the new current frame value, based on the average time */
1887 if (ked.i1) {
1888 Scene *scene = ac.scene;
1889 scene->r.cfra = round_fl_to_int(ked.f1 / ked.i1);
1890 scene->r.subframe = 0.0f;
1891 }
1892
1893 /* set notifier that things have changed */
1895
1896 return OPERATOR_FINISHED;
1897}
1898
1900{
1901 /* identifiers */
1902 ot->name = "Jump to Keyframes";
1903 ot->idname = "ACTION_OT_frame_jump";
1904 ot->description = "Set the current frame to the average frame value of selected keyframes";
1905
1906 /* API callbacks. */
1907 ot->exec = actkeys_framejump_exec;
1908 ot->poll = actkeys_framejump_poll;
1909
1910 /* flags */
1911 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1912}
1913
1915
1916/* -------------------------------------------------------------------- */
1919
1920/* defines for snap keyframes tool */
1923 "CFRA",
1924 0,
1925 "Selection to Current Frame",
1926 "Snap selected keyframes to the current frame"},
1928 "NEAREST_FRAME",
1929 0,
1930 "Selection to Nearest Frame",
1931 "Snap selected keyframes to the nearest (whole) frame "
1932 "(use to fix accidental subframe offsets)"},
1934 "NEAREST_SECOND",
1935 0,
1936 "Selection to Nearest Second",
1937 "Snap selected keyframes to the nearest second"},
1939 "NEAREST_MARKER",
1940 0,
1941 "Selection to Nearest Marker",
1942 "Snap selected keyframes to the nearest marker"},
1943 {0, nullptr, 0, nullptr, nullptr},
1944};
1945
1946/* this function is responsible for snapping keyframes to frame-times */
1947static void snap_action_keys(bAnimContext *ac, short mode)
1948{
1949 ListBase anim_data = {nullptr, nullptr};
1951
1952 KeyframeEditData ked = {{nullptr}};
1953 KeyframeEditFunc edit_cb;
1954
1955 /* filter data */
1958 }
1959 else {
1962 }
1963 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1964
1965 /* get beztriple editing callbacks */
1966 edit_cb = ANIM_editkeyframes_snap(mode);
1967
1968 ked.scene = ac->scene;
1969 if (mode == ACTKEYS_SNAP_NEAREST_MARKER) {
1970 ked.list.first = (ac->markers) ? ac->markers->first : nullptr;
1971 ked.list.last = (ac->markers) ? ac->markers->last : nullptr;
1972 }
1973
1974 /* snap keyframes */
1975 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1976 if (ale->type == ANIMTYPE_GPLAYER) {
1977 ED_gpencil_layer_snap_frames(static_cast<bGPDlayer *>(ale->data), ac->scene, mode);
1978 }
1979 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1980 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(ale->id);
1981 GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(ale->data);
1982
1984 *grease_pencil, layer->wrap(), *(ac->scene), static_cast<eEditKeyframes_Snap>(mode));
1985
1986 if (changed) {
1987 DEG_id_tag_update(&grease_pencil->id, ID_RECALC_GEOMETRY);
1988 }
1989 }
1990 else if (ale->type == ANIMTYPE_MASKLAYER) {
1991 ED_masklayer_snap_frames(static_cast<MaskLayer *>(ale->data), ac->scene, mode);
1992 }
1993 else {
1994 FCurve *fcurve = static_cast<FCurve *>(ale->key_data);
1995 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcurve, false, false);
1996 ANIM_fcurve_keyframes_loop(&ked, fcurve, nullptr, edit_cb, BKE_fcurve_handles_recalc);
1998 fcurve, SELECT, false); /* only use handles in graph editor */
1999 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcurve, true, false);
2000 }
2001
2003 }
2004
2005 ANIM_animdata_update(ac, &anim_data);
2006 ANIM_animdata_freelist(&anim_data);
2007}
2008
2009/* ------------------- */
2010
2012{
2013 bAnimContext ac;
2014 short mode;
2015
2016 /* get editor data */
2017 if (ANIM_animdata_get_context(C, &ac) == 0) {
2018 return OPERATOR_CANCELLED;
2019 }
2020
2021 /* get snapping mode */
2022 mode = RNA_enum_get(op->ptr, "type");
2023
2024 /* snap keyframes */
2025 snap_action_keys(&ac, mode);
2026
2027 /* set notifier that keyframes have changed */
2029
2030 return OPERATOR_FINISHED;
2031}
2032
2034{
2035 /* identifiers */
2036 ot->name = "Snap Keys";
2037 ot->idname = "ACTION_OT_snap";
2038 ot->description = "Snap selected keyframes to the times specified";
2039
2040 /* API callbacks. */
2041 ot->invoke = WM_menu_invoke;
2042 ot->exec = actkeys_snap_exec;
2044
2045 /* flags */
2046 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2047
2048 /* id-props */
2049 ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_snap_types, 0, "Type", "");
2050}
2051
2053
2054/* -------------------------------------------------------------------- */
2057
2058/* defines for mirror keyframes tool */
2061 "CFRA",
2062 0,
2063 "By Times Over Current Frame",
2064 "Flip times of selected keyframes using the current frame as the mirror line"},
2066 "XAXIS",
2067 0,
2068 "By Values Over Zero Value",
2069 "Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"},
2071 "MARKER",
2072 0,
2073 "By Times Over First Selected Marker",
2074 "Flip times of selected keyframes using the first selected marker as the reference point"},
2075 {0, nullptr, 0, nullptr, nullptr},
2076};
2077
2078/* this function is responsible for mirroring keyframes */
2079static void mirror_action_keys(bAnimContext *ac, short mode)
2080{
2081 ListBase anim_data = {nullptr, nullptr};
2083
2084 KeyframeEditData ked = {{nullptr}};
2085 KeyframeEditFunc edit_cb;
2086
2087 /* get beztriple editing callbacks */
2088 edit_cb = ANIM_editkeyframes_mirror(mode);
2089
2090 ked.scene = ac->scene;
2091
2092 /* for 'first selected marker' mode, need to find first selected marker first! */
2093 /* XXX should this be made into a helper func in the API? */
2094 if (mode == ACTKEYS_MIRROR_MARKER) {
2096
2097 if (marker) {
2098 ked.f1 = float(marker->frame);
2099 }
2100 else {
2101 return;
2102 }
2103 }
2104
2105 /* filter data */
2108 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
2109
2110 /* mirror keyframes */
2111 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
2112 if (ale->type == ANIMTYPE_GPLAYER) {
2113 ED_gpencil_layer_mirror_frames(static_cast<bGPDlayer *>(ale->data), ac->scene, mode);
2114 }
2115 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
2116 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(ale->id);
2117 GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(ale->data);
2118
2120 *grease_pencil, layer->wrap(), *(ac->scene), static_cast<eEditKeyframes_Mirror>(mode));
2121
2122 if (changed) {
2123 DEG_id_tag_update(&grease_pencil->id, ID_RECALC_GEOMETRY);
2124 }
2125 }
2126 else if (ale->type == ANIMTYPE_MASKLAYER) {
2127 /* TODO */
2128 }
2129 else {
2130 FCurve *fcurve = static_cast<FCurve *>(ale->key_data);
2131 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcurve, false, false);
2132 ANIM_fcurve_keyframes_loop(&ked, fcurve, nullptr, edit_cb, BKE_fcurve_handles_recalc);
2133 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcurve, true, false);
2134 }
2135
2136 ale->update |= ANIM_UPDATE_DEFAULT;
2137 }
2138
2139 ANIM_animdata_update(ac, &anim_data);
2140 ANIM_animdata_freelist(&anim_data);
2141}
2142
2143/* ------------------- */
2144
2146{
2147 bAnimContext ac;
2148 short mode;
2149
2150 /* get editor data */
2151 if (ANIM_animdata_get_context(C, &ac) == 0) {
2152 return OPERATOR_CANCELLED;
2153 }
2154
2155 /* get mirroring mode */
2156 mode = RNA_enum_get(op->ptr, "type");
2157
2158 /* mirror keyframes */
2159 mirror_action_keys(&ac, mode);
2160
2161 /* set notifier that keyframes have changed */
2163
2164 return OPERATOR_FINISHED;
2165}
2166
2168{
2169 /* identifiers */
2170 ot->name = "Mirror Keys";
2171 ot->idname = "ACTION_OT_mirror";
2172 ot->description = "Flip selected keyframes over the selected mirror line";
2173
2174 /* API callbacks. */
2175 ot->invoke = WM_menu_invoke;
2176 ot->exec = actkeys_mirror_exec;
2178
2179 /* flags */
2180 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2181
2182 /* id-props */
2183 ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_mirror_types, 0, "Type", "");
2184}
2185
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:738
bScreen * CTX_wm_screen(const bContext *C)
SpaceAction * CTX_wm_space_action(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
ViewLayer * CTX_data_view_layer(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:552
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:549
@ RPT_ERROR
Definition BKE_report.hh:39
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
#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:1074
@ ID_AC
@ 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:693
bool ED_operator_action_active(bContext *C)
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
#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:1939
void UI_view2d_center_set(View2D *v2d, float x, float y)
Definition view2d.cc:1949
#define ND_DATA
Definition WM_types.hh:509
#define NC_ANIMATION
Definition WM_types.hh:388
#define NC_SCENE
Definition WM_types.hh:378
#define NA_ADDED
Definition WM_types.hh:586
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NA_EDITED
Definition WM_types.hh:584
#define ND_KEYFRAME_PROP
Definition WM_types.hh:495
#define ND_MARKERS
Definition WM_types.hh:433
#define ND_FRAME
Definition WM_types.hh:434
#define NA_REMOVED
Definition WM_types.hh:587
#define NC_GPENCIL
Definition WM_types.hh:399
#define ND_KEYFRAME
Definition WM_types.hh:494
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 ED_anim_ale_fcurve_delete(bAnimContext &ac, 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:401
void ANIM_center_frame(bContext *C, int smooth_viewtx)
Definition anim_draw.cc:768
rctf ANIM_frame_range_view2d_add_xmargin(const View2D &view_2d, const rctf view_rect)
Definition anim_draw.cc:811
float ANIM_nla_tweakedit_remap(bAnimListElem *ale, const float cframe, const eNlaTime_ConvertModes mode)
Definition anim_draw.cc:324
bAction * ANIM_active_action_from_area(Scene *scene, ViewLayer *view_layer, const ScrArea *area, ID **r_action_user)
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
nullptr float
#define SELECT
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 GS(x)
#define filter
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)
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:103
#define floorf
#define fabsf
#define ceilf
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:414
char name[258]
Definition DNA_ID.h:432
eKeyPasteValueOffset value_offset_mode
eKeyPasteOffset offset_mode
void * last
void * first
ListBase splines_shapes
bool update(Progress &progress)
Definition scene.cpp:623
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:4238
wmOperatorType * ot
Definition wm_files.cc:4237
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:145