Blender V4.5
action_select.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
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 "MEM_guardedalloc.h"
15
16#include "BLI_lasso_2d.hh"
17#include "BLI_listbase.h"
18#include "BLI_utildefines.h"
19
20#include "DNA_anim_types.h"
22#include "DNA_mask_types.h"
23#include "DNA_object_types.h"
24#include "DNA_scene_types.h"
25
26#include "RNA_access.hh"
27#include "RNA_define.hh"
28
29#include "BKE_context.hh"
30#include "BKE_fcurve.hh"
31#include "BKE_grease_pencil.hh"
32#include "BKE_nla.hh"
33
34#include "UI_interface.hh"
35#include "UI_view2d.hh"
36
37#include "ED_anim_api.hh"
38#include "ED_gpencil_legacy.hh"
39#include "ED_grease_pencil.hh"
40#include "ED_keyframes_edit.hh"
42#include "ED_markers.hh"
43#include "ED_mask.hh"
44#include "ED_screen.hh"
45#include "ED_select_utils.hh"
46
47#include "WM_api.hh"
48#include "WM_types.hh"
49
50#include "action_intern.hh"
51
52using namespace blender;
53
54/* -------------------------------------------------------------------- */
57
60 float region_x,
61 float region_y)
62{
63 View2D *v2d = &ac->region->v2d;
64
65 float view_x, view_y;
66 int channel_index;
67 UI_view2d_region_to_view(v2d, region_x, region_y, &view_x, &view_y);
70 0,
72 view_x,
73 view_y,
74 nullptr,
75 &channel_index);
76
77 ListBase anim_data = {nullptr, nullptr};
78 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
79
80 bAnimListElem *ale = static_cast<bAnimListElem *>(BLI_findlink(&anim_data, channel_index));
81 if (ale != nullptr) {
82 BLI_remlink(&anim_data, ale);
83 ale->next = ale->prev = nullptr;
84 }
85 ANIM_animdata_freelist(&anim_data);
86
87 return ale;
88}
89
91 AnimKeylist *keylist,
92 bAnimListElem *ale)
93{
94 bDopeSheet *ads = nullptr;
96 ads = static_cast<bDopeSheet *>(ac->data);
97 }
98
99 blender::float2 range = {ac->region->v2d.cur.xmin, ac->region->v2d.cur.xmax};
100
101 if (ale->key_data) {
102 switch (ale->datatype) {
103 case ALE_SCE: {
104 Scene *scene = (Scene *)ale->key_data;
105 scene_to_keylist(ads, scene, keylist, 0, range);
106 break;
107 }
108 case ALE_OB: {
109 Object *ob = (Object *)ale->key_data;
110 ob_to_keylist(ads, ob, keylist, 0, range);
111 break;
112 }
113 case ALE_ACTION_LAYERED: {
114 /* This is only called for action summaries in the Dope-sheet, *not* the
115 * Action Editor. Therefore despite the name `ALE_ACTION_LAYERED`, this
116 * is only used to show a *single slot* of the action: the slot used by
117 * the ID the action is listed under.
118 *
119 * Thus we use the same function as the `ALE_ACTION_SLOT` case below
120 * because in practice the only distinction between these cases is where
121 * they get the slot from. In this case, we get it from `elem`'s ADT. */
122 animrig::Action *action = static_cast<animrig::Action *>(ale->key_data);
123 BLI_assert(action);
124 BLI_assert(ale->adt);
126 ac, ale->id, *action, ale->adt->slot_handle, keylist, 0, range);
127 break;
128 }
129 case ALE_ACTION_SLOT: {
130 animrig::Action *action = static_cast<animrig::Action *>(ale->key_data);
131 animrig::Slot *slot = static_cast<animrig::Slot *>(ale->data);
132 BLI_assert(action);
133 BLI_assert(slot);
134 action_slot_summary_to_keylist(ac, ale->id, *action, slot->handle, keylist, 0, range);
135 break;
136 }
137 case ALE_ACT: {
138 /* Legacy action. */
139 bAction *act = (bAction *)ale->key_data;
140 action_to_keylist(ale->adt, act, keylist, 0, range);
141 break;
142 }
143 case ALE_FCURVE: {
144 FCurve *fcu = (FCurve *)ale->key_data;
145 fcurve_to_keylist(ale->adt, fcu, keylist, 0, range, ANIM_nla_mapping_allowed(ale));
146 break;
147 }
148 case ALE_NONE:
149 case ALE_GPFRAME:
150 case ALE_MASKLAY:
151 case ALE_NLASTRIP:
152 case ALE_ALL:
153 case ALE_GROUP:
157 break;
158 }
159 }
160 else if (ale->type == ANIMTYPE_SUMMARY) {
161 /* Dope-sheet summary covers everything. */
162 summary_to_keylist(ac, keylist, 0, range);
163 }
164 else if (ale->type == ANIMTYPE_GROUP) {
165 /* TODO: why don't we just give groups key_data too? */
166 bActionGroup *agrp = (bActionGroup *)ale->data;
167 action_group_to_keylist(ale->adt, agrp, keylist, 0, range);
168 }
169 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
170 /* TODO: why don't we just give grease pencil layers key_data too? */
172 ale->adt, static_cast<const GreasePencilLayer *>(ale->data), keylist, 0);
173 }
174 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER_GROUP) {
175 /* TODO: why don't we just give grease pencil layers key_data too? */
177 ale->adt, static_cast<const GreasePencilLayerTreeGroup *>(ale->data), keylist, 0);
178 }
179 else if (ale->type == ANIMTYPE_GREASE_PENCIL_DATABLOCK) {
180 /* TODO: why don't we just give grease pencil layers key_data too? */
182 ale->adt, static_cast<const GreasePencil *>(ale->data), keylist, 0, false);
183 }
184 else if (ale->type == ANIMTYPE_GPLAYER) {
185 /* TODO: why don't we just give gplayers key_data too? */
186 bGPDlayer *gpl = (bGPDlayer *)ale->data;
187 gpl_to_keylist(ads, gpl, keylist);
188 }
189 else if (ale->type == ANIMTYPE_MASKLAYER) {
190 /* TODO: why don't we just give masklayers key_data too? */
191 MaskLayer *masklay = (MaskLayer *)ale->data;
192 mask_to_keylist(ads, masklay, keylist);
193 }
194}
195
197 bAnimListElem *ale,
198 float region_x,
199 float *r_selx,
200 float *r_frame,
201 bool *r_found,
202 bool *r_is_selected)
203{
204 *r_found = false;
205
206 View2D *v2d = &ac->region->v2d;
207
208 AnimKeylist *keylist = ED_keylist_create();
209 actkeys_list_element_to_keylist(ac, keylist, ale);
211
212 /* standard channel height (to allow for some slop) */
213 float key_hsize = ANIM_UI_get_channel_height() * 0.8f;
214 /* half-size (for either side), but rounded up to nearest int (for easier targeting) */
215 key_hsize = roundf(key_hsize / 2.0f);
216
217 const Bounds<float> range = {
218 UI_view2d_region_to_view_x(v2d, region_x - int(key_hsize)),
219 UI_view2d_region_to_view_x(v2d, region_x + int(key_hsize)),
220 };
221 const ActKeyColumn *ak = ED_keylist_find_any_between(keylist, range);
222 if (ak) {
223
224 /* set the frame to use, and apply inverse-correction for NLA-mapping
225 * so that the frame will get selected by the selection functions without
226 * requiring to map each frame once again...
227 */
229 *r_frame = ak->cfra;
230 *r_found = true;
231 *r_is_selected = (ak->sel & SELECT) != 0;
232 }
233
234 /* cleanup temporary lists */
235 ED_keylist_free(keylist);
236}
237
240 float region_x,
241 float region_y,
242 bAnimListElem **r_ale,
243 float *r_selx,
244 float *r_frame,
245 bool *r_found,
246 bool *r_is_selected)
247
248{
249 *r_found = false;
250 *r_ale = actkeys_find_list_element_at_position(ac, filter, region_x, region_y);
251
252 if (*r_ale != nullptr) {
254 ac, *r_ale, region_x, r_selx, r_frame, r_found, r_is_selected);
255 }
256}
257
258static bool actkeys_is_key_at_position(bAnimContext *ac, float region_x, float region_y)
259{
260 bAnimListElem *ale;
261 float selx, frame;
262 bool found;
263 bool is_selected;
264
268 ac, filter, region_x, region_y, &ale, &selx, &frame, &found, &is_selected);
269
270 if (ale != nullptr) {
271 MEM_freeN(ale);
272 }
273 return found;
274}
275
277
278/* -------------------------------------------------------------------- */
286
287/* Deselects keyframes in the action editor
288 * - This is called by the deselect all operator, as well as other ones!
289 *
290 * - test: check if select or deselect all
291 * - sel: how to select keyframes (SELECT_*)
292 */
294{
295 ListBase anim_data = {nullptr, nullptr};
297
298 KeyframeEditData ked = {{nullptr}};
299 KeyframeEditFunc test_cb, sel_cb;
300
301 /* determine type-based settings */
303
304 /* filter data */
305 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
306
307 /* init BezTriple looping data */
309
310 /* See if we should be selecting or deselecting */
311 if (test) {
312 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
313 if (ale->type == ANIMTYPE_GPLAYER) {
314 if (ED_gpencil_layer_frame_select_check(static_cast<bGPDlayer *>(ale->data))) {
315 sel = SELECT_SUBTRACT;
316 break;
317 }
318 }
319 else if (ale->type == ANIMTYPE_MASKLAYER) {
320 if (ED_masklayer_frame_select_check(static_cast<MaskLayer *>(ale->data))) {
321 sel = SELECT_SUBTRACT;
322 break;
323 }
324 }
325 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
327 static_cast<GreasePencilLayer *>(ale->data)->wrap()))
328 {
329 sel = SELECT_SUBTRACT;
330 }
331 break;
332 }
333 else {
335 &ked, static_cast<FCurve *>(ale->key_data), nullptr, test_cb, nullptr))
336 {
337 sel = SELECT_SUBTRACT;
338 break;
339 }
340 }
341 }
342 }
343
344 /* convert sel to selectmode, and use that to get editor */
345 sel_cb = ANIM_editkeyframes_select(sel);
346
347 /* Now set the flags */
348 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
349 if (ale->type == ANIMTYPE_GPLAYER) {
350 ED_gpencil_layer_frame_select_set(static_cast<bGPDlayer *>(ale->data), sel);
351 ale->update |= ANIM_UPDATE_DEPS;
352 }
353 else if (ale->type == ANIMTYPE_MASKLAYER) {
354 ED_masklayer_frame_select_set(static_cast<MaskLayer *>(ale->data), sel);
355 }
356 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
358 static_cast<GreasePencilLayer *>(ale->data)->wrap(), sel);
359 ale->update |= ANIM_UPDATE_DEPS;
360 }
361 else {
363 &ked, static_cast<FCurve *>(ale->key_data), nullptr, sel_cb, nullptr);
364 }
365 }
366
367 /* Cleanup */
368 ANIM_animdata_update(ac, &anim_data);
369 ANIM_animdata_freelist(&anim_data);
370}
371
372/* ------------------- */
373
375{
376 bAnimContext ac;
377
378 /* get editor data */
379 if (ANIM_animdata_get_context(C, &ac) == 0) {
380 return OPERATOR_CANCELLED;
381 }
382
383 /* 'standard' behavior - check if selected, then apply relevant selection */
384 const int action = RNA_enum_get(op->ptr, "action");
385 switch (action) {
386 case SEL_TOGGLE:
388 break;
389 case SEL_SELECT:
391 break;
392 case SEL_DESELECT:
394 break;
395 case SEL_INVERT:
397 break;
398 default:
399 BLI_assert(0);
400 break;
401 }
402
403 /* set notifier that keyframe selection have changed */
407 }
408 return OPERATOR_FINISHED;
409}
410
412{
413 /* identifiers */
414 ot->name = "Select All";
415 ot->idname = "ACTION_OT_select_all";
416 ot->description = "Toggle selection of all keyframes";
417
418 /* API callbacks. */
421
422 /* flags */
424
425 /* properties */
427}
428
430
431/* -------------------------------------------------------------------- */
441
442/* defines for box_select mode */
443enum {
447} /*eActKeys_BoxSelect_Mode*/;
448
456
457static void box_select_elem(
458 BoxSelectData *sel_data, bAnimListElem *ale, float xmin, float xmax, bool summary)
459{
460 bAnimContext *ac = sel_data->ac;
461
462 switch (ale->type) {
464 GreasePencil *grease_pencil = static_cast<GreasePencil *>(ale->data);
465 for (blender::bke::greasepencil::Layer *layer : grease_pencil->layers_for_write()) {
467 layer->wrap().as_node(), xmin, xmax, sel_data->selectmode);
468 }
469 ale->update |= ANIM_UPDATE_DEPS;
470 break;
471 }
475 static_cast<GreasePencilLayerTreeNode *>(ale->data)->wrap(),
476 xmin,
477 xmax,
478 sel_data->selectmode);
479 ale->update |= ANIM_UPDATE_DEPS;
480 break;
481 case ANIMTYPE_GPLAYER: {
483 static_cast<bGPDlayer *>(ale->data), xmin, xmax, sel_data->selectmode);
484 ale->update |= ANIM_UPDATE_DEPS;
485 break;
486 }
488 Mask *mask = static_cast<Mask *>(ale->data);
489 MaskLayer *masklay;
490 for (masklay = static_cast<MaskLayer *>(mask->masklayers.first); masklay;
491 masklay = masklay->next)
492 {
493 ED_masklayer_frames_select_box(masklay, xmin, xmax, sel_data->selectmode);
494 }
495 break;
496 }
497 case ANIMTYPE_MASKLAYER: {
499 static_cast<MaskLayer *>(ale->data), xmin, xmax, sel_data->selectmode);
500 break;
501 }
502 default: {
503 if (summary) {
504 break;
505 }
506
507 if (ale->type == ANIMTYPE_SUMMARY) {
508 ListBase anim_data = {nullptr, nullptr};
510 ac, &anim_data, ANIMFILTER_DATA_VISIBLE, ac->data, eAnimCont_Types(ac->datatype));
511
512 LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
513 box_select_elem(sel_data, ale2, xmin, xmax, true);
514 }
515
516 ANIM_animdata_update(ac, &anim_data);
517 ANIM_animdata_freelist(&anim_data);
518 }
519
522 &sel_data->ked, ac->ads, ale, sel_data->ok_cb, sel_data->select_cb, nullptr);
523 }
524 }
525 }
526}
527
529 const rcti rect,
530 short mode,
531 const eEditKeyframes_Select selectmode)
532{
533 ListBase anim_data = {nullptr, nullptr};
534 bAnimListElem *ale;
536
537 BoxSelectData sel_data{};
538 sel_data.ac = ac;
539 sel_data.selectmode = selectmode;
540
541 View2D *v2d = &ac->region->v2d;
542 rctf rectf;
543
544 /* Convert mouse coordinates to frame ranges and channel
545 * coordinates corrected for view pan/zoom. */
546 UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin + 2, &rectf.xmin, &rectf.ymin);
547 UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax - 2, &rectf.xmax, &rectf.ymax);
548
549 /* filter data */
551 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
552
553 /* Get beztriple editing/validation functions. */
554 sel_data.select_cb = ANIM_editkeyframes_select(selectmode);
555
558 }
559 else {
560 sel_data.ok_cb = nullptr;
561 }
562
563 /* init editing data */
564 memset(&sel_data.ked, 0, sizeof(KeyframeEditData));
565
566 float ymax = ANIM_UI_get_first_channel_top(v2d);
567 const float channel_step = ANIM_UI_get_channel_step();
568
569 /* loop over data, doing box select */
570 for (ale = static_cast<bAnimListElem *>(anim_data.first); ale;
571 ale = ale->next, ymax -= channel_step)
572 {
573 /* get new vertical minimum extent of channel */
574 float ymin = ymax - channel_step;
575
576 /* set horizontal range (if applicable) */
578 /* if channel is mapped in NLA, apply correction */
579 if (ANIM_nla_mapping_allowed(ale)) {
583 }
584 else {
585 sel_data.ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */
586 sel_data.ked.f1 = rectf.xmin;
587 sel_data.ked.f2 = rectf.xmax;
588 }
589 }
590
591 /* perform vertical suitability check (if applicable) */
592 if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) || !((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
593 box_select_elem(&sel_data, ale, rectf.xmin, rectf.xmax, false);
594 }
595 }
596
597 /* cleanup */
598 ANIM_animdata_update(ac, &anim_data);
599 ANIM_animdata_freelist(&anim_data);
600}
601
602/* ------------------- */
603
605 wmOperator *op,
606 const wmEvent *event)
607{
608 bAnimContext ac;
609 if (ANIM_animdata_get_context(C, &ac) == 0) {
610 return OPERATOR_CANCELLED;
611 }
612
613 bool tweak = RNA_boolean_get(op->ptr, "tweak");
614 if (tweak) {
615 int mval[2];
616 WM_event_drag_start_mval(event, ac.region, mval);
617 if (actkeys_is_key_at_position(&ac, mval[0], mval[1])) {
619 }
620 }
621
622 return WM_gesture_box_invoke(C, op, event);
623}
624
626{
627 bAnimContext ac;
628 rcti rect;
629 short mode = 0;
630
631 /* get editor data */
632 if (ANIM_animdata_get_context(C, &ac) == 0) {
633 return OPERATOR_CANCELLED;
634 }
635
636 const eSelectOp sel_op = eSelectOp(RNA_enum_get(op->ptr, "mode"));
637 const eEditKeyframes_Select selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT;
638 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
640 }
641
642 /* get settings from operator */
644
645 /* selection 'mode' depends on whether box_select region only matters on one axis */
646 if (RNA_boolean_get(op->ptr, "axis_range")) {
647 /* Mode depends on which axis of the range is larger to determine which axis to use:
648 * - checking this in region-space is fine,
649 * as it's fundamentally still going to be a different rect size.
650 * - the frame-range select option is favored over the channel one (x over y),
651 * as frame-range one is often used for tweaking timing when "blocking",
652 * while channels is not that useful...
653 */
654 if (BLI_rcti_size_x(&rect) >= BLI_rcti_size_y(&rect)) {
656 }
657 else {
659 }
660 }
661 else {
663 }
664
665 /* apply box_select action */
666 box_select_action(&ac, rect, mode, selectmode);
667
668 /* set notifier that keyframe selection have changed */
672 }
673 return OPERATOR_FINISHED;
674}
675
677{
678 /* identifiers */
679 ot->name = "Box Select";
680 ot->idname = "ACTION_OT_select_box";
681 ot->description = "Select all keyframes within the specified region";
682
683 /* API callbacks. */
686 ot->modal = WM_gesture_box_modal;
687 ot->cancel = WM_gesture_box_cancel;
688
690
691 /* flags */
692 ot->flag = OPTYPE_UNDO;
693
694 /* rna */
695 ot->prop = RNA_def_boolean(ot->srna, "axis_range", false, "Axis Range", "");
696
697 /* properties */
700
702 ot->srna, "tweak", false, "Tweak", "Operator has been activated using a click-drag event");
704}
705
707
708/* -------------------------------------------------------------------- */
715
724
725static void region_select_elem(RegionSelectData *sel_data, bAnimListElem *ale, bool summary)
726{
727 bAnimContext *ac = sel_data->ac;
728
729 switch (ale->type) {
730 case ANIMTYPE_GPLAYER: {
732 static_cast<bGPDlayer *>(ale->data),
733 sel_data->mode,
734 sel_data->selectmode);
735 ale->update |= ANIM_UPDATE_DEPS;
736 break;
737 }
741 &sel_data->ked,
742 static_cast<GreasePencilLayerTreeNode *>(ale->data)->wrap(),
743 sel_data->mode,
744 sel_data->selectmode);
745 ale->update |= ANIM_UPDATE_DEPS;
746 break;
747 }
749 ListBase anim_data = {nullptr, nullptr};
751 ac, &anim_data, ANIMFILTER_DATA_VISIBLE, ac->data, eAnimCont_Types(ac->datatype));
752
753 LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
754 if ((ale2->type == ANIMTYPE_GREASE_PENCIL_LAYER) && (ale2->id == ale->data)) {
755 region_select_elem(sel_data, ale2, true);
756 }
757 }
758
759 ANIM_animdata_update(ac, &anim_data);
760 ANIM_animdata_freelist(&anim_data);
761 break;
762 }
764 Mask *mask = static_cast<Mask *>(ale->data);
765 MaskLayer *masklay;
766 for (masklay = static_cast<MaskLayer *>(mask->masklayers.first); masklay;
767 masklay = masklay->next)
768 {
770 &sel_data->ked, masklay, sel_data->mode, sel_data->selectmode);
771 }
772 break;
773 }
774 case ANIMTYPE_MASKLAYER: {
776 static_cast<MaskLayer *>(ale->data),
777 sel_data->mode,
778 sel_data->selectmode);
779 break;
780 }
781 default: {
782 if (summary) {
783 break;
784 }
785
786 if (ale->type == ANIMTYPE_SUMMARY) {
787 ListBase anim_data = {nullptr, nullptr};
789 ac, &anim_data, ANIMFILTER_DATA_VISIBLE, ac->data, eAnimCont_Types(ac->datatype));
790
791 LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
792 region_select_elem(sel_data, ale2, true);
793 }
794
795 ANIM_animdata_update(ac, &anim_data);
796 ANIM_animdata_freelist(&anim_data);
797 }
798
801 &sel_data->ked, ac->ads, ale, sel_data->ok_cb, sel_data->select_cb, nullptr);
802 }
803 }
804 }
805}
806
808 const rctf *rectf_view,
809 short mode,
810 eEditKeyframes_Select selectmode,
811 void *data)
812{
813 ListBase anim_data = {nullptr, nullptr};
814 bAnimListElem *ale;
816
817 RegionSelectData sel_data{};
818 sel_data.ac = ac;
819 sel_data.mode = mode;
820 sel_data.selectmode = selectmode;
821 View2D *v2d = &ac->region->v2d;
822 rctf rectf, scaled_rectf;
823
824 /* Convert mouse coordinates to frame ranges and channel
825 * coordinates corrected for view pan/zoom. */
826 UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf);
827
828 /* filter data */
830 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
831
832 /* Get beztriple editing/validation functions. */
833 sel_data.select_cb = ANIM_editkeyframes_select(selectmode);
834 sel_data.ok_cb = ANIM_editkeyframes_ok(mode);
835
836 /* init editing data */
837 memset(&sel_data.ked, 0, sizeof(KeyframeEditData));
838 if (mode == BEZT_OK_CHANNEL_LASSO) {
839 KeyframeEdit_LassoData *data_lasso = static_cast<KeyframeEdit_LassoData *>(data);
840 data_lasso->rectf_scaled = &scaled_rectf;
841 sel_data.ked.data = data_lasso;
842 }
843 else if (mode == BEZT_OK_CHANNEL_CIRCLE) {
844 KeyframeEdit_CircleData *data_circle = static_cast<KeyframeEdit_CircleData *>(data);
845 data_circle->rectf_scaled = &scaled_rectf;
846 sel_data.ked.data = data;
847 }
848 else {
849 sel_data.ked.data = &scaled_rectf;
850 }
851
852 float ymax = ANIM_UI_get_first_channel_top(v2d);
853 const float channel_step = ANIM_UI_get_channel_step();
854
855 /* loop over data, doing region select */
856 for (ale = static_cast<bAnimListElem *>(anim_data.first); ale;
857 ale = ale->next, ymax -= channel_step)
858 {
859 /* get new vertical minimum extent of channel */
860 const float ymin = ymax - channel_step;
861
862 /* compute midpoint of channel (used for testing if the key is in the region or not) */
863 sel_data.ked.channel_y = (ymin + ymax) / 2.0f;
864
865 /* if channel is mapped in NLA, apply correction
866 * - Apply to the bounds being checked, not all the keyframe points,
867 * to avoid having scaling everything
868 * - Save result to the scaled_rect, which is all that these operators
869 * will read from
870 */
871 if (ANIM_nla_mapping_allowed(ale)) {
875 }
876 else {
877 sel_data.ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */
878 sel_data.ked.f1 = rectf.xmin;
879 sel_data.ked.f2 = rectf.xmax;
880 }
881
882 /* Update values for scaled_rectf - which is used to compute the mapping in the callbacks
883 * NOTE: Since summary tracks need late-binding remapping, the callbacks may overwrite these
884 * with the properly remapped ked.f1/f2 values, when needed
885 */
886 scaled_rectf.xmin = sel_data.ked.f1;
887 scaled_rectf.xmax = sel_data.ked.f2;
888 scaled_rectf.ymin = ymin;
889 scaled_rectf.ymax = ymax;
890
891 /* perform vertical suitability check (if applicable) */
892 if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) || !((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
893 region_select_elem(&sel_data, ale, false);
894 }
895 }
896
897 /* cleanup */
898 ANIM_animdata_update(ac, &anim_data);
899 ANIM_animdata_freelist(&anim_data);
900}
901
902/* ----------------------------------- */
903
905{
906 bAnimContext ac;
907
908 KeyframeEdit_LassoData data_lasso;
909 rcti rect;
910 rctf rect_fl;
911
912 /* get editor data */
913 if (ANIM_animdata_get_context(C, &ac) == 0) {
914 return OPERATOR_CANCELLED;
915 }
916
917 data_lasso.rectf_view = &rect_fl;
918 data_lasso.mcoords = WM_gesture_lasso_path_to_array(C, op);
919 if (data_lasso.mcoords.is_empty()) {
920 return OPERATOR_CANCELLED;
921 }
922
923 const eSelectOp sel_op = eSelectOp(RNA_enum_get(op->ptr, "mode"));
924 const eEditKeyframes_Select selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT;
925 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
927 }
928
929 /* get settings from operator */
930 BLI_lasso_boundbox(&rect, data_lasso.mcoords);
931 BLI_rctf_rcti_copy(&rect_fl, &rect);
932
933 /* apply box_select action */
934 region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso);
935
936 /* send notifier that keyframe selection has changed */
940 }
941 return OPERATOR_FINISHED;
942}
943
945{
946 /* identifiers */
947 ot->name = "Lasso Select";
948 ot->description = "Select keyframe points using lasso selection";
949 ot->idname = "ACTION_OT_select_lasso";
950
951 /* API callbacks. */
952 ot->invoke = WM_gesture_lasso_invoke;
953 ot->modal = WM_gesture_lasso_modal;
956 ot->cancel = WM_gesture_lasso_cancel;
957
958 /* flags */
960
961 /* properties */
964}
965
966/* ------------------- */
967
969{
970 bAnimContext ac;
971
972 KeyframeEdit_CircleData data = {nullptr};
973 rctf rect_fl;
974
975 float x = RNA_int_get(op->ptr, "x");
976 float y = RNA_int_get(op->ptr, "y");
977 float radius = RNA_int_get(op->ptr, "radius");
978
979 /* get editor data */
980 if (ANIM_animdata_get_context(C, &ac) == 0) {
981 return OPERATOR_CANCELLED;
982 }
983
984 const eSelectOp sel_op = ED_select_op_modal(
985 eSelectOp(RNA_enum_get(op->ptr, "mode")),
986 WM_gesture_is_modal_first(static_cast<wmGesture *>(op->customdata)));
987 const eEditKeyframes_Select selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT;
988 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
990 }
991
992 data.mval[0] = x;
993 data.mval[1] = y;
994 data.radius_squared = radius * radius;
995 data.rectf_view = &rect_fl;
996
997 rect_fl.xmin = x - radius;
998 rect_fl.xmax = x + radius;
999 rect_fl.ymin = y - radius;
1000 rect_fl.ymax = y + radius;
1001
1002 /* apply region select action */
1003 region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_CIRCLE, selectmode, &data);
1004
1005 /* send notifier that keyframe selection has changed */
1009 }
1010 return OPERATOR_FINISHED;
1011}
1012
1014{
1015 ot->name = "Circle Select";
1016 ot->description = "Select keyframe points using circle selection";
1017 ot->idname = "ACTION_OT_select_circle";
1018
1019 ot->invoke = WM_gesture_circle_invoke;
1020 ot->modal = WM_gesture_circle_modal;
1023 ot->cancel = WM_gesture_circle_cancel;
1024 ot->get_name = ED_select_circle_get_name;
1025
1026 /* flags */
1027 ot->flag = OPTYPE_UNDO;
1028
1029 /* properties */
1032}
1033
1035
1036/* -------------------------------------------------------------------- */
1045
1046/* defines for column-select mode */
1048 {ACTKEYS_COLUMNSEL_KEYS, "KEYS", 0, "On Selected Keyframes", ""},
1049 {ACTKEYS_COLUMNSEL_CFRA, "CFRA", 0, "On Current Frame", ""},
1050 {ACTKEYS_COLUMNSEL_MARKERS_COLUMN, "MARKERS_COLUMN", 0, "On Selected Markers", ""},
1052 "MARKERS_BETWEEN",
1053 0,
1054 "Between Min/Max Selected Markers",
1055 ""},
1056 {0, nullptr, 0, nullptr, nullptr},
1057};
1058
1059/* ------------------- */
1060
1061/* Selects all visible keyframes between the specified markers */
1062/* TODO(@ideasman42): this is almost an _exact_ duplicate of a function of the same name in
1063 * `graph_select.cc` should de-duplicate. */
1065{
1066 ListBase anim_data = {nullptr, nullptr};
1068
1069 KeyframeEditFunc ok_cb, select_cb;
1070 KeyframeEditData ked = {{nullptr}};
1071 float min, max;
1072
1073 /* get extreme markers */
1075 min -= 0.5f;
1076 max += 0.5f;
1077
1078 /* Get editing functions + data. */
1081
1082 ked.f1 = min;
1083 ked.f2 = max;
1084
1085 /* filter data */
1087 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1088
1089 /* select keys in-between */
1090 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1091 switch (ale->type) {
1094 static_cast<GreasePencilLayerTreeNode *>(ale->data)->wrap(), min, max, SELECT_ADD);
1095 ale->update |= ANIM_UPDATE_DEPS;
1096 break;
1097 case ANIMTYPE_GPLAYER:
1099 static_cast<bGPDlayer *>(ale->data), min, max, SELECT_ADD);
1100 ale->update |= ANIM_UPDATE_DEPS;
1101 break;
1102
1103 case ANIMTYPE_MASKLAYER:
1104 ED_masklayer_frames_select_box(static_cast<MaskLayer *>(ale->data), min, max, SELECT_ADD);
1105 break;
1106
1107 case ANIMTYPE_FCURVE: {
1108 FCurve *fcurve = static_cast<FCurve *>(ale->key_data);
1109 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcurve, false, true);
1110 ANIM_fcurve_keyframes_loop(&ked, fcurve, ok_cb, select_cb, nullptr);
1111 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcurve, true, true);
1112 break;
1113 }
1114
1115 default:
1116 BLI_assert_msg(false, "Keys cannot be selected into this animation type.");
1117 }
1118 }
1119
1120 /* Cleanup */
1121 ANIM_animdata_update(ac, &anim_data);
1122 ANIM_animdata_freelist(&anim_data);
1123}
1124
1125/* Selects all visible keyframes in the same frames as the specified elements */
1126static void columnselect_action_keys(bAnimContext *ac, short mode)
1127{
1128 ListBase anim_data = {nullptr, nullptr};
1130
1131 Scene *scene = ac->scene;
1132 CfraElem *ce;
1133 KeyframeEditFunc select_cb, ok_cb;
1134 KeyframeEditData ked = {{nullptr}};
1135
1136 /* build list of columns */
1137 switch (mode) {
1138 case ACTKEYS_COLUMNSEL_KEYS: /* list of selected keys */
1139 if (ac->datatype == ANIMCONT_GPENCIL) {
1141 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1142
1143 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1144 switch (ale->type) {
1145 case ANIMTYPE_GPLAYER:
1147 static_cast<bGPDlayer *>(ale->data), &ked.list, true);
1148 break;
1150 blender::ed::greasepencil ::create_keyframe_edit_data_selected_frames_list(
1151 &ked, static_cast<GreasePencilLayer *>(ale->data)->wrap());
1152 break;
1153 default:
1154 /* Invalid channel type. */
1156 }
1157 }
1158 }
1159 else {
1161 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1162
1163 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1164 if (ale->datatype == ALE_GPFRAME) {
1165 ED_gpencil_layer_make_cfra_list(static_cast<bGPDlayer *>(ale->data), &ked.list, true);
1166 }
1167 else {
1168 ked.data = ale;
1170 &ked, static_cast<FCurve *>(ale->key_data), nullptr, bezt_to_cfraelem, nullptr);
1171 }
1172 }
1173 }
1174 ANIM_animdata_freelist(&anim_data);
1175 break;
1176
1177 case ACTKEYS_COLUMNSEL_CFRA: /* current frame */
1178 /* make a single CfraElem for storing this */
1179 ce = MEM_callocN<CfraElem>("cfraElem");
1180 BLI_addtail(&ked.list, ce);
1181
1182 ce->cfra = float(scene->r.cfra);
1183 break;
1184
1185 case ACTKEYS_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */
1186 ED_markers_make_cfra_list(ac->markers, &ked.list, true);
1187 break;
1188
1189 default: /* invalid option */
1190 return;
1191 }
1192
1193 /* set up BezTriple edit callbacks */
1196
1197 /* loop through all of the keys and select additional keyframes
1198 * based on the keys found to be selected above
1199 */
1201 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1202
1203 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1204 /* loop over cfraelems (stored in the KeyframeEditData->list)
1205 * - we need to do this here, as we can apply fewer NLA-mapping conversions
1206 */
1207 LISTBASE_FOREACH (CfraElem *, ce, &ked.list) {
1208 /* set frame for validation callback to refer to */
1210
1211 /* select elements with frame number matching cfraelem */
1212 if (ale->type == ANIMTYPE_GPLAYER) {
1213 ED_gpencil_select_frame(static_cast<bGPDlayer *>(ale->data), ce->cfra, SELECT_ADD);
1214 ale->update |= ANIM_UPDATE_DEPS;
1215 }
1216 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1218 static_cast<GreasePencilLayer *>(ale->data)->wrap(), ce->cfra, SELECT_ADD);
1219 ale->update |= ANIM_UPDATE_DEPS;
1220 }
1221 else if (ale->type == ANIMTYPE_MASKLAYER) {
1222 ED_mask_select_frame(static_cast<MaskLayer *>(ale->data), ce->cfra, SELECT_ADD);
1223 }
1224 else {
1226 &ked, static_cast<FCurve *>(ale->key_data), ok_cb, select_cb, nullptr);
1227 }
1228 }
1229 }
1230
1231 /* free elements */
1232 BLI_freelistN(&ked.list);
1233
1234 ANIM_animdata_update(ac, &anim_data);
1235 ANIM_animdata_freelist(&anim_data);
1236}
1237
1238/* ------------------- */
1239
1241{
1242 bAnimContext ac;
1243 short mode;
1244
1245 /* get editor data */
1246 if (ANIM_animdata_get_context(C, &ac) == 0) {
1247 return OPERATOR_CANCELLED;
1248 }
1249
1250 /* action to take depends on the mode */
1251 mode = RNA_enum_get(op->ptr, "mode");
1252
1255 }
1256 else {
1257 columnselect_action_keys(&ac, mode);
1258 }
1259
1260 /* set notifier that keyframe selection have changed */
1264 }
1265 return OPERATOR_FINISHED;
1266}
1267
1269{
1270 /* identifiers */
1271 ot->name = "Select All";
1272 ot->idname = "ACTION_OT_select_column";
1273 ot->description = "Select all keyframes on the specified frame(s)";
1274
1275 /* API callbacks. */
1278
1279 /* flags */
1280 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1281
1282 /* props */
1283 ot->prop = RNA_def_enum(ot->srna, "mode", prop_column_select_types, 0, "Mode", "");
1285}
1286
1288
1289/* -------------------------------------------------------------------- */
1292
1294{
1295 bAnimContext ac;
1296
1297 ListBase anim_data = {nullptr, nullptr};
1299
1302
1303 /* get editor data */
1304 if (ANIM_animdata_get_context(C, &ac) == 0) {
1305 return OPERATOR_CANCELLED;
1306 }
1307
1308 /* loop through all of the keys and select additional keyframes based on these */
1311 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
1312
1313 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1314 FCurve *fcu = (FCurve *)ale->key_data;
1315
1316 /* check if anything selected? */
1317 if (ANIM_fcurve_keyframes_loop(nullptr, fcu, nullptr, ok_cb, nullptr)) {
1318 /* select every keyframe in this curve then */
1319 ANIM_fcurve_keyframes_loop(nullptr, fcu, nullptr, sel_cb, nullptr);
1320 }
1321 }
1322
1323 /* Cleanup */
1324 ANIM_animdata_freelist(&anim_data);
1325
1326 /* set notifier that keyframe selection has changed */
1330 }
1331 return OPERATOR_FINISHED;
1332}
1333
1335{
1336 /* identifiers */
1337 ot->name = "Select Linked";
1338 ot->idname = "ACTION_OT_select_linked";
1339 ot->description = "Select keyframes occurring in the same F-Curves as selected ones";
1340
1341 /* API callbacks. */
1344
1345 /* flags */
1346 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1347}
1348
1350
1351/* -------------------------------------------------------------------- */
1354
1355/* Common code to perform selection */
1356static void select_moreless_action_keys(bAnimContext *ac, short mode)
1357{
1358 ListBase anim_data = {nullptr, nullptr};
1360
1361 KeyframeEditData ked = {{nullptr}};
1362 KeyframeEditFunc build_cb;
1363
1364 /* init selmap building data */
1365 build_cb = ANIM_editkeyframes_buildselmap(mode);
1366
1367 /* loop through all of the keys and select additional keyframes based on these */
1370 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1371
1372 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1373
1374 /* TODO: other types. */
1375 if (ale->datatype != ALE_FCURVE) {
1376 continue;
1377 }
1378
1379 /* only continue if F-Curve has keyframes */
1380 FCurve *fcu = (FCurve *)ale->key_data;
1381 if (fcu->bezt == nullptr) {
1382 continue;
1383 }
1384
1385 /* build up map of whether F-Curve's keyframes should be selected or not */
1386 ked.data = MEM_callocN(fcu->totvert, "selmap actEdit more");
1387 ANIM_fcurve_keyframes_loop(&ked, fcu, nullptr, build_cb, nullptr);
1388
1389 /* based on this map, adjust the selection status of the keyframes */
1390 ANIM_fcurve_keyframes_loop(&ked, fcu, nullptr, bezt_selmap_flush, nullptr);
1391
1392 /* free the selmap used here */
1393 MEM_freeN(ked.data);
1394 ked.data = nullptr;
1395 }
1396
1397 /* Cleanup */
1398 ANIM_animdata_freelist(&anim_data);
1399}
1400
1401/* ----------------- */
1402
1404{
1405 bAnimContext ac;
1406
1407 /* get editor data */
1408 if (ANIM_animdata_get_context(C, &ac) == 0) {
1409 return OPERATOR_CANCELLED;
1410 }
1411
1412 /* perform select changes */
1414
1415 /* set notifier that keyframe selection has changed */
1419 }
1420 return OPERATOR_FINISHED;
1421}
1422
1424{
1425 /* identifiers */
1426 ot->name = "Select More";
1427 ot->idname = "ACTION_OT_select_more";
1428 ot->description = "Select keyframes beside already selected ones";
1429
1430 /* API callbacks. */
1433
1434 /* flags */
1435 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1436}
1437
1438/* ----------------- */
1439
1441{
1442 bAnimContext ac;
1443
1444 /* get editor data */
1445 if (ANIM_animdata_get_context(C, &ac) == 0) {
1446 return OPERATOR_CANCELLED;
1447 }
1448
1449 /* perform select changes */
1451
1452 /* set notifier that keyframe selection has changed */
1456 }
1457 return OPERATOR_FINISHED;
1458}
1459
1461{
1462 /* identifiers */
1463 ot->name = "Select Less";
1464 ot->idname = "ACTION_OT_select_less";
1465 ot->description = "Deselect keyframes on ends of selection islands";
1466
1467 /* API callbacks. */
1470
1471 /* flags */
1472 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1473}
1474
1476
1477/* -------------------------------------------------------------------- */
1482
1483/* defines for left-right select tool */
1485 {ACTKEYS_LRSEL_TEST, "CHECK", 0, "Check if Select Left or Right", ""},
1486 {ACTKEYS_LRSEL_LEFT, "LEFT", 0, "Before Current Frame", ""},
1487 {ACTKEYS_LRSEL_RIGHT, "RIGHT", 0, "After Current Frame", ""},
1488 {0, nullptr, 0, nullptr, nullptr},
1489};
1490
1491/* --------------------------------- */
1492
1494 short leftright,
1495 eEditKeyframes_Select select_mode)
1496{
1497 ListBase anim_data = {nullptr, nullptr};
1499
1500 KeyframeEditFunc ok_cb, select_cb;
1501 KeyframeEditData ked = {{nullptr}};
1502 Scene *scene = ac->scene;
1503
1504 /* if select mode is replace, deselect all keyframes (and channels) first */
1505 if (select_mode == SELECT_REPLACE) {
1506 select_mode = SELECT_ADD;
1507
1508 /* - deselect all other keyframes, so that just the newly selected remain
1509 * - channels aren't deselected, since we don't re-select any as a consequence
1510 */
1512 }
1513
1514 /* set callbacks and editing data */
1516 select_cb = ANIM_editkeyframes_select(select_mode);
1517
1518 if (leftright == ACTKEYS_LRSEL_LEFT) {
1519 ked.f1 = MINAFRAMEF;
1520 ked.f2 = float(scene->r.cfra + 0.1f);
1521 }
1522 else {
1523 ked.f1 = float(scene->r.cfra - 0.1f);
1524 ked.f2 = MAXFRAMEF;
1525 }
1526
1527 /* filter data */
1529 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1530
1531 /* select keys */
1532 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1533 switch (ale->type) {
1536 static_cast<GreasePencilLayerTreeNode *>(ale->data)->wrap(),
1537 ked.f1,
1538 ked.f2,
1539 select_mode);
1540 ale->update |= ANIM_UPDATE_DEPS;
1541 break;
1542 case ANIMTYPE_GPLAYER:
1544 static_cast<bGPDlayer *>(ale->data), ked.f1, ked.f2, select_mode);
1545 ale->update |= ANIM_UPDATE_DEPS;
1546 break;
1547
1548 case ANIMTYPE_MASKLAYER:
1550 static_cast<MaskLayer *>(ale->data), ked.f1, ked.f2, select_mode);
1551 break;
1552
1553 case ANIMTYPE_FCURVE: {
1554 FCurve *fcurve = static_cast<FCurve *>(ale->key_data);
1555 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcurve, false, true);
1556 ANIM_fcurve_keyframes_loop(&ked, fcurve, ok_cb, select_cb, nullptr);
1557 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcurve, true, true);
1558 break;
1559 }
1560
1561 default:
1562 BLI_assert_msg(false, "Keys cannot be selected into this animation type.");
1563 }
1564 }
1565
1566 /* Sync marker support */
1567 if (select_mode == SELECT_ADD) {
1568 SpaceAction *saction = (SpaceAction *)ac->sl;
1569
1570 if ((saction) && (saction->flag & SACTION_MARKERS_MOVE)) {
1571 ListBase *markers = ED_animcontext_get_markers(ac);
1572 LISTBASE_FOREACH (TimeMarker *, marker, markers) {
1573 if (((leftright == ACTKEYS_LRSEL_LEFT) && (marker->frame < scene->r.cfra)) ||
1574 ((leftright == ACTKEYS_LRSEL_RIGHT) && (marker->frame >= scene->r.cfra)))
1575 {
1576 marker->flag |= SELECT;
1577 }
1578 else {
1579 marker->flag &= ~SELECT;
1580 }
1581 }
1582 }
1583 }
1584
1585 /* Cleanup */
1586 ANIM_animdata_update(ac, &anim_data);
1587 ANIM_animdata_freelist(&anim_data);
1588}
1589
1590/* ----------------- */
1591
1593{
1594 bAnimContext ac;
1595 short leftright = RNA_enum_get(op->ptr, "mode");
1596 eEditKeyframes_Select selectmode;
1597
1598 /* get editor data */
1599 if (ANIM_animdata_get_context(C, &ac) == 0) {
1600 return OPERATOR_CANCELLED;
1601 }
1602
1603 /* select mode is either replace (deselect all, then add) or add/extend */
1604 if (RNA_boolean_get(op->ptr, "extend")) {
1605 selectmode = SELECT_INVERT;
1606 }
1607 else {
1608 selectmode = SELECT_REPLACE;
1609 }
1610
1611 /* if "test" mode is set, we don't have any info to set this with */
1612 if (leftright == ACTKEYS_LRSEL_TEST) {
1613 return OPERATOR_CANCELLED;
1614 }
1615
1616 /* do the selecting now */
1617 actkeys_select_leftright(&ac, leftright, selectmode);
1618
1619 /* set notifier that keyframe selection (and channels too) have changed */
1622
1623 return OPERATOR_FINISHED;
1624}
1625
1627 wmOperator *op,
1628 const wmEvent *event)
1629{
1630 bAnimContext ac;
1631 short leftright = RNA_enum_get(op->ptr, "mode");
1632
1633 /* get editor data */
1634 if (ANIM_animdata_get_context(C, &ac) == 0) {
1635 return OPERATOR_CANCELLED;
1636 }
1637
1638 /* handle mode-based testing */
1639 if (leftright == ACTKEYS_LRSEL_TEST) {
1640 Scene *scene = ac.scene;
1641 ARegion *region = ac.region;
1642 View2D *v2d = &region->v2d;
1643 float x;
1644
1645 /* determine which side of the current frame mouse is on */
1646 x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
1647 if (x < scene->r.cfra) {
1648 RNA_enum_set(op->ptr, "mode", ACTKEYS_LRSEL_LEFT);
1649 }
1650 else {
1651 RNA_enum_set(op->ptr, "mode", ACTKEYS_LRSEL_RIGHT);
1652 }
1653 }
1654
1655 /* perform selection */
1656 return actkeys_select_leftright_exec(C, op);
1657}
1658
1660{
1661 PropertyRNA *prop;
1662
1663 /* identifiers */
1664 ot->name = "Select Left/Right";
1665 ot->idname = "ACTION_OT_select_leftright";
1666 ot->description = "Select keyframes to the left or the right of the current frame";
1667
1668 /* API callbacks. */
1672
1673 /* flags */
1674 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1675
1676 /* properties */
1677 ot->prop = RNA_def_enum(
1678 ot->srna, "mode", prop_actkeys_leftright_select_types, ACTKEYS_LRSEL_TEST, "Mode", "");
1680
1681 prop = RNA_def_boolean(ot->srna, "extend", false, "Extend Select", "");
1683}
1684
1686
1687/* -------------------------------------------------------------------- */
1699
1700/* option 1) select keyframe directly under mouse */
1702 bAnimListElem *ale,
1703 const eEditKeyframes_Select select_mode,
1704 float selx)
1705{
1706 KeyframeEditData ked = {{nullptr}};
1707 KeyframeEditFunc select_cb, ok_cb;
1708
1709 /* get functions for selecting keyframes */
1710 select_cb = ANIM_editkeyframes_select(select_mode);
1712 ked.f1 = selx;
1714
1715 /* select the nominated keyframe on the given frame */
1716 if (ale->type == ANIMTYPE_GPLAYER) {
1717 ED_gpencil_select_frame(static_cast<bGPDlayer *>(ale->data), selx, select_mode);
1718 ale->update |= ANIM_UPDATE_DEPS;
1719 }
1720 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1722 static_cast<GreasePencilLayer *>(ale->data)->wrap(), selx, select_mode);
1723 ale->update |= ANIM_UPDATE_DEPS;
1724 }
1725 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER_GROUP) {
1727 static_cast<GreasePencilLayerTreeGroup *>(ale->data)->wrap(), selx, select_mode);
1728 }
1729 else if (ale->type == ANIMTYPE_GREASE_PENCIL_DATABLOCK) {
1730 ListBase anim_data = {nullptr, nullptr};
1732
1734 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1735
1736 /* Loop over all keys that are represented by this data-block key. */
1737 LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
1738 if ((ale2->type != ANIMTYPE_GREASE_PENCIL_LAYER) || (ale2->id != ale->data)) {
1739 continue;
1740 }
1742 static_cast<GreasePencilLayer *>(ale2->data)->wrap(), selx, select_mode);
1743 ale2->update |= ANIM_UPDATE_DEPS;
1744 }
1745 }
1746 else if (ale->type == ANIMTYPE_MASKLAYER) {
1747 ED_mask_select_frame(static_cast<MaskLayer *>(ale->data), selx, select_mode);
1748 }
1749 else {
1750 if (ale->type == ANIMTYPE_SUMMARY && ale->datatype == ALE_ALL) {
1751 ListBase anim_data = {nullptr, nullptr};
1753
1755 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1756
1757 /* Loop over all keys that are represented by this summary key. */
1758 LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
1759 switch (ale2->type) {
1760 case ANIMTYPE_GPLAYER:
1761 ED_gpencil_select_frame(static_cast<bGPDlayer *>(ale2->data), selx, select_mode);
1762 ale2->update |= ANIM_UPDATE_DEPS;
1763 break;
1764
1765 case ANIMTYPE_MASKLAYER:
1766 ED_mask_select_frame(static_cast<MaskLayer *>(ale2->data), selx, select_mode);
1767 break;
1768
1771 static_cast<GreasePencilLayer *>(ale2->data)->wrap(), selx, select_mode);
1772 ale2->update |= ANIM_UPDATE_DEPS;
1773 break;
1774
1775 default:
1776 break;
1777 }
1778 }
1779
1780 ANIM_animdata_update(ac, &anim_data);
1781 ANIM_animdata_freelist(&anim_data);
1782 }
1783
1785 ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, nullptr);
1786 }
1787 }
1788}
1789
1790/* Option 2) Selects all the keyframes on either side of the current frame
1791 * (depends on which side the mouse is on) */
1792/* (see actkeys_select_leftright) */
1793
1794/* Option 3) Selects all visible keyframes in the same frame as the mouse click */
1795static void actkeys_mselect_column(bAnimContext *ac, eEditKeyframes_Select select_mode, float selx)
1796{
1797 ListBase anim_data = {nullptr, nullptr};
1799
1800 KeyframeEditFunc select_cb, ok_cb;
1801 KeyframeEditData ked = {{nullptr}};
1802
1803 /* set up BezTriple edit callbacks */
1804 select_cb = ANIM_editkeyframes_select(select_mode);
1806
1807 /* loop through all of the keys and select additional keyframes
1808 * based on the keys found to be selected above
1809 */
1811 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1812
1813 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1814 /* select elements with frame number matching cfra */
1815 if (ale->type == ANIMTYPE_GPLAYER) {
1816 ED_gpencil_select_frame(static_cast<bGPDlayer *>(ale->data), selx, select_mode);
1817 ale->update |= ANIM_UPDATE_DEPS;
1818 }
1819 else if (ale->type == ANIMTYPE_MASKLAYER) {
1820 ED_mask_select_frame(static_cast<MaskLayer *>(ale->data), selx, select_mode);
1821 }
1822 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1824 static_cast<GreasePencilLayer *>(ale->data)->wrap(), selx, select_mode);
1825 ale->update |= ANIM_UPDATE_DEPS;
1826 }
1827 else {
1828 /* set frame for validation callback to refer to */
1830
1832 &ked, static_cast<FCurve *>(ale->key_data), ok_cb, select_cb, nullptr);
1833 }
1834 }
1835
1836 /* free elements */
1837 BLI_freelistN(&ked.list);
1838
1839 ANIM_animdata_update(ac, &anim_data);
1840 ANIM_animdata_freelist(&anim_data);
1841}
1842
1843/* option 4) select all keyframes in same channel */
1845 bAnimListElem *ale,
1846 eEditKeyframes_Select select_mode)
1847{
1848 KeyframeEditFunc select_cb;
1849
1850 /* get functions for selecting keyframes */
1851 select_cb = ANIM_editkeyframes_select(select_mode);
1852
1853 /* select all keyframes in this channel */
1854 if (ale->type == ANIMTYPE_GPLAYER) {
1855 ED_gpencil_select_frames(static_cast<bGPDlayer *>(ale->data), select_mode);
1856 ale->update = ANIM_UPDATE_DEPS;
1857 }
1858 else if (ale->type == ANIMTYPE_MASKLAYER) {
1859 ED_mask_select_frames(static_cast<MaskLayer *>(ale->data), select_mode);
1860 }
1861 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1863 static_cast<GreasePencilLayer *>(ale->data)->wrap(), select_mode);
1864 ale->update |= ANIM_UPDATE_DEPS;
1865 }
1866 else {
1867 if (ale->type == ANIMTYPE_SUMMARY && ale->datatype == ALE_ALL) {
1868 ListBase anim_data = {nullptr, nullptr};
1870
1872 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1873
1874 LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
1875 if (ale2->type == ANIMTYPE_GPLAYER) {
1876 ED_gpencil_select_frames(static_cast<bGPDlayer *>(ale2->data), select_mode);
1877 ale2->update |= ANIM_UPDATE_DEPS;
1878 }
1879 else if (ale2->type == ANIMTYPE_MASKLAYER) {
1880 ED_mask_select_frames(static_cast<MaskLayer *>(ale2->data), select_mode);
1881 }
1882 }
1883
1884 ANIM_animdata_update(ac, &anim_data);
1885 ANIM_animdata_freelist(&anim_data);
1886 }
1887
1889 ANIM_animchannel_keyframes_loop(nullptr, ac->ads, ale, nullptr, select_cb, nullptr);
1890 }
1891 }
1892}
1893
1894/* ------------------- */
1895
1897 const int mval[2],
1898 eEditKeyframes_Select select_mode,
1899 const bool deselect_all,
1900 const bool column,
1901 const bool same_channel,
1902 bool wait_to_deselect_others)
1903{
1904 /* NOTE: keep this functionality in sync with #MARKER_OT_select.
1905 * The logic here closely matches its internals.
1906 * From a user perspective the functions should also behave in much the same way. */
1907
1910
1911 bAnimListElem *ale = nullptr;
1912 bool found = false;
1913 bool is_selected = false;
1914 float frame = 0.0f; /* frame of keyframe under mouse - NLA corrections not applied/included */
1915 float selx = 0.0f; /* frame of keyframe under mouse */
1917
1919 ac, filter, mval[0], mval[1], &ale, &selx, &frame, &found, &is_selected);
1920
1921 if (select_mode != SELECT_REPLACE) {
1922 wait_to_deselect_others = false;
1923 }
1924
1925 /* For replacing selection, if we have something to select, we have to clear existing selection.
1926 * The same goes if we found nothing to select, and deselect_all is true
1927 * (deselect on nothing behavior). */
1928 if ((select_mode == SELECT_REPLACE && found) || (!found && deselect_all)) {
1929 /* reset selection mode for next steps */
1930 select_mode = SELECT_ADD;
1931
1932 /* Rather than deselecting others, users may want to drag to box-select (drag from empty space)
1933 * or tweak-translate an already selected item. If these cases may apply, delay deselection. */
1934 if (wait_to_deselect_others && (!found || is_selected)) {
1935 ret_value = OPERATOR_RUNNING_MODAL;
1936 }
1937 else {
1938 /* deselect all keyframes */
1940
1941 /* highlight channel clicked on */
1943 /* deselect all other channels first */
1945
1946 /* Highlight Action-Group or F-Curve? */
1947 if (ale != nullptr && ale->data) {
1948 if (ale->type == ANIMTYPE_GROUP) {
1949 bActionGroup *agrp = static_cast<bActionGroup *>(ale->data);
1950
1951 agrp->flag |= AGRP_SELECTED;
1953 ac, ac->data, eAnimCont_Types(ac->datatype), filter, agrp, ANIMTYPE_GROUP);
1954 }
1955 else if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
1956 FCurve *fcu = static_cast<FCurve *>(ale->data);
1957
1958 fcu->flag |= FCURVE_SELECTED;
1960 ac->data,
1962 filter,
1963 fcu,
1964 eAnim_ChannelType(ale->type));
1965 }
1966 else if (ale->type == ANIMTYPE_GPLAYER) {
1967 bGPdata *gpd = (bGPdata *)ale->id;
1968 bGPDlayer *gpl = static_cast<bGPDlayer *>(ale->data);
1969
1971 }
1972 else if (ale->type == ANIMTYPE_ACTION_SLOT) {
1974 "fcurve_owner_id of an Action Slot should be an Action");
1975 animrig::Action *action = reinterpret_cast<animrig::Action *>(ale->fcurve_owner_id);
1976 animrig::Slot *slot = static_cast<animrig::Slot *>(ale->data);
1977 slot->set_selected(true);
1978 action->slot_active_set(slot->handle);
1979 }
1980 }
1981 }
1982 else if (ac->datatype == ANIMCONT_GPENCIL) {
1983 /* Deselect all other channels first. */
1985
1986 /* Highlight the grease pencil channel, and set the corresponding layer as active. */
1987 if (ale != nullptr && ale->data != nullptr && ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1989 *reinterpret_cast<GreasePencil *>(ale->id),
1990 static_cast<blender::bke::greasepencil::Layer *>(ale->data));
1991 }
1992
1993 /* Highlight GPencil Layer (Legacy). */
1994 if (ale != nullptr && ale->data != nullptr && ale->type == ANIMTYPE_GPLAYER) {
1995 bGPdata *gpd = (bGPdata *)ale->id;
1996 bGPDlayer *gpl = static_cast<bGPDlayer *>(ale->data);
1997
1999 }
2000 }
2001 else if (ac->datatype == ANIMCONT_MASK) {
2002 /* deselect all other channels first */
2004
2005 if (ale != nullptr && ale->data != nullptr && ale->type == ANIMTYPE_MASKLAYER) {
2006 MaskLayer *masklay = static_cast<MaskLayer *>(ale->data);
2007
2008 masklay->flag |= MASK_LAYERFLAG_SELECT;
2009 }
2010 }
2011 }
2012 }
2013
2014 /* only select keyframes if we clicked on a valid channel and hit something */
2015 if (ale != nullptr) {
2016 if (found) {
2017 /* apply selection to keyframes */
2018 if (column) {
2019 /* select all keyframes in the same frame as the one we hit on the active channel
2020 * [#41077]: "frame" not "selx" here (i.e. no NLA corrections yet) as the code here
2021 * does that itself again as it needs to work on multiple data-blocks.
2022 */
2023 actkeys_mselect_column(ac, select_mode, frame);
2024 }
2025 else if (same_channel) {
2026 /* select all keyframes in the active channel */
2027 actkeys_mselect_channel_only(ac, ale, select_mode);
2028 }
2029 else {
2030 /* select the nominated keyframe on the given frame */
2031 actkeys_mselect_single(ac, ale, select_mode, selx);
2032 }
2033 }
2034
2035 /* flush tagged updates
2036 * NOTE: We temporarily add this channel back to the list so that this can happen
2037 */
2038 ListBase anim_data = {ale, ale};
2039 ANIM_animdata_update(ac, &anim_data);
2040
2041 /* free this channel */
2042 MEM_freeN(ale);
2043 }
2044
2045 return ret_value;
2046}
2047
2048/* handle clicking */
2050{
2051 bAnimContext ac;
2052 wmOperatorStatus ret_value;
2053
2054 /* get editor data */
2055 if (ANIM_animdata_get_context(C, &ac) == 0) {
2056 return OPERATOR_CANCELLED;
2057 }
2058
2059 /* get useful pointers from animation context data */
2060 // region = ac.region; /* UNUSED. */
2061
2062 /* select mode is either replace (deselect all, then add) or add/extend */
2063 const eEditKeyframes_Select selectmode = RNA_boolean_get(op->ptr, "extend") ? SELECT_INVERT :
2065 const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
2066 const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
2067 int mval[2];
2068
2069 /* column selection */
2070 const bool column = RNA_boolean_get(op->ptr, "column");
2071 const bool channel = RNA_boolean_get(op->ptr, "channel");
2072
2073 mval[0] = RNA_int_get(op->ptr, "mouse_x");
2074 mval[1] = RNA_int_get(op->ptr, "mouse_y");
2075
2076 /* Select keyframe(s) based upon mouse position. */
2077 ret_value = mouse_action_keys(
2078 &ac, mval, selectmode, deselect_all, column, channel, wait_to_deselect_others);
2079
2080 /* set notifier that keyframe selection (and channels too) have changed */
2083
2084 /* for tweak grab to work */
2085 return ret_value | OPERATOR_PASS_THROUGH;
2086}
2087
2089{
2090 PropertyRNA *prop;
2091
2092 /* identifiers */
2093 ot->name = "Select Keyframes";
2094 ot->idname = "ACTION_OT_clickselect";
2095 ot->description = "Select keyframes by clicking on them";
2096
2097 /* callbacks */
2100 ot->invoke = WM_generic_select_invoke;
2101 ot->modal = WM_generic_select_modal;
2102
2103 /* flags */
2104 ot->flag = OPTYPE_UNDO;
2105
2106 /* properties */
2108 /* Key-map: Enable with `Shift`. */
2109 prop = RNA_def_boolean(
2110 ot->srna,
2111 "extend",
2112 false,
2113 "Extend Select",
2114 "Toggle keyframe selection instead of leaving newly selected keyframes only");
2116
2117 prop = RNA_def_boolean(ot->srna,
2118 "deselect_all",
2119 false,
2120 "Deselect On Nothing",
2121 "Deselect all when nothing under the cursor");
2123
2124 /* Key-map: Enable with `Alt`. */
2125 prop = RNA_def_boolean(
2126 ot->srna,
2127 "column",
2128 false,
2129 "Column Select",
2130 "Select all keyframes that occur on the same frame as the one under the mouse");
2132
2133 /* Key-map: Enable with `Ctrl-Alt`. */
2134 prop = RNA_def_boolean(ot->srna,
2135 "channel",
2136 false,
2137 "Only Channel",
2138 "Select all the keyframes in the channel under the mouse");
2140}
2141
Low-level operations for grease pencil.
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:540
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
void BLI_lasso_boundbox(rcti *rect, blender::Span< blender::int2 > mcoords)
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
#define LISTBASE_FOREACH(type, var, list)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
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
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
void BLI_rctf_rcti_copy(struct rctf *dst, const struct rcti *src)
#define ELEM(...)
@ ID_AC
@ AGRP_SELECTED
@ SACTION_MARKERS_MOVE
@ FCURVE_SELECTED
@ MASK_LAYERFLAG_SELECT
Object is a sort of wrapper for general info.
#define MAXFRAMEF
#define MINAFRAMEF
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
@ ACHANNEL_SETFLAG_CLEAR
eAnim_ChannelType
@ ANIMTYPE_SUMMARY
@ ANIMTYPE_NLACURVE
@ ANIMTYPE_GROUP
@ ANIMTYPE_ACTION_SLOT
@ ANIMTYPE_GREASE_PENCIL_DATABLOCK
@ ANIMTYPE_GPLAYER
@ ANIMTYPE_MASKDATABLOCK
@ ANIMTYPE_MASKLAYER
@ ANIMTYPE_FCURVE
@ ANIMTYPE_GREASE_PENCIL_LAYER
@ ANIMTYPE_GREASE_PENCIL_LAYER_GROUP
@ ALE_GREASE_PENCIL_GROUP
@ ALE_SCE
@ ALE_GREASE_PENCIL_CEL
@ ALE_GREASE_PENCIL_DATA
@ ALE_NONE
@ ALE_GPFRAME
@ ALE_FCURVE
@ ALE_NLASTRIP
@ ALE_ALL
@ ALE_ACT
@ ALE_ACTION_LAYERED
@ ALE_OB
@ ALE_GROUP
@ ALE_ACTION_SLOT
@ ALE_MASKLAY
@ ANIM_UPDATE_DEPS
eAnimCont_Types
@ ANIMCONT_MASK
@ ANIMCONT_TIMELINE
@ ANIMCONT_DOPESHEET
@ ANIMCONT_ACTION
@ ANIMCONT_GPENCIL
eAnimFilter_Flags
@ ANIMFILTER_DATA_VISIBLE
@ ANIMFILTER_LIST_VISIBLE
@ ANIMFILTER_LIST_CHANNELS
@ ANIMFILTER_NODUPLIS
@ ANIMFILTER_FCURVESONLY
@ BEZT_OK_CHANNEL_CIRCLE
@ BEZT_OK_FRAMERANGE
@ BEZT_OK_FRAME
@ BEZT_OK_SELECTED
@ BEZT_OK_CHANNEL_LASSO
@ KED_F1_NLA_UNMAP
@ KED_F2_NLA_UNMAP
short(*)(KeyframeEditData *ked, BezTriple *bezt) KeyframeEditFunc
@ SELMAP_MORE
@ SELMAP_LESS
eEditKeyframes_Select
@ SELECT_INVERT
@ SELECT_SUBTRACT
@ SELECT_REPLACE
@ SELECT_ADD
bool ED_masklayer_frame_select_check(const MaskLayer *mask_layer)
void ED_mask_select_frame(MaskLayer *mask_layer, int selx, short select_mode)
void ED_mask_select_frames(MaskLayer *mask_layer, short select_mode)
void ED_masklayer_frames_select_region(KeyframeEditData *ked, MaskLayer *mask_layer, short tool, short select_mode)
void ED_masklayer_frames_select_box(MaskLayer *mask_layer, float min, float max, short select_mode)
void ED_masklayer_frame_select_set(MaskLayer *mask_layer, short mode)
bool ED_operator_action_active(bContext *C)
eSelectOp
@ SEL_OP_SUB
eSelectOp ED_select_op_modal(eSelectOp sel_op, bool is_first)
#define SEL_OP_USE_PRE_DESELECT(sel_op)
std::string ED_select_circle_get_name(wmOperatorType *ot, PointerRNA *ptr)
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
Read Guarded memory(de)allocation.
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
@ PROP_HIDDEN
Definition RNA_types.hh:324
#define C
Definition RandGen.cpp:29
void UI_view2d_listview_view_to_cell(float columnwidth, float rowheight, float startx, float starty, float viewx, float viewy, int *r_column, int *r_row)
Definition view2d.cc:1620
void UI_view2d_region_to_view(const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
Definition view2d.cc:1667
float UI_view2d_region_to_view_x(const View2D *v2d, float x)
Definition view2d.cc:1656
void UI_view2d_region_to_view_rctf(const View2D *v2d, const rctf *rect_src, rctf *rect_dst) ATTR_NONNULL()
Definition view2d.cc:1674
@ OPTYPE_DEPENDS_ON_CURSOR
Definition WM_types.hh:218
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NC_ANIMATION
Definition WM_types.hh:385
#define ND_KEYFRAME
Definition WM_types.hh:491
#define ND_ANIMCHAN
Definition WM_types.hh:493
#define NA_SELECTED
Definition WM_types.hh:586
@ ACTKEYS_LRSEL_TEST
@ ACTKEYS_LRSEL_LEFT
@ ACTKEYS_LRSEL_RIGHT
@ ACTKEYS_COLUMNSEL_CFRA
@ ACTKEYS_COLUMNSEL_MARKERS_BETWEEN
@ ACTKEYS_COLUMNSEL_MARKERS_COLUMN
@ ACTKEYS_COLUMNSEL_KEYS
static wmOperatorStatus actkeys_select_less_exec(bContext *C, wmOperator *)
static bool actkeys_is_key_at_position(bAnimContext *ac, float region_x, float region_y)
static wmOperatorStatus actkeys_select_leftright_exec(bContext *C, wmOperator *op)
void ACTION_OT_select_column(wmOperatorType *ot)
static wmOperatorStatus actkeys_deselectall_exec(bContext *C, wmOperator *op)
@ ACTKEYS_BORDERSEL_ALLKEYS
@ ACTKEYS_BORDERSEL_CHANNELS
@ ACTKEYS_BORDERSEL_FRAMERANGE
static void box_select_elem(BoxSelectData *sel_data, bAnimListElem *ale, float xmin, float xmax, bool summary)
static void actkeys_select_leftright(bAnimContext *ac, short leftright, eEditKeyframes_Select select_mode)
void ACTION_OT_select_less(wmOperatorType *ot)
static void actkeys_mselect_single(bAnimContext *ac, bAnimListElem *ale, const eEditKeyframes_Select select_mode, float selx)
static void actkeys_mselect_column(bAnimContext *ac, eEditKeyframes_Select select_mode, float selx)
static void deselect_action_keys(bAnimContext *ac, short test, eEditKeyframes_Select sel)
static void actkeys_find_key_at_position(bAnimContext *ac, eAnimFilter_Flags filter, float region_x, float region_y, bAnimListElem **r_ale, float *r_selx, float *r_frame, bool *r_found, bool *r_is_selected)
static void actkeys_list_element_to_keylist(bAnimContext *ac, AnimKeylist *keylist, bAnimListElem *ale)
static wmOperatorStatus actkeys_select_more_exec(bContext *C, wmOperator *)
static wmOperatorStatus actkeys_select_linked_exec(bContext *C, wmOperator *)
static const EnumPropertyItem prop_actkeys_leftright_select_types[]
static wmOperatorStatus actkeys_box_select_exec(bContext *C, wmOperator *op)
static void region_select_elem(RegionSelectData *sel_data, bAnimListElem *ale, bool summary)
static wmOperatorStatus actkeys_clickselect_exec(bContext *C, wmOperator *op)
void ACTION_OT_select_all(wmOperatorType *ot)
static wmOperatorStatus mouse_action_keys(bAnimContext *ac, const int mval[2], eEditKeyframes_Select select_mode, const bool deselect_all, const bool column, const bool same_channel, bool wait_to_deselect_others)
static bAnimListElem * actkeys_find_list_element_at_position(bAnimContext *ac, eAnimFilter_Flags filter, float region_x, float region_y)
void ACTION_OT_select_lasso(wmOperatorType *ot)
static wmOperatorStatus actkeys_select_leftright_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void ACTION_OT_select_leftright(wmOperatorType *ot)
static wmOperatorStatus actkeys_columnselect_exec(bContext *C, wmOperator *op)
static void markers_selectkeys_between(bAnimContext *ac)
static wmOperatorStatus actkeys_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus action_circle_select_exec(bContext *C, wmOperator *op)
static void columnselect_action_keys(bAnimContext *ac, short mode)
static void select_moreless_action_keys(bAnimContext *ac, short mode)
static wmOperatorStatus actkeys_lassoselect_exec(bContext *C, wmOperator *op)
void ACTION_OT_select_linked(wmOperatorType *ot)
static void box_select_action(bAnimContext *ac, const rcti rect, short mode, const eEditKeyframes_Select selectmode)
static void actkeys_find_key_in_list_element(bAnimContext *ac, bAnimListElem *ale, float region_x, float *r_selx, float *r_frame, bool *r_found, bool *r_is_selected)
static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view, short mode, eEditKeyframes_Select selectmode, void *data)
static void actkeys_mselect_channel_only(bAnimContext *ac, bAnimListElem *ale, eEditKeyframes_Select select_mode)
void ACTION_OT_select_box(wmOperatorType *ot)
void ACTION_OT_select_circle(wmOperatorType *ot)
void ACTION_OT_clickselect(wmOperatorType *ot)
static const EnumPropertyItem prop_column_select_types[]
void ACTION_OT_select_more(wmOperatorType *ot)
float ANIM_UI_get_channel_step()
float ANIM_UI_get_first_channel_top(View2D *v2d)
float ANIM_UI_get_channel_height()
void ANIM_anim_channels_select_set(bAnimContext *ac, eAnimChannels_SetFlag sel)
void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datatype, eAnimFilter_Flags filter, void *channel_data, eAnim_ChannelType channel_type)
void ANIM_animdata_freelist(ListBase *anim_data)
Definition anim_deps.cc:463
void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
Definition anim_deps.cc:356
void ANIM_nla_mapping_apply_if_needed_fcurve(bAnimListElem *ale, FCurve *fcu, const bool restore, const bool only_keys)
Definition anim_draw.cc:339
bool ANIM_nla_mapping_allowed(const bAnimListElem *ale)
Definition anim_draw.cc:212
float ANIM_nla_tweakedit_remap(bAnimListElem *ale, const float cframe, const eNlaTime_ConvertModes mode)
Definition anim_draw.cc:262
bool ANIM_animdata_can_have_greasepencil(const eAnimCont_Types type)
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_animcontext_get_markers(const bAnimContext *ac)
void ED_markers_get_minmax(ListBase *markers, short sel, float *r_first, float *r_last)
void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, const bool only_selected)
BMesh const char void * data
void slot_active_set(slot_handle_t slot_handle)
#define SELECT
void ED_gpencil_layer_frame_select_set(bGPDlayer *gpl, short mode)
void ED_gpencil_set_active_channel(bGPdata *gpd, bGPDlayer *gpl)
void ED_gpencil_select_frames(bGPDlayer *gpl, short select_mode)
bool ED_gpencil_layer_frame_select_check(const bGPDlayer *gpl)
void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode)
void ED_gpencil_layer_frames_select_region(KeyframeEditData *ked, bGPDlayer *gpl, short tool, short select_mode)
void ED_gpencil_layer_frames_select_box(bGPDlayer *gpl, float min, float max, short select_mode)
void ED_gpencil_layer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlysel)
#define filter
#define GS(a)
short bezt_selmap_flush(KeyframeEditData *ked, BezTriple *bezt)
short bezt_to_cfraelem(KeyframeEditData *ked, BezTriple *bezt)
KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode)
short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, bAnimListElem *ale, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, FCurve *fcu, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
KeyframeEditFunc ANIM_editkeyframes_select(const eEditKeyframes_Select selectmode)
void mask_to_keylist(bDopeSheet *, MaskLayer *masklay, AnimKeylist *keylist)
void action_slot_summary_to_keylist(bAnimContext *ac, ID *animated_id, animrig::Action &action, const animrig::slot_handle_t slot_handle, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
const ActKeyColumn * ED_keylist_find_any_between(const AnimKeylist *keylist, const Bounds< float > frame_range)
void fcurve_to_keylist(AnimData *adt, FCurve *fcu, AnimKeylist *keylist, const int saction_flag, blender::float2 range, const bool use_nla_remapping)
void scene_to_keylist(bDopeSheet *ads, Scene *sce, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
void ob_to_keylist(bDopeSheet *ads, Object *ob, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
void grease_pencil_data_block_to_keylist(AnimData *adt, const GreasePencil *grease_pencil, AnimKeylist *keylist, const int saction_flag, const bool active_layer_only)
void ED_keylist_prepare_for_direct_access(AnimKeylist *keylist)
void summary_to_keylist(bAnimContext *ac, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
AnimKeylist * ED_keylist_create()
void ED_keylist_free(AnimKeylist *keylist)
void grease_pencil_layer_group_to_keylist(AnimData *adt, const GreasePencilLayerTreeGroup *layer_group, AnimKeylist *keylist, const int saction_flag)
void action_to_keylist(AnimData *adt, bAction *dna_action, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
void grease_pencil_cels_to_keylist(AnimData *, const GreasePencilLayer *gpl, AnimKeylist *keylist, int)
void gpl_to_keylist(bDopeSheet *, bGPDlayer *gpl, AnimKeylist *keylist)
void action_group_to_keylist(AnimData *adt, bActionGroup *agrp, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
void select_frames_at(bke::greasepencil::LayerGroup &layer_group, const int frame_number, const short select_mode)
void select_frames_range(bke::greasepencil::TreeNode &node, const float min, const float max, const short select_mode)
void select_frames_region(KeyframeEditData *ked, bke::greasepencil::TreeNode &node, const short tool, const short select_mode)
bool has_any_frame_selected(const bke::greasepencil::Layer &layer)
void select_all_frames(bke::greasepencil::Layer &layer, const short select_mode)
void select_layer_channel(GreasePencil &grease_pencil, bke::greasepencil::Layer *layer)
bool select_frame_at(bke::greasepencil::Layer &layer, const int frame_number, const short select_mode)
VecBase< float, 2 > float2
int RNA_int_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
#define min(a, b)
Definition sort.cc:36
int32_t slot_handle
KeyframeEditFunc select_cb
KeyframeEditFunc ok_cb
KeyframeEditData ked
bAnimContext * ac
BezTriple * bezt
unsigned int totvert
char name[66]
Definition DNA_ID.h:415
eKeyframeIterFlags iterflags
blender::Array< blender::int2 > mcoords
void * first
struct MaskLayer * next
KeyframeEditFunc ok_cb
bAnimContext * ac
KeyframeEditFunc select_cb
KeyframeEditData ked
struct RenderData r
SpaceLink * sl
ListBase * markers
eAnimCont_Types datatype
bDopeSheet * ads
ARegion * region
AnimData * adt
bAnimListElem * next
eAnim_ChannelType type
eAnim_Update_Flags update
eAnim_KeyType datatype
bAnimListElem * prev
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
int mval[2]
Definition WM_types.hh:760
struct PointerRNA * ptr
max
Definition text_draw.cc:251
void WM_event_drag_start_mval(const wmEvent *event, const ARegion *region, int r_mval[2])
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4225
bool WM_gesture_is_modal_first(const wmGesture *gesture)
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
wmOperatorStatus WM_gesture_circle_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Array< int2 > WM_gesture_lasso_path_to_array(bContext *, wmOperator *op)
wmOperatorStatus WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void WM_gesture_circle_cancel(bContext *C, wmOperator *op)
void WM_gesture_lasso_cancel(bContext *C, wmOperator *op)
wmOperatorStatus WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void WM_operator_properties_border_to_rcti(wmOperator *op, rcti *r_rect)
void WM_operator_properties_gesture_box(wmOperatorType *ot)
void WM_operator_properties_select_operation_simple(wmOperatorType *ot)
void WM_operator_properties_generic_select(wmOperatorType *ot)
void WM_operator_properties_gesture_lasso(wmOperatorType *ot)
void WM_operator_properties_gesture_circle(wmOperatorType *ot)
void WM_operator_properties_select_all(wmOperatorType *ot)
wmOperatorStatus WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_generic_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)