Blender V4.3
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
9#include <cfloat>
10#include <cmath>
11#include <cstdlib>
12#include <cstring>
13
14#include "BLI_blenlib.h"
15#include "BLI_map.hh"
16#include "BLI_utildefines.h"
17
18#include "BLT_translation.hh"
19
20#include "DEG_depsgraph.hh"
21
22#include "DNA_anim_types.h"
24#include "DNA_mask_types.h"
25#include "DNA_scene_types.h"
26
27#include "RNA_access.hh"
28#include "RNA_define.hh"
29#include "RNA_enum_types.hh"
30
31#include "BKE_animsys.h"
32#include "BKE_context.hh"
33#include "BKE_fcurve.hh"
34#include "BKE_global.hh"
35#include "BKE_gpencil_legacy.h"
36#include "BKE_grease_pencil.hh"
37#include "BKE_nla.hh"
38#include "BKE_report.hh"
39
40#include "UI_interface_icons.hh"
41#include "UI_view2d.hh"
42
43#include "ANIM_action.hh"
44#include "ANIM_animdata.hh"
45#include "ANIM_fcurve.hh"
46#include "ANIM_keyframing.hh"
47#include "ED_anim_api.hh"
48#include "ED_gpencil_legacy.hh"
49#include "ED_grease_pencil.hh"
50#include "ED_keyframes_edit.hh"
51#include "ED_keyframing.hh"
52#include "ED_markers.hh"
53#include "ED_mask.hh"
54#include "ED_screen.hh"
55
56#include "WM_api.hh"
57#include "WM_types.hh"
58
59#include "action_intern.hh"
60
61/* -------------------------------------------------------------------- */
65/* ensure that there is:
66 * 1) an active action editor
67 * 2) that the mode will have an active action available
68 * 3) that the set of markers being shown are the scene markers, not the list we're merging
69 * 4) that there are some selected markers
70 */
72{
74
75 /* 1) */
76 if (sact == nullptr) {
77 return false;
78 }
79
80 /* 2) */
81 if (ELEM(sact->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY) == 0) {
82 return false;
83 }
84 if (sact->action == nullptr) {
85 return false;
86 }
87
88 /* 3) */
89 if (sact->flag & SACTION_POSEMARKERS_SHOW) {
90 return false;
91 }
92
93 /* 4) */
95}
96
98{
100
102 bAction *act = (sact) ? sact->action : nullptr;
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. */
125
126 /* notifiers - both sets, as this change affects both */
129
130 return OPERATOR_FINISHED;
131}
132
134{
135 /* identifiers */
136 ot->name = "Make Markers Local";
137 ot->idname = "ACTION_OT_markers_make_local";
138 ot->description = "Move selected scene markers to the active Action as local 'pose' markers";
139
140 /* callbacks */
143
144 /* flags */
146}
147
150/* -------------------------------------------------------------------- */
154/* Get the min/max keyframes. */
155static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const short onlySel)
156{
157 ListBase anim_data = {nullptr, nullptr};
159 bool found = false;
160
161 /* get data to filter, from Action or Dopesheet */
162 /* XXX: what is sel doing here?!
163 * Commented it, was breaking things (eg. the "auto preview range" tool). */
164 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_SEL */ |
166 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
167
168 /* set large values to try to override */
169 *min = 999999999.0f;
170 *max = -999999999.0f;
171
172 /* check if any channels to set range with */
173 if (anim_data.first) {
174 /* go through channels, finding max extents */
175 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
176 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
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)) {
219
220 if (adt) {
223 }
224
225 /* Try to set cur using these values,
226 * if they're more extreme than previously set values. */
227 *min = min_ff(*min, tmin);
228 *max = max_ff(*max, tmax);
229 found = true;
230 }
231 }
232 }
233
234 if (fabsf(*max - *min) < 0.001f) {
235 *min -= 0.0005f;
236 *max += 0.0005f;
237 }
238
239 /* free memory */
240 ANIM_animdata_freelist(&anim_data);
241 }
242 else {
243 /* set default range */
244 if (ac->scene) {
245 *min = float(ac->scene->r.sfra);
246 *max = float(ac->scene->r.efra);
247 }
248 else {
249 *min = -5;
250 *max = 100;
251 }
252 }
253
254 return found;
255}
256
259/* -------------------------------------------------------------------- */
264{
265 bAnimContext ac;
266 Scene *scene;
267 float min, max;
268
269 /* get editor data */
270 if (ANIM_animdata_get_context(C, &ac) == 0) {
271 return OPERATOR_CANCELLED;
272 }
273 if (ac.scene == nullptr) {
274 return OPERATOR_CANCELLED;
275 }
276
277 /* set the range directly */
278 if (!get_keyframe_extents(&ac, &min, &max, true)) {
279 return OPERATOR_CANCELLED;
280 }
281 scene = ac.scene;
282 scene->r.flag |= SCER_PRV_RANGE;
283 scene->r.psfra = floorf(min);
284 scene->r.pefra = ceilf(max);
285
286 if (scene->r.psfra == scene->r.pefra) {
287 scene->r.pefra = scene->r.psfra + 1;
288 }
289
290 /* set notifier that things have changed */
291 /* XXX err... there's nothing for frame ranges yet, but this should do fine too */
293
294 return OPERATOR_FINISHED;
295}
296
298{
299 /* identifiers */
300 ot->name = "Set Preview Range to Selected";
301 ot->idname = "ACTION_OT_previewrange_set";
302 ot->description = "Set Preview Range based on extents of selected Keyframes";
303
304 /* api callbacks */
307
308 /* flags */
310}
311
314/* -------------------------------------------------------------------- */
325static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *r_min, float *r_max)
326{
327 ListBase anim_data = {nullptr, nullptr};
328 bAnimListElem *ale;
330
331 /* NOTE: not bool, since we want prioritize individual channels over expanders. */
332 short found = 0;
333
334 /* get all items - we need to do it this way */
336 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
337
338 /* loop through all channels, finding the first one that's selected */
339 float ymax = ANIM_UI_get_first_channel_top(&ac->region->v2d);
340 const float channel_step = ANIM_UI_get_channel_step();
341 for (ale = static_cast<bAnimListElem *>(anim_data.first); ale;
342 ale = ale->next, ymax -= channel_step)
343 {
345
346 /* must be selected... */
347 if (acf && acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT) &&
349 {
350 /* update best estimate */
351 *r_min = ymax - ANIM_UI_get_channel_height();
352 *r_max = ymax;
353
354 /* is this high enough priority yet? */
355 found = acf->channel_role;
356
357 /* only stop our search when we've found an actual channel
358 * - data-block expanders get less priority so that we don't abort prematurely
359 */
360 if (found == ACHANNEL_ROLE_CHANNEL) {
361 break;
362 }
363 }
364 }
365
366 /* free all temp data */
367 ANIM_animdata_freelist(&anim_data);
368
369 return (found != 0);
370}
371
372static int actkeys_viewall(bContext *C, const bool only_sel)
373{
374 bAnimContext ac;
375 View2D *v2d;
376 float min, max;
377 bool found;
378
379 /* get editor data */
380 if (ANIM_animdata_get_context(C, &ac) == 0) {
381 return OPERATOR_CANCELLED;
382 }
383 v2d = &ac.region->v2d;
384
385 /* set the horizontal range, with an extra offset so that the extreme keys will be in view */
386 found = get_keyframe_extents(&ac, &min, &max, only_sel);
387
388 if (only_sel && (found == false)) {
389 return OPERATOR_CANCELLED;
390 }
391
392 if (fabsf(max - min) < 1.0f) {
393 /* Exception - center the single keyframe. */
394 float xwidth = BLI_rctf_size_x(&v2d->cur);
395
396 v2d->cur.xmin = min - xwidth / 2.0f;
397 v2d->cur.xmax = max + xwidth / 2.0f;
398 }
399 else {
400 /* Normal case - stretch the two keyframes out to fill the space, with extra spacing */
401 v2d->cur.xmin = min;
402 v2d->cur.xmax = max;
403
405 }
406
407 /* set vertical range */
408 if (only_sel == false) {
409 /* view all -> the summary channel is usually the shows everything,
410 * and resides right at the top... */
411 v2d->cur.ymax = 0.0f;
412 v2d->cur.ymin = float(-BLI_rcti_size_y(&v2d->mask));
413 }
414 else {
415 /* locate first selected channel (or the active one), and frame those */
416 float ymin = v2d->cur.ymin;
417 float ymax = v2d->cur.ymax;
418
419 if (actkeys_channels_get_selected_extents(&ac, &ymin, &ymax)) {
420 /* recenter the view so that this range is in the middle */
421 float ymid = (ymax - ymin) / 2.0f + ymin;
422 float x_center;
423
424 UI_view2d_center_get(v2d, &x_center, nullptr);
425 UI_view2d_center_set(v2d, x_center, ymid);
426 }
427 }
428
429 /* do View2D syncing */
431
432 /* just redraw this view */
434
435 return OPERATOR_FINISHED;
436}
437
438/* ......... */
439
441{
442 /* whole range */
443 return actkeys_viewall(C, false);
444}
445
447{
448 /* only selected */
449 return actkeys_viewall(C, true);
450}
451
452/* ......... */
453
455{
456 /* identifiers */
457 ot->name = "Frame All";
458 ot->idname = "ACTION_OT_view_all";
459 ot->description = "Reset viewable area to show full keyframe range";
460
461 /* api callbacks */
464
465 /* flags */
466 ot->flag = 0;
467}
468
470{
471 /* identifiers */
472 ot->name = "Frame Selected";
473 ot->idname = "ACTION_OT_view_selected";
474 ot->description = "Reset viewable area to show selected keyframes range";
475
476 /* api callbacks */
479
480 /* flags */
481 ot->flag = 0;
482}
483
486/* -------------------------------------------------------------------- */
491{
492 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
493 ANIM_center_frame(C, smooth_viewtx);
494
495 return OPERATOR_FINISHED;
496}
497
499{
500 /* identifiers */
501 ot->name = "Go to Current Frame";
502 ot->idname = "ACTION_OT_view_frame";
503 ot->description = "Move the view to the current frame";
504
505 /* api callbacks */
508
509 /* flags */
510 ot->flag = 0;
511}
512
515/* -------------------------------------------------------------------- */
519/* NOTE: the backend code for this is shared with the graph editor */
520
522{
523 ListBase anim_data = {nullptr, nullptr};
525 short ok = 0;
526
527 /* clear buffer first */
529
530 /* filter data */
533 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
534
535 /* copy keyframes */
536 ok = copy_animedit_keys(ac, &anim_data);
537
538 /* clean up */
539 ANIM_animdata_freelist(&anim_data);
540
541 return ok;
542}
543
545 const eKeyPasteOffset offset_mode,
546 const eKeyMergeMode merge_mode,
547 bool flip)
548{
549 ListBase anim_data = {nullptr, nullptr};
551
552 /* filter data
553 * - First time we try to filter more strictly, allowing only selected channels
554 * to allow copying animation between channels
555 * - Second time, we loosen things up if nothing was found the first time, allowing
556 * users to just paste keyframes back into the original curve again #31670.
557 */
560
562 ac, &anim_data, filter | ANIMFILTER_SEL, ac->data, eAnimCont_Types(ac->datatype)) == 0)
563 {
564 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
565 }
566
567 /* Value offset is always None because the user cannot see the effect of it. */
569 ac, &anim_data, offset_mode, KEYFRAME_PASTE_VALUE_OFFSET_NONE, merge_mode, flip);
570
571 /* clean up */
572 ANIM_animdata_freelist(&anim_data);
573
574 return ok;
575}
576
577/* ------------------- */
578
584
586{
587 bAnimContext ac;
588
589 /* get editor data */
590 if (ANIM_animdata_get_context(C, &ac) == 0) {
591 return OPERATOR_CANCELLED;
592 }
593
594 /* copy keyframes */
595 if (ac.datatype == ANIMCONT_GPENCIL) {
596 if (ED_gpencil_anim_copybuf_copy(&ac) == false &&
599 {
600 /* check if anything ended up in the buffer */
601 BKE_report(op->reports, RPT_ERROR, "No keyframes copied to the internal clipboard");
602 return OPERATOR_CANCELLED;
603 }
604 }
605 else if (ac.datatype == ANIMCONT_MASK) {
606 /* FIXME: support this case. */
607 BKE_report(op->reports, RPT_ERROR, "Keyframe pasting is not available for mask mode");
608 return OPERATOR_CANCELLED;
609 }
610 else {
611 /* Both copy function needs to be evaluated to account for mixed selection */
612 const short kf_empty = copy_action_keys(&ac);
613 const bool gpf_ok = ED_gpencil_anim_copybuf_copy(&ac) ||
616
617 if (kf_empty && !gpf_ok) {
618 BKE_report(op->reports, RPT_ERROR, "No keyframes copied to the internal clipboard");
619 return OPERATOR_CANCELLED;
620 }
621 }
622
623 return OPERATOR_FINISHED;
624}
625
627{
628 /* identifiers */
629 ot->name = "Copy Keyframes";
630 ot->idname = "ACTION_OT_copy";
631 ot->description = "Copy selected keyframes to the internal clipboard";
632
633 /* api callbacks */
636
637 /* flags */
639}
640
642{
643 bAnimContext ac;
644
645 const eKeyPasteOffset offset_mode = eKeyPasteOffset(RNA_enum_get(op->ptr, "offset"));
646 const eKeyMergeMode merge_mode = eKeyMergeMode(RNA_enum_get(op->ptr, "merge"));
647 const bool flipped = RNA_boolean_get(op->ptr, "flipped");
648
649 bool gpframes_inbuf = false;
650
651 /* get editor data */
652 if (ANIM_animdata_get_context(C, &ac) == 0) {
653 return OPERATOR_CANCELLED;
654 }
655
656 /* ac.reports by default will be the global reports list, which won't show warnings */
657 ac.reports = op->reports;
658
659 /* paste keyframes */
660 if (ac.datatype == ANIMCONT_GPENCIL) {
661 if (ED_gpencil_anim_copybuf_paste(&ac, offset_mode) == false &&
663 &ac, offset_mode, merge_mode, get_grease_pencil_keyframe_clipboard()) == false)
664 {
665 BKE_report(op->reports, RPT_ERROR, "No data in the internal clipboard to paste");
666 return OPERATOR_CANCELLED;
667 }
668 }
669 else if (ac.datatype == ANIMCONT_MASK) {
670 /* FIXME: support this case. */
672 RPT_ERROR,
673 "Keyframe pasting is not available for grease pencil or mask mode");
674 return OPERATOR_CANCELLED;
675 }
676 else {
677 /* Both paste function needs to be evaluated to account for mixed selection */
678 const eKeyPasteError kf_empty = paste_action_keys(&ac, offset_mode, merge_mode, flipped);
679 /* non-zero return means an error occurred while trying to paste */
680 gpframes_inbuf = ED_gpencil_anim_copybuf_paste(&ac, offset_mode) ||
682 &ac, offset_mode, merge_mode, get_grease_pencil_keyframe_clipboard());
683
684 /* Only report an error if nothing was pasted, i.e. when both FCurve and GPencil failed. */
685 if (!gpframes_inbuf) {
686 switch (kf_empty) {
688 /* FCurve paste was ok, so it's all good. */
689 break;
690
692 BKE_report(op->reports, RPT_ERROR, "No selected F-Curves to paste into");
693 return OPERATOR_CANCELLED;
694
696 BKE_report(op->reports, RPT_ERROR, "No data in the internal clipboard to paste");
697 return OPERATOR_CANCELLED;
698 }
699 }
700 }
701
702 /* Grease Pencil needs extra update to refresh the added keyframes. */
703 if (ac.datatype == ANIMCONT_GPENCIL || gpframes_inbuf) {
705 }
706 /* set notifier that keyframes have changed */
708
709 return OPERATOR_FINISHED;
710}
711
712static std::string actkeys_paste_get_description(bContext * /*C*/,
713 wmOperatorType * /*ot*/,
715{
716 /* Custom description if the 'flipped' option is used. */
717 if (RNA_boolean_get(ptr, "flipped")) {
718 return BLI_strdup(TIP_("Paste keyframes from mirrored bones if they exist"));
719 }
720
721 /* Use the default description in the other cases. */
722 return "";
723}
724
726{
727 PropertyRNA *prop;
728 /* identifiers */
729 ot->name = "Paste Keyframes";
730 ot->idname = "ACTION_OT_paste";
731 ot->description =
732 "Paste keyframes from the internal clipboard for the selected channels, starting on the "
733 "current "
734 "frame";
735
736 /* api callbacks */
737 // ot->invoke = WM_operator_props_popup; /* Better wait for action redo panel. */
741
742 /* flags */
744
745 /* props */
747 "offset",
750 "Offset",
751 "Paste time offset of keys");
753 "merge",
756 "Type",
757 "Method of merging pasted keys and existing");
758 prop = RNA_def_boolean(
759 ot->srna, "flipped", false, "Flipped", "Paste keyframes from mirrored bones if they exist");
761}
762
765/* -------------------------------------------------------------------- */
769/* defines for insert keyframes tool */
771 {1, "ALL", 0, "All Channels", ""},
772 {2, "SEL", 0, "Only Selected Channels", ""},
773 /* XXX not in all cases. */
774 {3, "GROUP", 0, "In Active Group", ""},
775 {0, nullptr, 0, nullptr, nullptr},
776};
777
779 bAnimListElem *ale,
780 const eGP_GetFrame_Mode add_frame_mode,
781 bGPdata **gpd_old)
782{
783 Scene *scene = ac->scene;
784 bGPdata *gpd = (bGPdata *)ale->id;
785 bGPDlayer *gpl = (bGPDlayer *)ale->data;
786 BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, add_frame_mode);
787 /* Check if the gpd changes to tag only once. */
788 if (gpd != *gpd_old) {
789 BKE_gpencil_tag(gpd);
790 *gpd_old = gpd;
791 }
792}
793
795 bAnimListElem *ale,
796 const bool hold_previous)
797{
798 using namespace blender::bke::greasepencil;
799 Layer *layer = static_cast<Layer *>(ale->data);
800 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(ale->id);
801 const int current_frame_number = ac->scene->r.cfra;
802
803 if (layer->frames().contains(current_frame_number)) {
804 return;
805 }
806
807 bool changed = false;
808 if (hold_previous) {
809 const std::optional<int> active_frame_number = layer->start_frame_at(current_frame_number);
810 if (!active_frame_number) {
811 /* There is no active frame to hold to, or it's an end frame. Therefore just insert a blank
812 * frame. */
813 changed |= grease_pencil->insert_frame(*layer, current_frame_number) != nullptr;
814 }
815 else {
816 /* Duplicate the active frame. */
817 changed = grease_pencil->insert_duplicate_frame(
818 *layer, *active_frame_number, current_frame_number, false);
819 }
820 }
821 else {
822 /* Insert a blank frame. */
823 changed |= grease_pencil->insert_frame(*layer, current_frame_number) != nullptr;
824 }
825
826 if (changed) {
827 DEG_id_tag_update(&grease_pencil->id, ID_RECALC_GEOMETRY);
828 }
829}
830
832 bAnimListElem *ale,
833 const AnimationEvalContext anim_eval_context,
835{
836 using namespace blender::animrig;
837 FCurve *fcu = (FCurve *)ale->key_data;
838
839 ReportList *reports = ac->reports;
840 Scene *scene = ac->scene;
841 ToolSettings *ts = scene->toolsettings;
842
843 /* These asserts are ensuring that the fcurve we're keying lives on an Action,
844 * rather than being an fcurve for e.g. a driver or NLA Strip. This should
845 * always hold true for this function, since all the other cases take
846 * different code paths before getting here. */
847 BLI_assert(ale->owner == nullptr);
848 BLI_assert(ale->fcurve_owner_id != nullptr);
850
851 bAction *action = reinterpret_cast<bAction *>(ale->fcurve_owner_id);
852 ID *id = action_slot_get_id_for_keying(*ale->bmain, action->wrap(), ale->slot_handle, ale->id);
853
854 /* If we found an unambiguous ID to use for keying the channel, go through the
855 * normal keyframing code path. Otherwise, just directly key the fcurve
856 * itself. */
857 if (id) {
858 const std::optional<blender::StringRefNull> channel_group = fcu->grp ?
859 std::optional(fcu->grp->name) :
860 std::nullopt;
861 PointerRNA id_rna_pointer = RNA_id_pointer_create(id);
862 CombinedKeyingResult result = insert_keyframes(ac->bmain,
863 &id_rna_pointer,
864 channel_group,
865 {{fcu->rna_path, {}, fcu->array_index}},
866 std::nullopt,
867 anim_eval_context,
869 flag);
870 if (result.get_count(SingleKeyingResult::SUCCESS) == 0) {
871 result.generate_reports(reports);
872 }
873 }
874 else {
875 /* TODO: when layered action strips are allowed to have time offsets, that
876 * mapping will need to be handled here. */
877 assert_baklava_phase_1_invariants(action->wrap());
878
879 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
880
881 /* adjust current frame for NLA-scaling */
882 float cfra = anim_eval_context.eval_time;
883 if (adt) {
885 }
886
887 const float curval = evaluate_fcurve(fcu, cfra);
889 settings.keyframe_type = eBezTriple_KeyframeType(ts->keyframe_type);
890 insert_vert_fcurve(fcu, {cfra, curval}, settings, eInsertKeyFlags(0));
891 }
892
893 ale->update |= ANIM_UPDATE_DEFAULT;
894}
895
896/* this function is responsible for inserting new keyframes */
897static void insert_action_keys(bAnimContext *ac, short mode)
898{
899 ListBase anim_data = {nullptr, nullptr};
901
902 Scene *scene = ac->scene;
903 ToolSettings *ts = scene->toolsettings;
905
906 eGP_GetFrame_Mode add_frame_mode;
907 bGPdata *gpd_old = nullptr;
908
909 /* filter data */
912 if (mode == 2) {
913 filter |= ANIMFILTER_SEL;
914 }
915 else if (mode == 3) {
916 filter |= ANIMFILTER_ACTGROUPED;
917 }
918
919 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
920
921 /* Init keyframing flag. */
923
924 /* GPLayers specific flags */
926 add_frame_mode = GP_GETFRAME_ADD_COPY;
927 }
928 else {
929 add_frame_mode = GP_GETFRAME_ADD_NEW;
930 }
931 const bool grease_pencil_hold_previous = ((ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) != 0);
932
933 /* insert keyframes */
935 ac->depsgraph, float(scene->r.cfra));
936 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
937 switch (ale->type) {
938 case ANIMTYPE_GPLAYER:
939 insert_gpencil_key(ac, ale, add_frame_mode, &gpd_old);
940 break;
941
943 insert_grease_pencil_key(ac, ale, grease_pencil_hold_previous);
944 break;
945
946 case ANIMTYPE_FCURVE:
947 insert_fcurve_key(ac, ale, anim_eval_context, flag);
948 break;
949
950 default:
951 BLI_assert_msg(false, "Keys cannot be inserted into this animation type.");
952 }
953 }
954
955 ANIM_animdata_update(ac, &anim_data);
956 ANIM_animdata_freelist(&anim_data);
957}
958
959/* ------------------- */
960
962{
963 bAnimContext ac;
964 short mode;
965
966 /* get editor data */
967 if (ANIM_animdata_get_context(C, &ac) == 0) {
968 return OPERATOR_CANCELLED;
969 }
970
971 if (ac.datatype == ANIMCONT_MASK) {
972 BKE_report(op->reports, RPT_ERROR, "Insert Keyframes is not yet implemented for this mode");
973 return OPERATOR_CANCELLED;
974 }
975
976 /* what channels to affect? */
977 mode = RNA_enum_get(op->ptr, "type");
978
980
981 /* insert keyframes */
982 insert_action_keys(&ac, mode);
983
984 /* set notifier that keyframes have changed */
985 if (ac.datatype == ANIMCONT_GPENCIL) {
987 }
989
990 return OPERATOR_FINISHED;
991}
992
994{
995 /* identifiers */
996 ot->name = "Insert Keyframes";
997 ot->idname = "ACTION_OT_keyframe_insert";
998 ot->description = "Insert keyframes for the specified channels";
999
1000 /* api callbacks */
1004
1005 /* flags */
1007
1008 /* id-props */
1009 ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_insertkey_types, 0, "Type", "");
1010}
1011
1014/* -------------------------------------------------------------------- */
1019{
1020 ListBase anim_data = {nullptr, nullptr};
1022 bool changed = false;
1023
1024 /* filter data */
1027 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1028
1029 /* loop through filtered data and delete selected keys */
1030 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1031 if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
1032 changed |= duplicate_fcurve_keys((FCurve *)ale->key_data);
1033 }
1034 else if (ale->type == ANIMTYPE_GPLAYER) {
1036 changed |= ED_gpencil_layer_frame_select_check((bGPDlayer *)ale->data);
1037 }
1038 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1040 *reinterpret_cast<GreasePencil *>(ale->id),
1041 static_cast<GreasePencilLayer *>(ale->data)->wrap());
1042 }
1043 else if (ale->type == ANIMTYPE_MASKLAYER) {
1044 changed |= ED_masklayer_frames_duplicate((MaskLayer *)ale->data);
1045 }
1046 else {
1047 BLI_assert(0);
1048 }
1049
1050 ale->update |= ANIM_UPDATE_DEFAULT;
1051 }
1052
1053 ANIM_animdata_update(ac, &anim_data);
1054 ANIM_animdata_freelist(&anim_data);
1055
1056 return changed;
1057}
1058
1059/* ------------------- */
1060
1062{
1063 bAnimContext ac;
1064
1065 /* get editor data */
1066 if (ANIM_animdata_get_context(C, &ac) == 0) {
1067 return OPERATOR_CANCELLED;
1068 }
1069
1070 /* duplicate keyframes */
1071 if (!duplicate_action_keys(&ac)) {
1072 return OPERATOR_CANCELLED;
1073 }
1074
1075 /* set notifier that keyframes have changed */
1077
1078 return OPERATOR_FINISHED;
1079}
1080
1082{
1083 /* identifiers */
1084 ot->name = "Duplicate Keyframes";
1085 ot->idname = "ACTION_OT_duplicate";
1086 ot->description = "Make a copy of all selected keyframes";
1087
1088 /* api callbacks */
1091
1092 /* flags */
1094}
1095
1098/* -------------------------------------------------------------------- */
1103{
1104 ListBase anim_data = {nullptr, nullptr};
1106 bool changed_final = false;
1107
1108 /* filter data */
1111 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1112
1113 /* loop through filtered data and delete selected keys */
1114 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1115 bool changed = false;
1116
1117 if (ale->type == ANIMTYPE_GPLAYER) {
1118 changed = ED_gpencil_layer_frames_delete((bGPDlayer *)ale->data);
1119 }
1120 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1121 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(ale->id);
1123 *grease_pencil, static_cast<GreasePencilLayer *>(ale->data)->wrap());
1124
1125 if (changed) {
1126 DEG_id_tag_update(&grease_pencil->id, ID_RECALC_GEOMETRY);
1127 }
1128 }
1129 else if (ale->type == ANIMTYPE_MASKLAYER) {
1130 changed = ED_masklayer_frames_delete((MaskLayer *)ale->data);
1131 }
1132 else {
1133 FCurve *fcu = (FCurve *)ale->key_data;
1134 AnimData *adt = ale->adt;
1135
1136 /* delete selected keyframes only */
1137 changed = BKE_fcurve_delete_keys_selected(fcu);
1138
1139 /* Only delete curve too if it won't be doing anything anymore */
1140 if (BKE_fcurve_is_empty(fcu)) {
1142 ale->key_data = nullptr;
1143 }
1144 }
1145
1146 if (changed) {
1147 ale->update |= ANIM_UPDATE_DEFAULT;
1148 changed_final = true;
1149 }
1150 }
1151
1152 ANIM_animdata_update(ac, &anim_data);
1153 ANIM_animdata_freelist(&anim_data);
1154
1155 return changed_final;
1156}
1157
1158/* ------------------- */
1159
1161{
1162 bAnimContext ac;
1163
1164 /* get editor data */
1165 if (ANIM_animdata_get_context(C, &ac) == 0) {
1166 return OPERATOR_CANCELLED;
1167 }
1168
1169 /* delete keyframes */
1170 if (!delete_action_keys(&ac)) {
1171 return OPERATOR_CANCELLED;
1172 }
1173
1174 /* set notifier that keyframes have changed */
1176
1177 return OPERATOR_FINISHED;
1178}
1179
1180static int actkeys_delete_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
1181{
1182 if (RNA_boolean_get(op->ptr, "confirm")) {
1183 return WM_operator_confirm_ex(C,
1184 op,
1185 IFACE_("Delete selected keyframes?"),
1186 nullptr,
1187 IFACE_("Delete"),
1189 false);
1190 }
1191 return actkeys_delete_exec(C, op);
1192}
1193
1195{
1196 /* identifiers */
1197 ot->name = "Delete Keyframes";
1198 ot->idname = "ACTION_OT_delete";
1199 ot->description = "Remove all selected keyframes";
1200
1201 /* api callbacks */
1205
1206 /* flags */
1209}
1210
1213/* -------------------------------------------------------------------- */
1217static void clean_action_keys(bAnimContext *ac, float thresh, bool clean_chan)
1218{
1219 ListBase anim_data = {nullptr, nullptr};
1221
1222 /* filter data */
1225
1226 if (clean_chan) {
1227 filter |= ANIMFILTER_SEL;
1228 }
1229
1230 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1231
1232 const bool only_selected_keys = !clean_chan;
1233 /* loop through filtered data and clean curves */
1234 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1235 clean_fcurve(ac, ale, thresh, clean_chan, only_selected_keys);
1236
1237 ale->update |= ANIM_UPDATE_DEFAULT;
1238 }
1239
1240 ANIM_animdata_update(ac, &anim_data);
1241 ANIM_animdata_freelist(&anim_data);
1242}
1243
1244/* ------------------- */
1245
1247{
1248 bAnimContext ac;
1249 float thresh;
1250 bool clean_chan;
1251
1252 /* get editor data */
1253 if (ANIM_animdata_get_context(C, &ac) == 0) {
1254 return OPERATOR_CANCELLED;
1255 }
1256
1258 BKE_report(op->reports, RPT_ERROR, "Not implemented");
1259 return OPERATOR_PASS_THROUGH;
1260 }
1261
1262 /* get cleaning threshold */
1263 thresh = RNA_float_get(op->ptr, "threshold");
1264 clean_chan = RNA_boolean_get(op->ptr, "channels");
1265
1266 /* clean keyframes */
1267 clean_action_keys(&ac, thresh, clean_chan);
1268
1269 /* set notifier that keyframes have changed */
1271
1272 return OPERATOR_FINISHED;
1273}
1274
1276{
1277 /* identifiers */
1278 ot->name = "Clean Keyframes";
1279 ot->idname = "ACTION_OT_clean";
1280 ot->description = "Simplify F-Curves by removing closely spaced keyframes";
1281
1282 /* api callbacks */
1283 // ot->invoke = /* XXX we need that number popup for this! */
1286
1287 /* flags */
1289
1290 /* properties */
1292 ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
1293 RNA_def_boolean(ot->srna, "channels", false, "Channels", "");
1294}
1295
1298/* -------------------------------------------------------------------- */
1302/* Evaluates the curves between each selected keyframe on each frame, and keys the value. */
1304{
1305 ListBase anim_data = {nullptr, nullptr};
1307
1308 /* filter data */
1311 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1312
1313 /* Loop through filtered data and add keys between selected keyframes on every frame. */
1314 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1316
1317 ale->update |= ANIM_UPDATE_DEPS;
1318 }
1319
1320 ANIM_animdata_update(ac, &anim_data);
1321 ANIM_animdata_freelist(&anim_data);
1322}
1323
1324/* ------------------- */
1325
1327{
1328 bAnimContext ac;
1329
1330 /* get editor data */
1331 if (ANIM_animdata_get_context(C, &ac) == 0) {
1332 return OPERATOR_CANCELLED;
1333 }
1334
1336 BKE_report(op->reports, RPT_ERROR, "Not implemented");
1337 return OPERATOR_PASS_THROUGH;
1338 }
1339
1340 /* sample keyframes */
1341 bake_action_keys(&ac);
1342
1343 /* set notifier that keyframes have changed */
1345
1346 return OPERATOR_FINISHED;
1347}
1348
1350{
1351 /* identifiers */
1352 ot->name = "Bake Keyframes";
1353 ot->idname = "ACTION_OT_bake_keys";
1354 ot->description = "Add keyframes on every frame between the selected keyframes";
1355
1356 /* api callbacks */
1359
1360 /* flags */
1362}
1363
1366/* -------------------------------------------------------------------- */
1370/* defines for make/clear cyclic extrapolation tools */
1371#define MAKE_CYCLIC_EXPO -1
1372#define CLEAR_CYCLIC_EXPO -2
1373
1374/* defines for set extrapolation-type for selected keyframes tool */
1377 "CONSTANT",
1378 0,
1379 "Constant Extrapolation",
1380 "Values on endpoint keyframes are held"},
1382 "LINEAR",
1383 0,
1384 "Linear Extrapolation",
1385 "Straight-line slope of end segments are extended past the endpoint keyframes"},
1386
1388 "MAKE_CYCLIC",
1389 0,
1390 "Make Cyclic (F-Modifier)",
1391 "Add Cycles F-Modifier if one doesn't exist already"},
1393 "CLEAR_CYCLIC",
1394 0,
1395 "Clear Cyclic (F-Modifier)",
1396 "Remove Cycles F-Modifier if not needed anymore"},
1397 {0, nullptr, 0, nullptr, nullptr},
1398};
1399
1400/* this function is responsible for setting extrapolation mode for keyframes */
1401static void setexpo_action_keys(bAnimContext *ac, short mode)
1402{
1403 ListBase anim_data = {nullptr, nullptr};
1405
1406 /* filter data */
1409 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1410
1411 /* loop through setting mode per F-Curve */
1412 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1413 FCurve *fcu = (FCurve *)ale->data;
1414
1415 if (mode >= 0) {
1416 /* just set mode setting */
1417 fcu->extend = mode;
1418 }
1419 else {
1420 /* shortcuts for managing Cycles F-Modifiers to make it easier to toggle cyclic animation
1421 * without having to go through FModifier UI in Graph Editor to do so
1422 */
1423 if (mode == MAKE_CYCLIC_EXPO) {
1424 /* only add if one doesn't exist */
1426 /* TODO: add some more preset versions which set different extrapolation options? */
1428 }
1429 }
1430 else if (mode == CLEAR_CYCLIC_EXPO) {
1431 /* remove all the modifiers fitting this description */
1432 FModifier *fcm, *fcn = nullptr;
1433
1434 for (fcm = static_cast<FModifier *>(fcu->modifiers.first); fcm; fcm = fcn) {
1435 fcn = fcm->next;
1436
1437 if (fcm->type == FMODIFIER_TYPE_CYCLES) {
1438 remove_fmodifier(&fcu->modifiers, fcm);
1439 }
1440 }
1441 }
1442 }
1443
1444 ale->update |= ANIM_UPDATE_DEFAULT;
1445 }
1446
1447 ANIM_animdata_update(ac, &anim_data);
1448 ANIM_animdata_freelist(&anim_data);
1449}
1450
1451/* ------------------- */
1452
1454{
1455 bAnimContext ac;
1456 short mode;
1457
1458 /* get editor data */
1459 if (ANIM_animdata_get_context(C, &ac) == 0) {
1460 return OPERATOR_CANCELLED;
1461 }
1462
1464 BKE_report(op->reports, RPT_ERROR, "Not implemented");
1465 return OPERATOR_PASS_THROUGH;
1466 }
1467
1468 /* get handle setting mode */
1469 mode = RNA_enum_get(op->ptr, "type");
1470
1471 /* set handle type */
1472 setexpo_action_keys(&ac, mode);
1473
1474 /* set notifier that keyframe properties have changed */
1476
1477 return OPERATOR_FINISHED;
1478}
1479
1481{
1482 /* identifiers */
1483 ot->name = "Set F-Curve Extrapolation";
1484 ot->idname = "ACTION_OT_extrapolation_type";
1485 ot->description = "Set extrapolation mode for selected F-Curves";
1486
1487 /* api callbacks */
1491
1492 /* flags */
1494
1495 /* id-props */
1496 ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_expo_types, 0, "Type", "");
1497}
1498
1501/* -------------------------------------------------------------------- */
1506{
1507 bAnimContext ac;
1508 short mode;
1509
1510 /* get editor data */
1511 if (ANIM_animdata_get_context(C, &ac) == 0) {
1512 return OPERATOR_CANCELLED;
1513 }
1514
1516 BKE_report(op->reports, RPT_ERROR, "Not implemented");
1517 return OPERATOR_PASS_THROUGH;
1518 }
1519
1520 /* get handle setting mode */
1521 mode = RNA_enum_get(op->ptr, "type");
1522
1523 /* set handle type */
1529
1530 /* set notifier that keyframe properties have changed */
1532
1533 return OPERATOR_FINISHED;
1534}
1535
1537{
1538 /* identifiers */
1539 ot->name = "Set Keyframe Interpolation";
1540 ot->idname = "ACTION_OT_interpolation_type";
1541 ot->description =
1542 "Set interpolation mode for the F-Curve segments starting from the selected keyframes";
1543
1544 /* api callbacks */
1548
1549 /* flags */
1551
1552 /* id-props */
1553 ot->prop = RNA_def_enum(
1554 ot->srna, "type", rna_enum_beztriple_interpolation_mode_items, 0, "Type", "");
1556}
1557
1560/* -------------------------------------------------------------------- */
1565{
1566 bAnimContext ac;
1567 short mode;
1568
1569 /* get editor data */
1570 if (ANIM_animdata_get_context(C, &ac) == 0) {
1571 return OPERATOR_CANCELLED;
1572 }
1573
1574 /* get handle setting mode */
1575 mode = RNA_enum_get(op->ptr, "type");
1576
1577 /* set handle type */
1583
1584 /* set notifier that keyframe properties have changed */
1586
1587 return OPERATOR_FINISHED;
1588}
1589
1591{
1592 /* identifiers */
1593 ot->name = "Set Keyframe Easing Type";
1594 ot->idname = "ACTION_OT_easing_type";
1595 ot->description =
1596 "Set easing type for the F-Curve segments starting from the selected keyframes";
1597
1598 /* api callbacks */
1602
1603 /* flags */
1605
1606 /* id-props */
1607 ot->prop = RNA_def_enum(
1608 ot->srna, "type", rna_enum_beztriple_interpolation_easing_items, 0, "Type", "");
1609}
1610
1613/* -------------------------------------------------------------------- */
1617/* this function is responsible for setting handle-type of selected keyframes */
1618static void sethandles_action_keys(bAnimContext *ac, short mode)
1619{
1620 ListBase anim_data = {nullptr, nullptr};
1622
1625
1626 /* filter data */
1629 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1630
1631 /* Loop through setting flags for handles
1632 * NOTE: we do not supply KeyframeEditData to the looper yet.
1633 * Currently that's not necessary here.
1634 */
1635 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1636 FCurve *fcu = (FCurve *)ale->key_data;
1637
1638 /* any selected keyframes for editing? */
1639 if (ANIM_fcurve_keyframes_loop(nullptr, fcu, nullptr, sel_cb, nullptr)) {
1640 /* change type of selected handles */
1641 ANIM_fcurve_keyframes_loop(nullptr, fcu, nullptr, edit_cb, BKE_fcurve_handles_recalc);
1642
1643 ale->update |= ANIM_UPDATE_DEFAULT;
1644 }
1645 }
1646
1647 ANIM_animdata_update(ac, &anim_data);
1648 ANIM_animdata_freelist(&anim_data);
1649}
1650
1651/* ------------------- */
1652
1654{
1655 bAnimContext ac;
1656 short mode;
1657
1658 /* get editor data */
1659 if (ANIM_animdata_get_context(C, &ac) == 0) {
1660 return OPERATOR_CANCELLED;
1661 }
1662
1664 BKE_report(op->reports, RPT_ERROR, "Not implemented");
1665 return OPERATOR_PASS_THROUGH;
1666 }
1667
1668 /* get handle setting mode */
1669 mode = RNA_enum_get(op->ptr, "type");
1670
1671 /* set handle type */
1672 sethandles_action_keys(&ac, mode);
1673
1674 /* set notifier that keyframe properties have changed */
1676
1677 return OPERATOR_FINISHED;
1678}
1679
1681{
1682 /* identifiers */
1683 ot->name = "Set Keyframe Handle Type";
1684 ot->idname = "ACTION_OT_handle_type";
1685 ot->description = "Set type of handle for selected keyframes";
1686
1687 /* api callbacks */
1691
1692 /* flags */
1694
1695 /* id-props */
1696 ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_keyframe_handle_type_items, 0, "Type", "");
1697}
1698
1701/* -------------------------------------------------------------------- */
1705/* this function is responsible for setting keyframe type for keyframes */
1707{
1708 ListBase anim_data = {nullptr, nullptr};
1711
1712 /* filter data */
1715 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1716
1717 /* Loop through setting BezTriple interpolation
1718 * NOTE: we do not supply KeyframeEditData to the looper yet.
1719 * Currently that's not necessary here.
1720 */
1721 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1722 switch (ale->type) {
1723 case ANIMTYPE_GPLAYER:
1724 ED_gpencil_layer_frames_keytype_set(static_cast<bGPDlayer *>(ale->data), mode);
1725 ale->update |= ANIM_UPDATE_DEPS;
1726 break;
1727
1730 static_cast<GreasePencilLayer *>(ale->data)->wrap(),
1731 static_cast<eBezTriple_KeyframeType>(mode));
1732 ale->update |= ANIM_UPDATE_DEPS;
1733 break;
1734
1735 case ANIMTYPE_FCURVE:
1737 nullptr, static_cast<FCurve *>(ale->key_data), nullptr, set_cb, nullptr);
1738 ale->update |= ANIM_UPDATE_DEPS | ANIM_UPDATE_HANDLES;
1739 break;
1740
1741 default:
1742 BLI_assert_msg(false, "Keytype cannot be set into this animation type.");
1743 }
1744 }
1745
1746 ANIM_animdata_update(ac, &anim_data);
1747 ANIM_animdata_freelist(&anim_data);
1748}
1749
1750/* ------------------- */
1751
1753{
1754 bAnimContext ac;
1755
1756 /* get editor data */
1757 if (ANIM_animdata_get_context(C, &ac) == 0) {
1758 return OPERATOR_CANCELLED;
1759 }
1760
1761 if (ac.datatype == ANIMCONT_MASK) {
1762 BKE_report(op->reports, RPT_ERROR, "Not implemented for Masks");
1763 return OPERATOR_PASS_THROUGH;
1764 }
1765
1766 const int mode = RNA_enum_get(op->ptr, "type");
1768
1769 /* set notifier that keyframe properties have changed */
1771
1772 return OPERATOR_FINISHED;
1773}
1774
1776{
1777 /* identifiers */
1778 ot->name = "Set Keyframe Type";
1779 ot->idname = "ACTION_OT_keyframe_type";
1780 ot->description = "Set type of keyframe for the selected keyframes";
1781
1782 /* api callbacks */
1786
1787 /* flags */
1789
1790 /* id-props */
1792}
1793
1796/* -------------------------------------------------------------------- */
1801{
1802 /* prevent changes during render */
1803 if (G.is_rendering) {
1804 return false;
1805 }
1806
1807 return ED_operator_action_active(C);
1808}
1809
1810/* snap current-frame indicator to 'average time' of selected keyframe */
1812{
1813 bAnimContext ac;
1814 ListBase anim_data = {nullptr, nullptr};
1816 KeyframeEditData ked = {{nullptr}};
1817
1818 /* get editor data */
1819 if (ANIM_animdata_get_context(C, &ac) == 0) {
1820 return OPERATOR_CANCELLED;
1821 }
1822
1823 /* init edit data */
1824 /* loop over action data, averaging values */
1826 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
1827
1828 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1829 switch (ale->datatype) {
1830 case ALE_GPFRAME: {
1831 bGPDlayer *gpl = static_cast<bGPDlayer *>(ale->data);
1832
1833 LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
1834 /* only if selected */
1835 if (!(gpf->flag & GP_FRAME_SELECT)) {
1836 continue;
1837 }
1838 /* store average time in float 1 (only do rounding at last step) */
1839 ked.f1 += gpf->framenum;
1840
1841 /* increment number of items */
1842 ked.i1++;
1843 }
1844 break;
1845 }
1846
1847 case ALE_GREASE_PENCIL_CEL: {
1848 using namespace blender::bke::greasepencil;
1849 const Layer &layer = *static_cast<Layer *>(ale->data);
1850 for (auto [frame_number, frame] : layer.frames().items()) {
1851 if (!frame.is_selected()) {
1852 continue;
1853 }
1854 ked.f1 += frame_number;
1855 ked.i1++;
1856 }
1857 break;
1858 }
1859
1860 case ALE_FCURVE: {
1861 AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
1862 FCurve *fcurve = static_cast<FCurve *>(ale->key_data);
1863 if (adt) {
1864 ANIM_nla_mapping_apply_fcurve(adt, fcurve, false, true);
1865 ANIM_fcurve_keyframes_loop(&ked, fcurve, nullptr, bezt_calc_average, nullptr);
1866 ANIM_nla_mapping_apply_fcurve(adt, fcurve, true, true);
1867 }
1868 else {
1869 ANIM_fcurve_keyframes_loop(&ked, fcurve, nullptr, bezt_calc_average, nullptr);
1870 }
1871 break;
1872 }
1873
1874 default:
1875 BLI_assert_msg(false, "Cannot jump to keyframe into this animation type.");
1876 }
1877 }
1878
1879 ANIM_animdata_freelist(&anim_data);
1880
1881 /* set the new current frame value, based on the average time */
1882 if (ked.i1) {
1883 Scene *scene = ac.scene;
1884 scene->r.cfra = round_fl_to_int(ked.f1 / ked.i1);
1885 scene->r.subframe = 0.0f;
1886 }
1887
1888 /* set notifier that things have changed */
1890
1891 return OPERATOR_FINISHED;
1892}
1893
1895{
1896 /* identifiers */
1897 ot->name = "Jump to Keyframes";
1898 ot->idname = "ACTION_OT_frame_jump";
1899 ot->description = "Set the current frame to the average frame value of selected keyframes";
1900
1901 /* api callbacks */
1904
1905 /* flags */
1907}
1908
1911/* -------------------------------------------------------------------- */
1915/* defines for snap keyframes tool */
1918 "CFRA",
1919 0,
1920 "Selection to Current Frame",
1921 "Snap selected keyframes to the current frame"},
1923 "NEAREST_FRAME",
1924 0,
1925 "Selection to Nearest Frame",
1926 "Snap selected keyframes to the nearest (whole) frame "
1927 "(use to fix accidental subframe offsets)"},
1929 "NEAREST_SECOND",
1930 0,
1931 "Selection to Nearest Second",
1932 "Snap selected keyframes to the nearest second"},
1934 "NEAREST_MARKER",
1935 0,
1936 "Selection to Nearest Marker",
1937 "Snap selected keyframes to the nearest marker"},
1938 {0, nullptr, 0, nullptr, nullptr},
1939};
1940
1941/* this function is responsible for snapping keyframes to frame-times */
1942static void snap_action_keys(bAnimContext *ac, short mode)
1943{
1944 ListBase anim_data = {nullptr, nullptr};
1946
1947 KeyframeEditData ked = {{nullptr}};
1948 KeyframeEditFunc edit_cb;
1949
1950 /* filter data */
1953 }
1954 else {
1957 }
1958 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1959
1960 /* get beztriple editing callbacks */
1961 edit_cb = ANIM_editkeyframes_snap(mode);
1962
1963 ked.scene = ac->scene;
1964 if (mode == ACTKEYS_SNAP_NEAREST_MARKER) {
1965 ked.list.first = (ac->markers) ? ac->markers->first : nullptr;
1966 ked.list.last = (ac->markers) ? ac->markers->last : nullptr;
1967 }
1968
1969 /* snap keyframes */
1970 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1971 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
1972
1973 if (ale->type == ANIMTYPE_GPLAYER) {
1974 ED_gpencil_layer_snap_frames(static_cast<bGPDlayer *>(ale->data), ac->scene, mode);
1975 }
1976 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1977 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(ale->id);
1978 GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(ale->data);
1979
1981 *grease_pencil, layer->wrap(), *(ac->scene), static_cast<eEditKeyframes_Snap>(mode));
1982
1983 if (changed) {
1984 DEG_id_tag_update(&grease_pencil->id, ID_RECALC_GEOMETRY);
1985 }
1986 }
1987 else if (ale->type == ANIMTYPE_MASKLAYER) {
1988 ED_masklayer_snap_frames(static_cast<MaskLayer *>(ale->data), ac->scene, mode);
1989 }
1990 else if (adt) {
1991 FCurve *fcurve = static_cast<FCurve *>(ale->key_data);
1992 ANIM_nla_mapping_apply_fcurve(adt, fcurve, false, false);
1993 ANIM_fcurve_keyframes_loop(&ked, fcurve, nullptr, edit_cb, BKE_fcurve_handles_recalc);
1995 fcurve, SELECT, false); /* only use handles in graph editor */
1996 ANIM_nla_mapping_apply_fcurve(adt, fcurve, true, false);
1997 }
1998 else {
1999 FCurve *fcurve = static_cast<FCurve *>(ale->key_data);
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 }
2004
2005 ale->update |= ANIM_UPDATE_DEFAULT;
2006 }
2007
2008 ANIM_animdata_update(ac, &anim_data);
2009 ANIM_animdata_freelist(&anim_data);
2010}
2011
2012/* ------------------- */
2013
2015{
2016 bAnimContext ac;
2017 short mode;
2018
2019 /* get editor data */
2020 if (ANIM_animdata_get_context(C, &ac) == 0) {
2021 return OPERATOR_CANCELLED;
2022 }
2023
2024 /* get snapping mode */
2025 mode = RNA_enum_get(op->ptr, "type");
2026
2027 /* snap keyframes */
2028 snap_action_keys(&ac, mode);
2029
2030 /* set notifier that keyframes have changed */
2032
2033 return OPERATOR_FINISHED;
2034}
2035
2037{
2038 /* identifiers */
2039 ot->name = "Snap Keys";
2040 ot->idname = "ACTION_OT_snap";
2041 ot->description = "Snap selected keyframes to the times specified";
2042
2043 /* api callbacks */
2047
2048 /* flags */
2050
2051 /* id-props */
2052 ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_snap_types, 0, "Type", "");
2053}
2054
2057/* -------------------------------------------------------------------- */
2061/* defines for mirror keyframes tool */
2064 "CFRA",
2065 0,
2066 "By Times Over Current Frame",
2067 "Flip times of selected keyframes using the current frame as the mirror line"},
2069 "XAXIS",
2070 0,
2071 "By Values Over Zero Value",
2072 "Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"},
2074 "MARKER",
2075 0,
2076 "By Times Over First Selected Marker",
2077 "Flip times of selected keyframes using the first selected marker as the reference point"},
2078 {0, nullptr, 0, nullptr, nullptr},
2079};
2080
2081/* this function is responsible for mirroring keyframes */
2082static void mirror_action_keys(bAnimContext *ac, short mode)
2083{
2084 ListBase anim_data = {nullptr, nullptr};
2086
2087 KeyframeEditData ked = {{nullptr}};
2088 KeyframeEditFunc edit_cb;
2089
2090 /* get beztriple editing callbacks */
2091 edit_cb = ANIM_editkeyframes_mirror(mode);
2092
2093 ked.scene = ac->scene;
2094
2095 /* for 'first selected marker' mode, need to find first selected marker first! */
2096 /* XXX should this be made into a helper func in the API? */
2097 if (mode == ACTKEYS_MIRROR_MARKER) {
2099
2100 if (marker) {
2101 ked.f1 = float(marker->frame);
2102 }
2103 else {
2104 return;
2105 }
2106 }
2107
2108 /* filter data */
2111 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
2112
2113 /* mirror keyframes */
2114 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
2115 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
2116
2117 if (ale->type == ANIMTYPE_GPLAYER) {
2118 ED_gpencil_layer_mirror_frames(static_cast<bGPDlayer *>(ale->data), ac->scene, mode);
2119 }
2120 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
2121 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(ale->id);
2122 GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(ale->data);
2123
2125 *grease_pencil, layer->wrap(), *(ac->scene), static_cast<eEditKeyframes_Mirror>(mode));
2126
2127 if (changed) {
2128 DEG_id_tag_update(&grease_pencil->id, ID_RECALC_GEOMETRY);
2129 }
2130 }
2131 else if (ale->type == ANIMTYPE_MASKLAYER) {
2132 /* TODO */
2133 }
2134 else if (adt) {
2135 FCurve *fcurve = static_cast<FCurve *>(ale->key_data);
2136 ANIM_nla_mapping_apply_fcurve(adt, fcurve, false, false);
2137 ANIM_fcurve_keyframes_loop(&ked, fcurve, nullptr, edit_cb, BKE_fcurve_handles_recalc);
2138 ANIM_nla_mapping_apply_fcurve(adt, fcurve, true, false);
2139 }
2140 else {
2142 &ked, static_cast<FCurve *>(ale->key_data), nullptr, edit_cb, BKE_fcurve_handles_recalc);
2143 }
2144
2145 ale->update |= ANIM_UPDATE_DEFAULT;
2146 }
2147
2148 ANIM_animdata_update(ac, &anim_data);
2149 ANIM_animdata_freelist(&anim_data);
2150}
2151
2152/* ------------------- */
2153
2155{
2156 bAnimContext ac;
2157 short mode;
2158
2159 /* get editor data */
2160 if (ANIM_animdata_get_context(C, &ac) == 0) {
2161 return OPERATOR_CANCELLED;
2162 }
2163
2164 /* get mirroring mode */
2165 mode = RNA_enum_get(op->ptr, "type");
2166
2167 /* mirror keyframes */
2168 mirror_action_keys(&ac, mode);
2169
2170 /* set notifier that keyframes have changed */
2172
2173 return OPERATOR_FINISHED;
2174}
2175
2177{
2178 /* identifiers */
2179 ot->name = "Mirror Keys";
2180 ot->idname = "ACTION_OT_mirror";
2181 ot->description = "Flip selected keyframes over the selected mirror line";
2182
2183 /* api callbacks */
2187
2188 /* flags */
2190
2191 /* id-props */
2192 ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_mirror_types, 0, "Type", "");
2193}
2194
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:734
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.
float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, short mode)
@ NLATIME_CONVERT_MAP
Definition BKE_nla.hh:516
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:513
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
#define LISTBASE_FOREACH(type, var, list)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
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:193
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:197
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.c:40
#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:1041
@ 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_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_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:708
bool ED_operator_action_active(bContext *C)
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ ALERT_ICON_NONE
void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag)
Definition view2d.cc:861
#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:1934
void UI_view2d_center_set(View2D *v2d, float x, float y)
Definition view2d.cc:1944
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define ND_DATA
Definition WM_types.hh:475
#define NC_ANIMATION
Definition WM_types.hh:355
#define NC_SCENE
Definition WM_types.hh:345
#define NA_ADDED
Definition WM_types.hh:552
#define NA_EDITED
Definition WM_types.hh:550
#define ND_KEYFRAME_PROP
Definition WM_types.hh:462
#define ND_MARKERS
Definition WM_types.hh:400
#define ND_FRAME
Definition WM_types.hh:401
#define NA_REMOVED
Definition WM_types.hh:553
#define NC_GPENCIL
Definition WM_types.hh:366
#define ND_KEYFRAME
Definition WM_types.hh:461
void ACTION_OT_view_selected(wmOperatorType *ot)
static int actkeys_delete_invoke(bContext *C, wmOperator *op, const wmEvent *)
static bool actkeys_framejump_poll(bContext *C)
void ACTION_OT_keyframe_type(wmOperatorType *ot)
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 void snap_action_keys(bAnimContext *ac, short mode)
static int actkeys_delete_exec(bContext *C, wmOperator *)
static int actkeys_view_frame_exec(bContext *C, wmOperator *op)
static void clean_action_keys(bAnimContext *ac, float thresh, bool clean_chan)
static int act_markers_make_local_exec(bContext *C, wmOperator *)
static const EnumPropertyItem prop_actkeys_snap_types[]
void ACTION_OT_view_all(wmOperatorType *ot)
static int actkeys_viewall(bContext *C, const bool only_sel)
static bool duplicate_action_keys(bAnimContext *ac)
void ACTION_OT_previewrange_set(wmOperatorType *ot)
static int actkeys_previewrange_exec(bContext *C, wmOperator *)
static int actkeys_snap_exec(bContext *C, wmOperator *op)
void ACTION_OT_duplicate(wmOperatorType *ot)
void ACTION_OT_delete(wmOperatorType *ot)
void ACTION_OT_view_frame(wmOperatorType *ot)
static int actkeys_viewsel_exec(bContext *C, wmOperator *)
void ACTION_OT_extrapolation_type(wmOperatorType *ot)
static int actkeys_ipo_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 int actkeys_paste_exec(bContext *C, wmOperator *op)
static int actkeys_duplicate_exec(bContext *C, wmOperator *)
void ACTION_OT_bake_keys(wmOperatorType *ot)
#define MAKE_CYCLIC_EXPO
void ACTION_OT_frame_jump(wmOperatorType *ot)
void ACTION_OT_paste(wmOperatorType *ot)
static int actkeys_bake_exec(bContext *C, wmOperator *op)
static int actkeys_framejump_exec(bContext *C, wmOperator *)
static int actkeys_clean_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 short copy_action_keys(bAnimContext *ac)
static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const short onlySel)
static int actkeys_easing_exec(bContext *C, wmOperator *op)
static int actkeys_copy_exec(bContext *C, wmOperator *op)
static int actkeys_mirror_exec(bContext *C, wmOperator *op)
void ACTION_OT_markers_make_local(wmOperatorType *ot)
void ACTION_OT_interpolation_type(wmOperatorType *ot)
static int actkeys_viewall_exec(bContext *C, wmOperator *)
static int actkeys_expo_exec(bContext *C, wmOperator *op)
static int actkeys_handletype_exec(bContext *C, wmOperator *op)
void ACTION_OT_handle_type(wmOperatorType *ot)
static const EnumPropertyItem prop_actkeys_insertkey_types[]
static int actkeys_insertkey_exec(bContext *C, wmOperator *op)
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 void setexpo_action_keys(bAnimContext *ac, short mode)
void ACTION_OT_clean(wmOperatorType *ot)
#define CLEAR_CYCLIC_EXPO
static int actkeys_keytype_exec(bContext *C, wmOperator *op)
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
const bAnimChannelType * ANIM_channel_get_typeinfo(bAnimListElem *ale)
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)
void ANIM_animdata_freelist(ListBase *anim_data)
Definition anim_deps.cc:457
void ANIM_deselect_keys_in_animation_editors(bContext *C)
Definition anim_deps.cc:472
void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
Definition anim_deps.cc:350
AnimData * ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
Definition anim_draw.cc:210
void ANIM_center_frame(bContext *C, int smooth_viewtx)
Definition anim_draw.cc:663
void ANIM_nla_mapping_apply_fcurve(AnimData *adt, FCurve *fcu, bool restore, bool only_keys)
Definition anim_draw.cc:290
rctf ANIM_frame_range_view2d_add_xmargin(const View2D &view_2d, const rctf view_rect)
Definition anim_draw.cc:706
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)
void generate_reports(ReportList *reports, eReportType report_level=RPT_ERROR)
#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)
draw_view in_light_buf[] float
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
const vector< Marker > & markers
#define GS(x)
Definition iris.cc:202
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)
void clean_fcurve(bAnimContext *ac, bAnimListElem *ale, float thresh, bool cleardefault, const bool only_selected_keys)
const EnumPropertyItem rna_enum_keyframe_paste_offset_items[]
short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
const EnumPropertyItem rna_enum_keyframe_paste_merge_items[]
eKeyPasteError paste_animedit_keys(bAnimContext *ac, ListBase *anim_data, const eKeyPasteOffset offset_mode, const eKeyPasteValueOffset value_offset_mode, const eKeyMergeMode merge_mode, bool flip)
void ANIM_fcurves_copybuf_free()
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)
SingleKeyingResult insert_vert_fcurve(FCurve *fcu, const float2 position, const KeyframeSettings &settings, eInsertKeyFlags flag)
Main Key-framing API call.
void bake_fcurve_segments(FCurve *fcu)
void animdata_fcurve_delete(bAnimContext *ac, AnimData *adt, FCurve *fcu)
Definition animdata.cc:253
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:67
const EnumPropertyItem rna_enum_keyframe_handle_type_items[]
Definition rna_curve.cc:39
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:86
#define min(a, b)
Definition sort.c:32
#define FLT_MAX
Definition stdcycles.h:14
bActionGroup * grp
short extend
ListBase modifiers
struct FModifier * next
Definition DNA_ID.h:413
char name[66]
Definition DNA_ID.h:425
void * last
void * first
ListBase splines_shapes
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
float xmax
float xmin
float ymax
float ymin
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
std::string(* get_description)(bContext *C, wmOperatorType *ot, PointerRNA *ptr)
Definition WM_types.hh:1074
const char * idname
Definition WM_types.hh:992
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
struct ReportList * reports
struct PointerRNA * ptr
float max
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_operator_properties_confirm_or_exec(wmOperatorType *ot)
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)
int WM_operator_confirm_ex(bContext *C, wmOperator *op, const char *title, const char *message, const char *confirm_text, int icon, bool cancel_default)
int WM_operator_smooth_viewtx_get(const wmOperator *op)
uint8_t flag
Definition wm_window.cc:138