Blender V5.0
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_view2d.hh"
35
36#include "ED_anim_api.hh"
37#include "ED_gpencil_legacy.hh"
38#include "ED_grease_pencil.hh"
39#include "ED_keyframes_edit.hh"
41#include "ED_markers.hh"
42#include "ED_mask.hh"
43#include "ED_screen.hh"
44#include "ED_select_utils.hh"
45
46#include "WM_api.hh"
47#include "WM_types.hh"
48
49#include "action_intern.hh"
50
51using namespace blender;
52
53/* -------------------------------------------------------------------- */
56
59 float region_x,
60 float region_y)
61{
62 View2D *v2d = &ac->region->v2d;
63
64 float view_x, view_y;
65 int channel_index;
66 UI_view2d_region_to_view(v2d, region_x, region_y, &view_x, &view_y);
69 0,
71 view_x,
72 view_y,
73 nullptr,
74 &channel_index);
75
76 ListBase anim_data = {nullptr, nullptr};
77 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
78
79 bAnimListElem *ale = static_cast<bAnimListElem *>(BLI_findlink(&anim_data, channel_index));
80 if (ale != nullptr) {
81 BLI_remlink(&anim_data, ale);
82 ale->next = ale->prev = nullptr;
83 }
84 ANIM_animdata_freelist(&anim_data);
85
86 return ale;
87}
88
90 AnimKeylist *keylist,
91 bAnimListElem *ale)
92{
93 bDopeSheet *ads = nullptr;
95 ads = static_cast<bDopeSheet *>(ac->data);
96 }
97
98 blender::float2 range = {ac->region->v2d.cur.xmin, ac->region->v2d.cur.xmax};
99
100 if (ale->key_data) {
101 switch (ale->datatype) {
102 case ALE_SCE: {
103 Scene *scene = (Scene *)ale->key_data;
104 scene_to_keylist(ads, scene, keylist, 0, range);
105 break;
106 }
107 case ALE_OB: {
108 Object *ob = (Object *)ale->key_data;
109 ob_to_keylist(ads, ob, keylist, 0, range);
110 break;
111 }
112 case ALE_ACTION_LAYERED: {
113 /* This is only called for action summaries in the Dope-sheet, *not* the
114 * Action Editor. Therefore despite the name `ALE_ACTION_LAYERED`, this
115 * is only used to show a *single slot* of the action: the slot used by
116 * the ID the action is listed under.
117 *
118 * Thus we use the same function as the `ALE_ACTION_SLOT` case below
119 * because in practice the only distinction between these cases is where
120 * they get the slot from. In this case, we get it from `elem`'s ADT. */
121 animrig::Action *action = static_cast<animrig::Action *>(ale->key_data);
122 BLI_assert(action);
123 BLI_assert(ale->adt);
125 ac, ale->id, *action, ale->adt->slot_handle, keylist, 0, range);
126 break;
127 }
128 case ALE_ACTION_SLOT: {
129 animrig::Action *action = static_cast<animrig::Action *>(ale->key_data);
130 animrig::Slot *slot = static_cast<animrig::Slot *>(ale->data);
131 BLI_assert(action);
132 BLI_assert(slot);
133 action_slot_summary_to_keylist(ac, ale->id, *action, slot->handle, keylist, 0, range);
134 break;
135 }
136 case ALE_ACT: {
137 /* Legacy action. */
138 bAction *act = (bAction *)ale->key_data;
139 action_to_keylist(ale->adt, act, keylist, 0, range);
140 break;
141 }
142 case ALE_FCURVE: {
143 FCurve *fcu = (FCurve *)ale->key_data;
144 fcurve_to_keylist(ale->adt, fcu, keylist, 0, range, ANIM_nla_mapping_allowed(ale));
145 break;
146 }
147 case ALE_NONE:
148 case ALE_GPFRAME:
149 case ALE_MASKLAY:
150 case ALE_NLASTRIP:
151 case ALE_ALL:
152 case ALE_GROUP:
156 break;
157 }
158 }
159 else if (ale->type == ANIMTYPE_SUMMARY) {
160 /* Dope-sheet summary covers everything. */
161 summary_to_keylist(ac, keylist, 0, range);
162 }
163 else if (ale->type == ANIMTYPE_GROUP) {
164 /* TODO: why don't we just give groups key_data too? */
165 bActionGroup *agrp = (bActionGroup *)ale->data;
166 action_group_to_keylist(ale->adt, agrp, keylist, 0, range);
167 }
168 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
169 /* TODO: why don't we just give grease pencil layers key_data too? */
171 ale->adt, static_cast<const GreasePencilLayer *>(ale->data), keylist, 0);
172 }
173 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER_GROUP) {
174 /* TODO: why don't we just give grease pencil layers key_data too? */
176 ale->adt, static_cast<const GreasePencilLayerTreeGroup *>(ale->data), keylist, 0);
177 }
178 else if (ale->type == ANIMTYPE_GREASE_PENCIL_DATABLOCK) {
179 /* TODO: why don't we just give grease pencil layers key_data too? */
181 ale->adt, static_cast<const GreasePencil *>(ale->data), keylist, 0, false);
182 }
183 else if (ale->type == ANIMTYPE_GPLAYER) {
184 /* TODO: why don't we just give gplayers key_data too? */
185 bGPDlayer *gpl = (bGPDlayer *)ale->data;
186 gpl_to_keylist(ads, gpl, keylist);
187 }
188 else if (ale->type == ANIMTYPE_MASKLAYER) {
189 /* TODO: why don't we just give masklayers key_data too? */
190 MaskLayer *masklay = (MaskLayer *)ale->data;
191 mask_to_keylist(ads, masklay, keylist);
192 }
193}
194
196 bAnimListElem *ale,
197 float region_x,
198 float *r_selx,
199 float *r_frame,
200 bool *r_found,
201 bool *r_is_selected)
202{
203 *r_found = false;
204
205 View2D *v2d = &ac->region->v2d;
206
207 AnimKeylist *keylist = ED_keylist_create();
208 actkeys_list_element_to_keylist(ac, keylist, ale);
210
211 /* standard channel height (to allow for some slop) */
212 float key_hsize = ANIM_UI_get_channel_height() * 0.8f;
213 /* half-size (for either side), but rounded up to nearest int (for easier targeting) */
214 key_hsize = roundf(key_hsize / 2.0f);
215
216 const Bounds<float> range = {
217 UI_view2d_region_to_view_x(v2d, region_x - int(key_hsize)),
218 UI_view2d_region_to_view_x(v2d, region_x + int(key_hsize)),
219 };
220 const ActKeyColumn *ak = ED_keylist_find_any_between(keylist, range);
221 if (ak) {
222
223 /* set the frame to use, and apply inverse-correction for NLA-mapping
224 * so that the frame will get selected by the selection functions without
225 * requiring to map each frame once again...
226 */
228 *r_frame = ak->cfra;
229 *r_found = true;
230 *r_is_selected = (ak->sel & SELECT) != 0;
231 }
232
233 /* cleanup temporary lists */
234 ED_keylist_free(keylist);
235}
236
239 float region_x,
240 float region_y,
241 bAnimListElem **r_ale,
242 float *r_selx,
243 float *r_frame,
244 bool *r_found,
245 bool *r_is_selected)
246
247{
248 *r_found = false;
249 *r_ale = actkeys_find_list_element_at_position(ac, filter, region_x, region_y);
250
251 if (*r_ale != nullptr) {
253 ac, *r_ale, region_x, r_selx, r_frame, r_found, r_is_selected);
254 }
255}
256
257static bool actkeys_is_key_at_position(bAnimContext *ac, float region_x, float region_y)
258{
259 bAnimListElem *ale;
260 float selx, frame;
261 bool found;
262 bool is_selected;
263
267 ac, filter, region_x, region_y, &ale, &selx, &frame, &found, &is_selected);
268
269 if (ale != nullptr) {
270 MEM_freeN(ale);
271 }
272 return found;
273}
274
276
277/* -------------------------------------------------------------------- */
285
286/* Deselects keyframes in the action editor
287 * - This is called by the deselect all operator, as well as other ones!
288 *
289 * - test: check if select or deselect all
290 * - sel: how to select keyframes (SELECT_*)
291 */
293{
294 ListBase anim_data = {nullptr, nullptr};
296
297 KeyframeEditData ked = {{nullptr}};
298 KeyframeEditFunc test_cb, sel_cb;
299
300 /* determine type-based settings */
302
303 /* filter data */
304 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
305
306 /* init BezTriple looping data */
308
309 /* See if we should be selecting or deselecting */
310 if (test) {
311 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
312 if (ale->type == ANIMTYPE_GPLAYER) {
313 if (ED_gpencil_layer_frame_select_check(static_cast<bGPDlayer *>(ale->data))) {
314 sel = SELECT_SUBTRACT;
315 break;
316 }
317 }
318 else if (ale->type == ANIMTYPE_MASKLAYER) {
319 if (ED_masklayer_frame_select_check(static_cast<MaskLayer *>(ale->data))) {
320 sel = SELECT_SUBTRACT;
321 break;
322 }
323 }
324 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
326 static_cast<GreasePencilLayer *>(ale->data)->wrap()))
327 {
328 sel = SELECT_SUBTRACT;
329 }
330 break;
331 }
332 else {
334 &ked, static_cast<FCurve *>(ale->key_data), nullptr, test_cb, nullptr))
335 {
336 sel = SELECT_SUBTRACT;
337 break;
338 }
339 }
340 }
341 }
342
343 /* convert sel to selectmode, and use that to get editor */
344 sel_cb = ANIM_editkeyframes_select(sel);
345
346 /* Now set the flags */
347 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
348 if (ale->type == ANIMTYPE_GPLAYER) {
349 ED_gpencil_layer_frame_select_set(static_cast<bGPDlayer *>(ale->data), sel);
350 ale->update |= ANIM_UPDATE_DEPS;
351 }
352 else if (ale->type == ANIMTYPE_MASKLAYER) {
353 ED_masklayer_frame_select_set(static_cast<MaskLayer *>(ale->data), sel);
354 }
355 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
357 static_cast<GreasePencilLayer *>(ale->data)->wrap(), sel);
358 ale->update |= ANIM_UPDATE_DEPS;
359 }
360 else {
362 &ked, static_cast<FCurve *>(ale->key_data), nullptr, sel_cb, nullptr);
363 }
364 }
365
366 /* Cleanup */
367 ANIM_animdata_update(ac, &anim_data);
368 ANIM_animdata_freelist(&anim_data);
369}
370
371/* ------------------- */
372
374{
375 bAnimContext ac;
376
377 /* get editor data */
378 if (ANIM_animdata_get_context(C, &ac) == 0) {
379 return OPERATOR_CANCELLED;
380 }
381
382 /* 'standard' behavior - check if selected, then apply relevant selection */
383 const int action = RNA_enum_get(op->ptr, "action");
384 switch (action) {
385 case SEL_TOGGLE:
387 break;
388 case SEL_SELECT:
390 break;
391 case SEL_DESELECT:
393 break;
394 case SEL_INVERT:
396 break;
397 default:
398 BLI_assert(0);
399 break;
400 }
401
402 /* set notifier that keyframe selection have changed */
406 }
407 return OPERATOR_FINISHED;
408}
409
411{
412 /* identifiers */
413 ot->name = "Select All";
414 ot->idname = "ACTION_OT_select_all";
415 ot->description = "Toggle selection of all keyframes";
416
417 /* API callbacks. */
420
421 /* flags */
423
424 /* properties */
426}
427
429
430/* -------------------------------------------------------------------- */
440
441/* defines for box_select mode */
442enum {
446} /*eActKeys_BoxSelect_Mode*/;
447
455
456static void box_select_elem(
457 BoxSelectData *sel_data, bAnimListElem *ale, float xmin, float xmax, bool summary)
458{
459 bAnimContext *ac = sel_data->ac;
460
461 switch (ale->type) {
463 GreasePencil *grease_pencil = static_cast<GreasePencil *>(ale->data);
464 for (blender::bke::greasepencil::Layer *layer : grease_pencil->layers_for_write()) {
466 layer->wrap().as_node(), xmin, xmax, sel_data->selectmode);
467 }
468 ale->update |= ANIM_UPDATE_DEPS;
469 break;
470 }
474 static_cast<GreasePencilLayerTreeNode *>(ale->data)->wrap(),
475 xmin,
476 xmax,
477 sel_data->selectmode);
478 ale->update |= ANIM_UPDATE_DEPS;
479 break;
480 case ANIMTYPE_GPLAYER: {
482 static_cast<bGPDlayer *>(ale->data), xmin, xmax, sel_data->selectmode);
483 ale->update |= ANIM_UPDATE_DEPS;
484 break;
485 }
487 Mask *mask = static_cast<Mask *>(ale->data);
488 MaskLayer *masklay;
489 for (masklay = static_cast<MaskLayer *>(mask->masklayers.first); masklay;
490 masklay = masklay->next)
491 {
492 ED_masklayer_frames_select_box(masklay, xmin, xmax, sel_data->selectmode);
493 }
494 break;
495 }
496 case ANIMTYPE_MASKLAYER: {
498 static_cast<MaskLayer *>(ale->data), xmin, xmax, sel_data->selectmode);
499 break;
500 }
501 default: {
502 if (summary) {
503 break;
504 }
505
506 if (ale->type == ANIMTYPE_SUMMARY) {
507 ListBase anim_data = {nullptr, nullptr};
509 ac, &anim_data, ANIMFILTER_DATA_VISIBLE, ac->data, eAnimCont_Types(ac->datatype));
510
511 LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
512 box_select_elem(sel_data, ale2, xmin, xmax, true);
513 }
514
515 ANIM_animdata_update(ac, &anim_data);
516 ANIM_animdata_freelist(&anim_data);
517 }
518
521 &sel_data->ked, ac->ads, ale, sel_data->ok_cb, sel_data->select_cb, nullptr);
522 }
523 }
524 }
525}
526
528 const rcti rect,
529 short mode,
530 const eEditKeyframes_Select selectmode)
531{
532 ListBase anim_data = {nullptr, nullptr};
533 bAnimListElem *ale;
535
536 BoxSelectData sel_data{};
537 sel_data.ac = ac;
538 sel_data.selectmode = selectmode;
539
540 View2D *v2d = &ac->region->v2d;
541 rctf rectf;
542
543 /* Convert mouse coordinates to frame ranges and channel
544 * coordinates corrected for view pan/zoom. */
545 UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin + 2, &rectf.xmin, &rectf.ymin);
546 UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax - 2, &rectf.xmax, &rectf.ymax);
547
548 /* filter data */
550 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
551
552 /* Get beztriple editing/validation functions. */
553 sel_data.select_cb = ANIM_editkeyframes_select(selectmode);
554
557 }
558 else {
559 sel_data.ok_cb = nullptr;
560 }
561
562 /* init editing data */
563 memset(&sel_data.ked, 0, sizeof(KeyframeEditData));
564
565 float ymax = ANIM_UI_get_first_channel_top(v2d);
566 const float channel_step = ANIM_UI_get_channel_step();
567
568 /* loop over data, doing box select */
569 for (ale = static_cast<bAnimListElem *>(anim_data.first); ale;
570 ale = ale->next, ymax -= channel_step)
571 {
572 /* get new vertical minimum extent of channel */
573 float ymin = ymax - channel_step;
574
575 /* set horizontal range (if applicable) */
577 /* if channel is mapped in NLA, apply correction */
578 if (ANIM_nla_mapping_allowed(ale)) {
582 }
583 else {
584 sel_data.ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */
585 sel_data.ked.f1 = rectf.xmin;
586 sel_data.ked.f2 = rectf.xmax;
587 }
588 }
589
590 /* perform vertical suitability check (if applicable) */
591 if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) || !((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
592 box_select_elem(&sel_data, ale, rectf.xmin, rectf.xmax, false);
593 }
594 }
595
596 /* cleanup */
597 ANIM_animdata_update(ac, &anim_data);
598 ANIM_animdata_freelist(&anim_data);
599}
600
601/* ------------------- */
602
604 wmOperator *op,
605 const wmEvent *event)
606{
607 bAnimContext ac;
608 if (ANIM_animdata_get_context(C, &ac) == 0) {
609 return OPERATOR_CANCELLED;
610 }
611
612 bool tweak = RNA_boolean_get(op->ptr, "tweak");
613 if (tweak) {
614 int mval[2];
615 WM_event_drag_start_mval(event, ac.region, mval);
616 if (actkeys_is_key_at_position(&ac, mval[0], mval[1])) {
618 }
619 }
620
621 return WM_gesture_box_invoke(C, op, event);
622}
623
625{
626 bAnimContext ac;
627 rcti rect;
628 short mode = 0;
629
630 /* get editor data */
631 if (ANIM_animdata_get_context(C, &ac) == 0) {
632 return OPERATOR_CANCELLED;
633 }
634
635 const eSelectOp sel_op = eSelectOp(RNA_enum_get(op->ptr, "mode"));
636 const eEditKeyframes_Select selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT;
637 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
639 }
640
641 /* get settings from operator */
643
644 /* selection 'mode' depends on whether box_select region only matters on one axis */
645 if (RNA_boolean_get(op->ptr, "axis_range")) {
646 /* Mode depends on which axis of the range is larger to determine which axis to use:
647 * - checking this in region-space is fine,
648 * as it's fundamentally still going to be a different rect size.
649 * - the frame-range select option is favored over the channel one (x over y),
650 * as frame-range one is often used for tweaking timing when "blocking",
651 * while channels is not that useful...
652 */
653 if (BLI_rcti_size_x(&rect) >= BLI_rcti_size_y(&rect)) {
655 }
656 else {
658 }
659 }
660 else {
662 }
663
664 /* apply box_select action */
665 box_select_action(&ac, rect, mode, selectmode);
666
667 /* set notifier that keyframe selection have changed */
671 }
672 return OPERATOR_FINISHED;
673}
674
676{
677 /* identifiers */
678 ot->name = "Box Select";
679 ot->idname = "ACTION_OT_select_box";
680 ot->description = "Select all keyframes within the specified region";
681
682 /* API callbacks. */
685 ot->modal = WM_gesture_box_modal;
686 ot->cancel = WM_gesture_box_cancel;
687
689
690 /* flags */
691 ot->flag = OPTYPE_UNDO;
692
693 /* rna */
694 ot->prop = RNA_def_boolean(ot->srna, "axis_range", false, "Axis Range", "");
695
696 /* properties */
699
701 ot->srna, "tweak", false, "Tweak", "Operator has been activated using a click-drag event");
703}
704
706
707/* -------------------------------------------------------------------- */
714
723
724static void region_select_elem(RegionSelectData *sel_data, bAnimListElem *ale, bool summary)
725{
726 bAnimContext *ac = sel_data->ac;
727
728 switch (ale->type) {
729 case ANIMTYPE_GPLAYER: {
731 static_cast<bGPDlayer *>(ale->data),
732 sel_data->mode,
733 sel_data->selectmode);
734 ale->update |= ANIM_UPDATE_DEPS;
735 break;
736 }
740 &sel_data->ked,
741 static_cast<GreasePencilLayerTreeNode *>(ale->data)->wrap(),
742 sel_data->mode,
743 sel_data->selectmode);
744 ale->update |= ANIM_UPDATE_DEPS;
745 break;
746 }
748 ListBase anim_data = {nullptr, nullptr};
750 ac, &anim_data, ANIMFILTER_DATA_VISIBLE, ac->data, eAnimCont_Types(ac->datatype));
751
752 LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
753 if ((ale2->type == ANIMTYPE_GREASE_PENCIL_LAYER) && (ale2->id == ale->data)) {
754 region_select_elem(sel_data, ale2, true);
755 }
756 }
757
758 ANIM_animdata_update(ac, &anim_data);
759 ANIM_animdata_freelist(&anim_data);
760 break;
761 }
763 Mask *mask = static_cast<Mask *>(ale->data);
764 MaskLayer *masklay;
765 for (masklay = static_cast<MaskLayer *>(mask->masklayers.first); masklay;
766 masklay = masklay->next)
767 {
769 &sel_data->ked, masklay, sel_data->mode, sel_data->selectmode);
770 }
771 break;
772 }
773 case ANIMTYPE_MASKLAYER: {
775 static_cast<MaskLayer *>(ale->data),
776 sel_data->mode,
777 sel_data->selectmode);
778 break;
779 }
780 default: {
781 if (summary) {
782 break;
783 }
784
785 if (ale->type == ANIMTYPE_SUMMARY) {
786 ListBase anim_data = {nullptr, nullptr};
788 ac, &anim_data, ANIMFILTER_DATA_VISIBLE, ac->data, eAnimCont_Types(ac->datatype));
789
790 LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
791 region_select_elem(sel_data, ale2, true);
792 }
793
794 ANIM_animdata_update(ac, &anim_data);
795 ANIM_animdata_freelist(&anim_data);
796 }
797
800 &sel_data->ked, ac->ads, ale, sel_data->ok_cb, sel_data->select_cb, nullptr);
801 }
802 }
803 }
804}
805
807 const rctf *rectf_view,
808 short mode,
809 eEditKeyframes_Select selectmode,
810 void *data)
811{
812 ListBase anim_data = {nullptr, nullptr};
813 bAnimListElem *ale;
815
816 RegionSelectData sel_data{};
817 sel_data.ac = ac;
818 sel_data.mode = mode;
819 sel_data.selectmode = selectmode;
820 View2D *v2d = &ac->region->v2d;
821 rctf rectf, scaled_rectf;
822
823 /* Convert mouse coordinates to frame ranges and channel
824 * coordinates corrected for view pan/zoom. */
825 UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf);
826
827 /* filter data */
829 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
830
831 /* Get beztriple editing/validation functions. */
832 sel_data.select_cb = ANIM_editkeyframes_select(selectmode);
833 sel_data.ok_cb = ANIM_editkeyframes_ok(mode);
834
835 /* init editing data */
836 memset(&sel_data.ked, 0, sizeof(KeyframeEditData));
837 if (mode == BEZT_OK_CHANNEL_LASSO) {
838 KeyframeEdit_LassoData *data_lasso = static_cast<KeyframeEdit_LassoData *>(data);
839 data_lasso->rectf_scaled = &scaled_rectf;
840 sel_data.ked.data = data_lasso;
841 }
842 else if (mode == BEZT_OK_CHANNEL_CIRCLE) {
843 KeyframeEdit_CircleData *data_circle = static_cast<KeyframeEdit_CircleData *>(data);
844 data_circle->rectf_scaled = &scaled_rectf;
845 sel_data.ked.data = data;
846 }
847 else {
848 sel_data.ked.data = &scaled_rectf;
849 }
850
851 float ymax = ANIM_UI_get_first_channel_top(v2d);
852 const float channel_step = ANIM_UI_get_channel_step();
853
854 /* loop over data, doing region select */
855 for (ale = static_cast<bAnimListElem *>(anim_data.first); ale;
856 ale = ale->next, ymax -= channel_step)
857 {
858 /* get new vertical minimum extent of channel */
859 const float ymin = ymax - channel_step;
860
861 /* compute midpoint of channel (used for testing if the key is in the region or not) */
862 sel_data.ked.channel_y = (ymin + ymax) / 2.0f;
863
864 /* if channel is mapped in NLA, apply correction
865 * - Apply to the bounds being checked, not all the keyframe points,
866 * to avoid having scaling everything
867 * - Save result to the scaled_rect, which is all that these operators
868 * will read from
869 */
870 if (ANIM_nla_mapping_allowed(ale)) {
874 }
875 else {
876 sel_data.ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */
877 sel_data.ked.f1 = rectf.xmin;
878 sel_data.ked.f2 = rectf.xmax;
879 }
880
881 /* Update values for scaled_rectf - which is used to compute the mapping in the callbacks
882 * NOTE: Since summary tracks need late-binding remapping, the callbacks may overwrite these
883 * with the properly remapped ked.f1/f2 values, when needed
884 */
885 scaled_rectf.xmin = sel_data.ked.f1;
886 scaled_rectf.xmax = sel_data.ked.f2;
887 scaled_rectf.ymin = ymin;
888 scaled_rectf.ymax = ymax;
889
890 /* perform vertical suitability check (if applicable) */
891 if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) || !((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
892 region_select_elem(&sel_data, ale, false);
893 }
894 }
895
896 /* cleanup */
897 ANIM_animdata_update(ac, &anim_data);
898 ANIM_animdata_freelist(&anim_data);
899}
900
901/* ----------------------------------- */
902
904{
905 bAnimContext ac;
906
907 KeyframeEdit_LassoData data_lasso;
908 rcti rect;
909 rctf rect_fl;
910
911 /* get editor data */
912 if (ANIM_animdata_get_context(C, &ac) == 0) {
913 return OPERATOR_CANCELLED;
914 }
915
916 data_lasso.rectf_view = &rect_fl;
917 data_lasso.mcoords = WM_gesture_lasso_path_to_array(C, op);
918 if (data_lasso.mcoords.is_empty()) {
919 return OPERATOR_CANCELLED;
920 }
921
922 const eSelectOp sel_op = eSelectOp(RNA_enum_get(op->ptr, "mode"));
923 const eEditKeyframes_Select selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT;
924 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
926 }
927
928 /* get settings from operator */
929 BLI_lasso_boundbox(&rect, data_lasso.mcoords);
930 BLI_rctf_rcti_copy(&rect_fl, &rect);
931
932 /* apply box_select action */
933 region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso);
934
935 /* send notifier that keyframe selection has changed */
939 }
940 return OPERATOR_FINISHED;
941}
942
944{
945 /* identifiers */
946 ot->name = "Lasso Select";
947 ot->description = "Select keyframe points using lasso selection";
948 ot->idname = "ACTION_OT_select_lasso";
949
950 /* API callbacks. */
951 ot->invoke = WM_gesture_lasso_invoke;
952 ot->modal = WM_gesture_lasso_modal;
955 ot->cancel = WM_gesture_lasso_cancel;
956
957 /* flags */
959
960 /* properties */
963}
964
965/* ------------------- */
966
968{
969 bAnimContext ac;
970
971 KeyframeEdit_CircleData data = {nullptr};
972 rctf rect_fl;
973
974 float x = RNA_int_get(op->ptr, "x");
975 float y = RNA_int_get(op->ptr, "y");
976 float radius = RNA_int_get(op->ptr, "radius");
977
978 /* get editor data */
979 if (ANIM_animdata_get_context(C, &ac) == 0) {
980 return OPERATOR_CANCELLED;
981 }
982
983 const eSelectOp sel_op = ED_select_op_modal(
984 eSelectOp(RNA_enum_get(op->ptr, "mode")),
985 WM_gesture_is_modal_first(static_cast<wmGesture *>(op->customdata)));
986 const eEditKeyframes_Select selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT;
987 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
989 }
990
991 data.mval[0] = x;
992 data.mval[1] = y;
993 data.radius_squared = radius * radius;
994 data.rectf_view = &rect_fl;
995
996 rect_fl.xmin = x - radius;
997 rect_fl.xmax = x + radius;
998 rect_fl.ymin = y - radius;
999 rect_fl.ymax = y + radius;
1000
1001 /* apply region select action */
1002 region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_CIRCLE, selectmode, &data);
1003
1004 /* send notifier that keyframe selection has changed */
1008 }
1009 return OPERATOR_FINISHED;
1010}
1011
1013{
1014 ot->name = "Circle Select";
1015 ot->description = "Select keyframe points using circle selection";
1016 ot->idname = "ACTION_OT_select_circle";
1017
1018 ot->invoke = WM_gesture_circle_invoke;
1019 ot->modal = WM_gesture_circle_modal;
1022 ot->cancel = WM_gesture_circle_cancel;
1023 ot->get_name = ED_select_circle_get_name;
1024
1025 /* flags */
1026 ot->flag = OPTYPE_UNDO;
1027
1028 /* properties */
1031}
1032
1034
1035/* -------------------------------------------------------------------- */
1044
1045/* defines for column-select mode */
1047 {ACTKEYS_COLUMNSEL_KEYS, "KEYS", 0, "On Selected Keyframes", ""},
1048 {ACTKEYS_COLUMNSEL_CFRA, "CFRA", 0, "On Current Frame", ""},
1049 {ACTKEYS_COLUMNSEL_MARKERS_COLUMN, "MARKERS_COLUMN", 0, "On Selected Markers", ""},
1051 "MARKERS_BETWEEN",
1052 0,
1053 "Between Min/Max Selected Markers",
1054 ""},
1055 {0, nullptr, 0, nullptr, nullptr},
1056};
1057
1058/* ------------------- */
1059
1060/* Selects all visible keyframes between the specified markers */
1061/* TODO(@ideasman42): this is almost an _exact_ duplicate of a function of the same name in
1062 * `graph_select.cc` should de-duplicate. */
1064{
1065 ListBase anim_data = {nullptr, nullptr};
1067
1068 KeyframeEditFunc ok_cb, select_cb;
1069 KeyframeEditData ked = {{nullptr}};
1070 float min, max;
1071
1072 /* get extreme markers */
1074 min -= 0.5f;
1075 max += 0.5f;
1076
1077 /* Get editing functions + data. */
1080
1081 ked.f1 = min;
1082 ked.f2 = max;
1083
1084 /* filter data */
1086 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1087
1088 /* select keys in-between */
1089 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1090 switch (ale->type) {
1093 static_cast<GreasePencilLayerTreeNode *>(ale->data)->wrap(), min, max, SELECT_ADD);
1094 ale->update |= ANIM_UPDATE_DEPS;
1095 break;
1096 case ANIMTYPE_GPLAYER:
1098 static_cast<bGPDlayer *>(ale->data), min, max, SELECT_ADD);
1099 ale->update |= ANIM_UPDATE_DEPS;
1100 break;
1101
1102 case ANIMTYPE_MASKLAYER:
1103 ED_masklayer_frames_select_box(static_cast<MaskLayer *>(ale->data), min, max, SELECT_ADD);
1104 break;
1105
1106 case ANIMTYPE_FCURVE: {
1107 FCurve *fcurve = static_cast<FCurve *>(ale->key_data);
1108 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcurve, false, true);
1109 ANIM_fcurve_keyframes_loop(&ked, fcurve, ok_cb, select_cb, nullptr);
1110 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcurve, true, true);
1111 break;
1112 }
1113
1114 default:
1115 BLI_assert_msg(false, "Keys cannot be selected into this animation type.");
1116 }
1117 }
1118
1119 /* Cleanup */
1120 ANIM_animdata_update(ac, &anim_data);
1121 ANIM_animdata_freelist(&anim_data);
1122}
1123
1124/* Selects all visible keyframes in the same frames as the specified elements */
1125static void columnselect_action_keys(bAnimContext *ac, short mode)
1126{
1127 ListBase anim_data = {nullptr, nullptr};
1129
1130 Scene *scene = ac->scene;
1131 CfraElem *ce;
1132 KeyframeEditFunc select_cb, ok_cb;
1133 KeyframeEditData ked = {{nullptr}};
1134
1135 /* build list of columns */
1136 switch (mode) {
1137 case ACTKEYS_COLUMNSEL_KEYS: /* list of selected keys */
1138 if (ac->datatype == ANIMCONT_GPENCIL) {
1140 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1141
1142 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1143 switch (ale->type) {
1144 case ANIMTYPE_GPLAYER:
1146 static_cast<bGPDlayer *>(ale->data), &ked.list, true);
1147 break;
1149 blender::ed::greasepencil ::create_keyframe_edit_data_selected_frames_list(
1150 &ked, static_cast<GreasePencilLayer *>(ale->data)->wrap());
1151 break;
1152 default:
1153 /* Invalid channel type. */
1155 }
1156 }
1157 }
1158 else {
1160 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1161
1162 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1163 if (ale->datatype == ALE_GPFRAME) {
1164 ED_gpencil_layer_make_cfra_list(static_cast<bGPDlayer *>(ale->data), &ked.list, true);
1165 }
1166 else {
1167 ked.data = ale;
1169 &ked, static_cast<FCurve *>(ale->key_data), nullptr, bezt_to_cfraelem, nullptr);
1170 }
1171 }
1172 }
1173 ANIM_animdata_freelist(&anim_data);
1174 break;
1175
1176 case ACTKEYS_COLUMNSEL_CFRA: /* current frame */
1177 /* make a single CfraElem for storing this */
1178 ce = MEM_callocN<CfraElem>("cfraElem");
1179 BLI_addtail(&ked.list, ce);
1180
1181 ce->cfra = float(scene->r.cfra);
1182 break;
1183
1184 case ACTKEYS_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */
1185 ED_markers_make_cfra_list(ac->markers, &ked.list, true);
1186 break;
1187
1188 default: /* invalid option */
1189 return;
1190 }
1191
1192 /* set up BezTriple edit callbacks */
1195
1196 /* loop through all of the keys and select additional keyframes
1197 * based on the keys found to be selected above
1198 */
1200 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1201
1202 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1203 /* loop over cfraelems (stored in the KeyframeEditData->list)
1204 * - we need to do this here, as we can apply fewer NLA-mapping conversions
1205 */
1206 LISTBASE_FOREACH (CfraElem *, ce, &ked.list) {
1207 /* set frame for validation callback to refer to */
1209
1210 /* select elements with frame number matching cfraelem */
1211 if (ale->type == ANIMTYPE_GPLAYER) {
1212 ED_gpencil_select_frame(static_cast<bGPDlayer *>(ale->data), ce->cfra, SELECT_ADD);
1213 ale->update |= ANIM_UPDATE_DEPS;
1214 }
1215 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1217 static_cast<GreasePencilLayer *>(ale->data)->wrap(), ce->cfra, SELECT_ADD);
1218 ale->update |= ANIM_UPDATE_DEPS;
1219 }
1220 else if (ale->type == ANIMTYPE_MASKLAYER) {
1221 ED_mask_select_frame(static_cast<MaskLayer *>(ale->data), ce->cfra, SELECT_ADD);
1222 }
1223 else {
1225 &ked, static_cast<FCurve *>(ale->key_data), ok_cb, select_cb, nullptr);
1226 }
1227 }
1228 }
1229
1230 /* free elements */
1231 BLI_freelistN(&ked.list);
1232
1233 ANIM_animdata_update(ac, &anim_data);
1234 ANIM_animdata_freelist(&anim_data);
1235}
1236
1237/* ------------------- */
1238
1240{
1241 bAnimContext ac;
1242 short mode;
1243
1244 /* get editor data */
1245 if (ANIM_animdata_get_context(C, &ac) == 0) {
1246 return OPERATOR_CANCELLED;
1247 }
1248
1249 /* action to take depends on the mode */
1250 mode = RNA_enum_get(op->ptr, "mode");
1251
1254 }
1255 else {
1256 columnselect_action_keys(&ac, mode);
1257 }
1258
1259 /* set notifier that keyframe selection have changed */
1263 }
1264 return OPERATOR_FINISHED;
1265}
1266
1268{
1269 /* identifiers */
1270 ot->name = "Select All";
1271 ot->idname = "ACTION_OT_select_column";
1272 ot->description = "Select all keyframes on the specified frame(s)";
1273
1274 /* API callbacks. */
1277
1278 /* flags */
1279 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1280
1281 /* props */
1282 ot->prop = RNA_def_enum(ot->srna, "mode", prop_column_select_types, 0, "Mode", "");
1284}
1285
1287
1288/* -------------------------------------------------------------------- */
1291
1293{
1294 bAnimContext ac;
1295
1296 ListBase anim_data = {nullptr, nullptr};
1298
1301
1302 /* get editor data */
1303 if (ANIM_animdata_get_context(C, &ac) == 0) {
1304 return OPERATOR_CANCELLED;
1305 }
1306
1307 /* loop through all of the keys and select additional keyframes based on these */
1310 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
1311
1312 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1313 FCurve *fcu = (FCurve *)ale->key_data;
1314
1315 /* check if anything selected? */
1316 if (ANIM_fcurve_keyframes_loop(nullptr, fcu, nullptr, ok_cb, nullptr)) {
1317 /* select every keyframe in this curve then */
1318 ANIM_fcurve_keyframes_loop(nullptr, fcu, nullptr, sel_cb, nullptr);
1319 }
1320 }
1321
1322 /* Cleanup */
1323 ANIM_animdata_freelist(&anim_data);
1324
1325 /* set notifier that keyframe selection has changed */
1329 }
1330 return OPERATOR_FINISHED;
1331}
1332
1334{
1335 /* identifiers */
1336 ot->name = "Select Linked";
1337 ot->idname = "ACTION_OT_select_linked";
1338 ot->description = "Select keyframes occurring in the same F-Curves as selected ones";
1339
1340 /* API callbacks. */
1343
1344 /* flags */
1345 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1346}
1347
1349
1350/* -------------------------------------------------------------------- */
1353
1354/* Common code to perform selection */
1355static void select_moreless_action_keys(bAnimContext *ac, short mode)
1356{
1357 ListBase anim_data = {nullptr, nullptr};
1359
1360 KeyframeEditData ked = {{nullptr}};
1361 KeyframeEditFunc build_cb;
1362
1363 /* init selmap building data */
1364 build_cb = ANIM_editkeyframes_buildselmap(mode);
1365
1366 /* loop through all of the keys and select additional keyframes based on these */
1369 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1370
1371 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1372
1373 /* TODO: other types. */
1374 if (ale->datatype != ALE_FCURVE) {
1375 continue;
1376 }
1377
1378 /* only continue if F-Curve has keyframes */
1379 FCurve *fcu = (FCurve *)ale->key_data;
1380 if (fcu->bezt == nullptr) {
1381 continue;
1382 }
1383
1384 /* build up map of whether F-Curve's keyframes should be selected or not */
1385 ked.data = MEM_callocN(fcu->totvert, "selmap actEdit more");
1386 ANIM_fcurve_keyframes_loop(&ked, fcu, nullptr, build_cb, nullptr);
1387
1388 /* based on this map, adjust the selection status of the keyframes */
1389 ANIM_fcurve_keyframes_loop(&ked, fcu, nullptr, bezt_selmap_flush, nullptr);
1390
1391 /* free the selmap used here */
1392 MEM_freeN(ked.data);
1393 ked.data = nullptr;
1394 }
1395
1396 /* Cleanup */
1397 ANIM_animdata_freelist(&anim_data);
1398}
1399
1400/* ----------------- */
1401
1403{
1404 bAnimContext ac;
1405
1406 /* get editor data */
1407 if (ANIM_animdata_get_context(C, &ac) == 0) {
1408 return OPERATOR_CANCELLED;
1409 }
1410
1411 /* perform select changes */
1413
1414 /* set notifier that keyframe selection has changed */
1418 }
1419 return OPERATOR_FINISHED;
1420}
1421
1423{
1424 /* identifiers */
1425 ot->name = "Select More";
1426 ot->idname = "ACTION_OT_select_more";
1427 ot->description = "Select keyframes beside already selected ones";
1428
1429 /* API callbacks. */
1432
1433 /* flags */
1434 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1435}
1436
1437/* ----------------- */
1438
1440{
1441 bAnimContext ac;
1442
1443 /* get editor data */
1444 if (ANIM_animdata_get_context(C, &ac) == 0) {
1445 return OPERATOR_CANCELLED;
1446 }
1447
1448 /* perform select changes */
1450
1451 /* set notifier that keyframe selection has changed */
1455 }
1456 return OPERATOR_FINISHED;
1457}
1458
1460{
1461 /* identifiers */
1462 ot->name = "Select Less";
1463 ot->idname = "ACTION_OT_select_less";
1464 ot->description = "Deselect keyframes on ends of selection islands";
1465
1466 /* API callbacks. */
1469
1470 /* flags */
1471 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1472}
1473
1475
1476/* -------------------------------------------------------------------- */
1481
1482/* defines for left-right select tool */
1484 {ACTKEYS_LRSEL_TEST, "CHECK", 0, "Check if Select Left or Right", ""},
1485 {ACTKEYS_LRSEL_LEFT, "LEFT", 0, "Before Current Frame", ""},
1486 {ACTKEYS_LRSEL_RIGHT, "RIGHT", 0, "After Current Frame", ""},
1487 {0, nullptr, 0, nullptr, nullptr},
1488};
1489
1490/* --------------------------------- */
1491
1493 short leftright,
1494 eEditKeyframes_Select select_mode)
1495{
1496 ListBase anim_data = {nullptr, nullptr};
1498
1499 KeyframeEditFunc ok_cb, select_cb;
1500 KeyframeEditData ked = {{nullptr}};
1501 Scene *scene = ac->scene;
1502
1503 /* if select mode is replace, deselect all keyframes (and channels) first */
1504 if (select_mode == SELECT_REPLACE) {
1505 select_mode = SELECT_ADD;
1506
1507 /* - deselect all other keyframes, so that just the newly selected remain
1508 * - channels aren't deselected, since we don't re-select any as a consequence
1509 */
1511 }
1512
1513 /* set callbacks and editing data */
1515 select_cb = ANIM_editkeyframes_select(select_mode);
1516
1517 if (leftright == ACTKEYS_LRSEL_LEFT) {
1518 ked.f1 = MINAFRAMEF;
1519 ked.f2 = float(scene->r.cfra + 0.1f);
1520 }
1521 else {
1522 ked.f1 = float(scene->r.cfra - 0.1f);
1523 ked.f2 = MAXFRAMEF;
1524 }
1525
1526 /* filter data */
1528 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1529
1530 /* select keys */
1531 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1532 switch (ale->type) {
1535 static_cast<GreasePencilLayerTreeNode *>(ale->data)->wrap(),
1536 ked.f1,
1537 ked.f2,
1538 select_mode);
1539 ale->update |= ANIM_UPDATE_DEPS;
1540 break;
1541 case ANIMTYPE_GPLAYER:
1543 static_cast<bGPDlayer *>(ale->data), ked.f1, ked.f2, select_mode);
1544 ale->update |= ANIM_UPDATE_DEPS;
1545 break;
1546
1547 case ANIMTYPE_MASKLAYER:
1549 static_cast<MaskLayer *>(ale->data), ked.f1, ked.f2, select_mode);
1550 break;
1551
1552 case ANIMTYPE_FCURVE: {
1553 FCurve *fcurve = static_cast<FCurve *>(ale->key_data);
1554 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcurve, false, true);
1555 ANIM_fcurve_keyframes_loop(&ked, fcurve, ok_cb, select_cb, nullptr);
1556 ANIM_nla_mapping_apply_if_needed_fcurve(ale, fcurve, true, true);
1557 break;
1558 }
1559
1560 default:
1561 BLI_assert_msg(false, "Keys cannot be selected into this animation type.");
1562 }
1563 }
1564
1565 /* Sync marker support */
1566 if (select_mode == SELECT_ADD) {
1567 SpaceAction *saction = (SpaceAction *)ac->sl;
1568
1569 if (saction && ac->markers && (saction->flag & SACTION_MARKERS_MOVE)) {
1570 LISTBASE_FOREACH (TimeMarker *, marker, ac->markers) {
1571 if (((leftright == ACTKEYS_LRSEL_LEFT) && (marker->frame < scene->r.cfra)) ||
1572 ((leftright == ACTKEYS_LRSEL_RIGHT) && (marker->frame >= scene->r.cfra)))
1573 {
1574 marker->flag |= SELECT;
1575 }
1576 else {
1577 marker->flag &= ~SELECT;
1578 }
1579 }
1580 }
1581 }
1582
1583 /* Cleanup */
1584 ANIM_animdata_update(ac, &anim_data);
1585 ANIM_animdata_freelist(&anim_data);
1586}
1587
1588/* ----------------- */
1589
1591{
1592 bAnimContext ac;
1593 short leftright = RNA_enum_get(op->ptr, "mode");
1594 eEditKeyframes_Select selectmode;
1595
1596 /* get editor data */
1597 if (ANIM_animdata_get_context(C, &ac) == 0) {
1598 return OPERATOR_CANCELLED;
1599 }
1600
1601 /* select mode is either replace (deselect all, then add) or add/extend */
1602 if (RNA_boolean_get(op->ptr, "extend")) {
1603 selectmode = SELECT_INVERT;
1604 }
1605 else {
1606 selectmode = SELECT_REPLACE;
1607 }
1608
1609 /* if "test" mode is set, we don't have any info to set this with */
1610 if (leftright == ACTKEYS_LRSEL_TEST) {
1611 return OPERATOR_CANCELLED;
1612 }
1613
1614 /* do the selecting now */
1615 actkeys_select_leftright(&ac, leftright, selectmode);
1616
1617 /* set notifier that keyframe selection (and channels too) have changed */
1620
1621 return OPERATOR_FINISHED;
1622}
1623
1625 wmOperator *op,
1626 const wmEvent *event)
1627{
1628 bAnimContext ac;
1629 short leftright = RNA_enum_get(op->ptr, "mode");
1630
1631 /* get editor data */
1632 if (ANIM_animdata_get_context(C, &ac) == 0) {
1633 return OPERATOR_CANCELLED;
1634 }
1635
1636 /* handle mode-based testing */
1637 if (leftright == ACTKEYS_LRSEL_TEST) {
1638 Scene *scene = ac.scene;
1639 ARegion *region = ac.region;
1640 View2D *v2d = &region->v2d;
1641 float x;
1642
1643 /* determine which side of the current frame mouse is on */
1644 x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
1645 if (x < scene->r.cfra) {
1646 RNA_enum_set(op->ptr, "mode", ACTKEYS_LRSEL_LEFT);
1647 }
1648 else {
1649 RNA_enum_set(op->ptr, "mode", ACTKEYS_LRSEL_RIGHT);
1650 }
1651 }
1652
1653 /* perform selection */
1654 return actkeys_select_leftright_exec(C, op);
1655}
1656
1658{
1659 PropertyRNA *prop;
1660
1661 /* identifiers */
1662 ot->name = "Select Left/Right";
1663 ot->idname = "ACTION_OT_select_leftright";
1664 ot->description = "Select keyframes to the left or the right of the current frame";
1665
1666 /* API callbacks. */
1670
1671 /* flags */
1672 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1673
1674 /* properties */
1675 ot->prop = RNA_def_enum(
1676 ot->srna, "mode", prop_actkeys_leftright_select_types, ACTKEYS_LRSEL_TEST, "Mode", "");
1678
1679 prop = RNA_def_boolean(ot->srna, "extend", false, "Extend Select", "");
1681}
1682
1684
1685/* -------------------------------------------------------------------- */
1697
1698/* option 1) select keyframe directly under mouse */
1700 bAnimListElem *ale,
1701 const eEditKeyframes_Select select_mode,
1702 float selx)
1703{
1704 KeyframeEditData ked = {{nullptr}};
1705 KeyframeEditFunc select_cb, ok_cb;
1706
1707 /* get functions for selecting keyframes */
1708 select_cb = ANIM_editkeyframes_select(select_mode);
1710 ked.f1 = selx;
1712
1713 /* select the nominated keyframe on the given frame */
1714 if (ale->type == ANIMTYPE_GPLAYER) {
1715 ED_gpencil_select_frame(static_cast<bGPDlayer *>(ale->data), selx, select_mode);
1716 ale->update |= ANIM_UPDATE_DEPS;
1717 }
1718 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1720 static_cast<GreasePencilLayer *>(ale->data)->wrap(), selx, select_mode);
1721 ale->update |= ANIM_UPDATE_DEPS;
1722 }
1723 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER_GROUP) {
1725 static_cast<GreasePencilLayerTreeGroup *>(ale->data)->wrap(), selx, select_mode);
1726 }
1727 else if (ale->type == ANIMTYPE_GREASE_PENCIL_DATABLOCK) {
1728 ListBase anim_data = {nullptr, nullptr};
1730
1732 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1733
1734 /* Loop over all keys that are represented by this data-block key. */
1735 LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
1736 if ((ale2->type != ANIMTYPE_GREASE_PENCIL_LAYER) || (ale2->id != ale->data)) {
1737 continue;
1738 }
1740 static_cast<GreasePencilLayer *>(ale2->data)->wrap(), selx, select_mode);
1741 ale2->update |= ANIM_UPDATE_DEPS;
1742 }
1743 }
1744 else if (ale->type == ANIMTYPE_MASKLAYER) {
1745 ED_mask_select_frame(static_cast<MaskLayer *>(ale->data), selx, select_mode);
1746 }
1747 else {
1748 if (ale->type == ANIMTYPE_SUMMARY && ale->datatype == ALE_ALL) {
1749 ListBase anim_data = {nullptr, nullptr};
1751
1753 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1754
1755 /* Loop over all keys that are represented by this summary key. */
1756 LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
1757 switch (ale2->type) {
1758 case ANIMTYPE_GPLAYER:
1759 ED_gpencil_select_frame(static_cast<bGPDlayer *>(ale2->data), selx, select_mode);
1760 ale2->update |= ANIM_UPDATE_DEPS;
1761 break;
1762
1763 case ANIMTYPE_MASKLAYER:
1764 ED_mask_select_frame(static_cast<MaskLayer *>(ale2->data), selx, select_mode);
1765 break;
1766
1769 static_cast<GreasePencilLayer *>(ale2->data)->wrap(), selx, select_mode);
1770 ale2->update |= ANIM_UPDATE_DEPS;
1771 break;
1772
1773 default:
1774 break;
1775 }
1776 }
1777
1778 ANIM_animdata_update(ac, &anim_data);
1779 ANIM_animdata_freelist(&anim_data);
1780 }
1781
1783 ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, nullptr);
1784 }
1785 }
1786}
1787
1788/* Option 2) Selects all the keyframes on either side of the current frame
1789 * (depends on which side the mouse is on) */
1790/* (see actkeys_select_leftright) */
1791
1792/* Option 3) Selects all visible keyframes in the same frame as the mouse click */
1793static void actkeys_mselect_column(bAnimContext *ac, eEditKeyframes_Select select_mode, float selx)
1794{
1795 ListBase anim_data = {nullptr, nullptr};
1797
1798 KeyframeEditFunc select_cb, ok_cb;
1799 KeyframeEditData ked = {{nullptr}};
1800
1801 /* set up BezTriple edit callbacks */
1802 select_cb = ANIM_editkeyframes_select(select_mode);
1804
1805 /* loop through all of the keys and select additional keyframes
1806 * based on the keys found to be selected above
1807 */
1809 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1810
1811 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1812 /* select elements with frame number matching cfra */
1813 if (ale->type == ANIMTYPE_GPLAYER) {
1814 ED_gpencil_select_frame(static_cast<bGPDlayer *>(ale->data), selx, select_mode);
1815 ale->update |= ANIM_UPDATE_DEPS;
1816 }
1817 else if (ale->type == ANIMTYPE_MASKLAYER) {
1818 ED_mask_select_frame(static_cast<MaskLayer *>(ale->data), selx, select_mode);
1819 }
1820 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1822 static_cast<GreasePencilLayer *>(ale->data)->wrap(), selx, select_mode);
1823 ale->update |= ANIM_UPDATE_DEPS;
1824 }
1825 else {
1826 /* set frame for validation callback to refer to */
1828
1830 &ked, static_cast<FCurve *>(ale->key_data), ok_cb, select_cb, nullptr);
1831 }
1832 }
1833
1834 /* free elements */
1835 BLI_freelistN(&ked.list);
1836
1837 ANIM_animdata_update(ac, &anim_data);
1838 ANIM_animdata_freelist(&anim_data);
1839}
1840
1841/* option 4) select all keyframes in same channel */
1843 bAnimListElem *ale,
1844 eEditKeyframes_Select select_mode)
1845{
1846 KeyframeEditFunc select_cb;
1847
1848 /* get functions for selecting keyframes */
1849 select_cb = ANIM_editkeyframes_select(select_mode);
1850
1851 /* select all keyframes in this channel */
1852 if (ale->type == ANIMTYPE_GPLAYER) {
1853 ED_gpencil_select_frames(static_cast<bGPDlayer *>(ale->data), select_mode);
1854 ale->update = ANIM_UPDATE_DEPS;
1855 }
1856 else if (ale->type == ANIMTYPE_MASKLAYER) {
1857 ED_mask_select_frames(static_cast<MaskLayer *>(ale->data), select_mode);
1858 }
1859 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1861 static_cast<GreasePencilLayer *>(ale->data)->wrap(), select_mode);
1862 ale->update |= ANIM_UPDATE_DEPS;
1863 }
1864 else {
1865 if (ale->type == ANIMTYPE_SUMMARY && ale->datatype == ALE_ALL) {
1866 ListBase anim_data = {nullptr, nullptr};
1868
1870 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1871
1872 LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
1873 if (ale2->type == ANIMTYPE_GPLAYER) {
1874 ED_gpencil_select_frames(static_cast<bGPDlayer *>(ale2->data), select_mode);
1875 ale2->update |= ANIM_UPDATE_DEPS;
1876 }
1877 else if (ale2->type == ANIMTYPE_MASKLAYER) {
1878 ED_mask_select_frames(static_cast<MaskLayer *>(ale2->data), select_mode);
1879 }
1880 }
1881
1882 ANIM_animdata_update(ac, &anim_data);
1883 ANIM_animdata_freelist(&anim_data);
1884 }
1885
1887 ANIM_animchannel_keyframes_loop(nullptr, ac->ads, ale, nullptr, select_cb, nullptr);
1888 }
1889 }
1890}
1891
1892/* ------------------- */
1893
1895 const int mval[2],
1896 eEditKeyframes_Select select_mode,
1897 const bool deselect_all,
1898 const bool column,
1899 const bool same_channel,
1900 bool wait_to_deselect_others)
1901{
1902 /* NOTE: keep this functionality in sync with #MARKER_OT_select.
1903 * The logic here closely matches its internals.
1904 * From a user perspective the functions should also behave in much the same way. */
1905
1908
1909 bAnimListElem *ale = nullptr;
1910 bool found = false;
1911 bool is_selected = false;
1912 float frame = 0.0f; /* frame of keyframe under mouse - NLA corrections not applied/included */
1913 float selx = 0.0f; /* frame of keyframe under mouse */
1915
1917 ac, filter, mval[0], mval[1], &ale, &selx, &frame, &found, &is_selected);
1918
1919 if (select_mode != SELECT_REPLACE) {
1920 wait_to_deselect_others = false;
1921 }
1922
1923 /* For replacing selection, if we have something to select, we have to clear existing selection.
1924 * The same goes if we found nothing to select, and deselect_all is true
1925 * (deselect on nothing behavior). */
1926 if ((select_mode == SELECT_REPLACE && found) || (!found && deselect_all)) {
1927 /* reset selection mode for next steps */
1928 select_mode = SELECT_ADD;
1929
1930 /* Rather than deselecting others, users may want to drag to box-select (drag from empty space)
1931 * or tweak-translate an already selected item. If these cases may apply, delay deselection. */
1932 if (wait_to_deselect_others && (!found || is_selected)) {
1933 ret_value = OPERATOR_RUNNING_MODAL;
1934 }
1935 else {
1936 /* deselect all keyframes */
1938
1939 /* highlight channel clicked on */
1941 /* deselect all other channels first */
1943
1944 /* Highlight Action-Group or F-Curve? */
1945 if (ale != nullptr && ale->data) {
1946 if (ale->type == ANIMTYPE_GROUP) {
1947 bActionGroup *agrp = static_cast<bActionGroup *>(ale->data);
1948
1949 agrp->flag |= AGRP_SELECTED;
1951 ac, ac->data, eAnimCont_Types(ac->datatype), filter, agrp, ANIMTYPE_GROUP);
1952 }
1953 else if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
1954 FCurve *fcu = static_cast<FCurve *>(ale->data);
1955
1956 fcu->flag |= FCURVE_SELECTED;
1958 ac->data,
1960 filter,
1961 fcu,
1962 eAnim_ChannelType(ale->type));
1963 }
1964 else if (ale->type == ANIMTYPE_GPLAYER) {
1965 bGPdata *gpd = (bGPdata *)ale->id;
1966 bGPDlayer *gpl = static_cast<bGPDlayer *>(ale->data);
1967
1969 }
1970 else if (ale->type == ANIMTYPE_ACTION_SLOT) {
1972 "fcurve_owner_id of an Action Slot should be an Action");
1973 animrig::Action *action = reinterpret_cast<animrig::Action *>(ale->fcurve_owner_id);
1974 animrig::Slot *slot = static_cast<animrig::Slot *>(ale->data);
1975 slot->set_selected(true);
1976 action->slot_active_set(slot->handle);
1977 }
1978 }
1979 }
1980 else if (ac->datatype == ANIMCONT_GPENCIL) {
1981 /* Deselect all other channels first. */
1983
1984 /* Highlight the grease pencil channel, and set the corresponding layer as active. */
1985 if (ale != nullptr && ale->data != nullptr && ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1987 *reinterpret_cast<GreasePencil *>(ale->id),
1988 static_cast<blender::bke::greasepencil::Layer *>(ale->data));
1989 }
1990
1991 /* Highlight GPencil Layer (Legacy). */
1992 if (ale != nullptr && ale->data != nullptr && ale->type == ANIMTYPE_GPLAYER) {
1993 bGPdata *gpd = (bGPdata *)ale->id;
1994 bGPDlayer *gpl = static_cast<bGPDlayer *>(ale->data);
1995
1997 }
1998 }
1999 else if (ac->datatype == ANIMCONT_MASK) {
2000 /* deselect all other channels first */
2002
2003 if (ale != nullptr && ale->data != nullptr && ale->type == ANIMTYPE_MASKLAYER) {
2004 MaskLayer *masklay = static_cast<MaskLayer *>(ale->data);
2005
2006 masklay->flag |= MASK_LAYERFLAG_SELECT;
2007 }
2008 }
2009 }
2010 }
2011
2012 /* only select keyframes if we clicked on a valid channel and hit something */
2013 if (ale != nullptr) {
2014 if (found) {
2015 /* apply selection to keyframes */
2016 if (column) {
2017 /* select all keyframes in the same frame as the one we hit on the active channel
2018 * [#41077]: "frame" not "selx" here (i.e. no NLA corrections yet) as the code here
2019 * does that itself again as it needs to work on multiple data-blocks.
2020 */
2021 actkeys_mselect_column(ac, select_mode, frame);
2022 }
2023 else if (same_channel) {
2024 /* select all keyframes in the active channel */
2025 actkeys_mselect_channel_only(ac, ale, select_mode);
2026 }
2027 else {
2028 /* select the nominated keyframe on the given frame */
2029 actkeys_mselect_single(ac, ale, select_mode, selx);
2030 }
2031 }
2032
2033 /* flush tagged updates
2034 * NOTE: We temporarily add this channel back to the list so that this can happen
2035 */
2036 ListBase anim_data = {ale, ale};
2037 ANIM_animdata_update(ac, &anim_data);
2038
2039 /* free this channel */
2040 MEM_freeN(ale);
2041 }
2042
2043 return ret_value;
2044}
2045
2046/* handle clicking */
2048{
2049 bAnimContext ac;
2050 wmOperatorStatus ret_value;
2051
2052 /* get editor data */
2053 if (ANIM_animdata_get_context(C, &ac) == 0) {
2054 return OPERATOR_CANCELLED;
2055 }
2056
2057 /* get useful pointers from animation context data */
2058 // region = ac.region; /* UNUSED. */
2059
2060 /* select mode is either replace (deselect all, then add) or add/extend */
2061 const eEditKeyframes_Select selectmode = RNA_boolean_get(op->ptr, "extend") ? SELECT_INVERT :
2063 const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
2064 const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
2065 int mval[2];
2066
2067 /* column selection */
2068 const bool column = RNA_boolean_get(op->ptr, "column");
2069 const bool channel = RNA_boolean_get(op->ptr, "channel");
2070
2071 mval[0] = RNA_int_get(op->ptr, "mouse_x");
2072 mval[1] = RNA_int_get(op->ptr, "mouse_y");
2073
2074 /* Select keyframe(s) based upon mouse position. */
2075 ret_value = mouse_action_keys(
2076 &ac, mval, selectmode, deselect_all, column, channel, wait_to_deselect_others);
2077
2078 /* set notifier that keyframe selection (and channels too) have changed */
2081
2082 /* for tweak grab to work */
2083 return ret_value | OPERATOR_PASS_THROUGH;
2084}
2085
2087{
2088 PropertyRNA *prop;
2089
2090 /* identifiers */
2091 ot->name = "Select Keyframes";
2092 ot->idname = "ACTION_OT_clickselect";
2093 ot->description = "Select keyframes by clicking on them";
2094
2095 /* callbacks */
2098 ot->invoke = WM_generic_select_invoke;
2099 ot->modal = WM_generic_select_modal;
2100
2101 /* flags */
2102 ot->flag = OPTYPE_UNDO;
2103
2104 /* properties */
2106 /* Key-map: Enable with `Shift`. */
2107 prop = RNA_def_boolean(
2108 ot->srna,
2109 "extend",
2110 false,
2111 "Extend Select",
2112 "Toggle keyframe selection instead of leaving newly selected keyframes only");
2114
2115 prop = RNA_def_boolean(ot->srna,
2116 "deselect_all",
2117 false,
2118 "Deselect On Nothing",
2119 "Deselect all when nothing under the cursor");
2121
2122 /* Key-map: Enable with `Alt`. */
2123 prop = RNA_def_boolean(
2124 ot->srna,
2125 "column",
2126 false,
2127 "Column Select",
2128 "Select all keyframes that occur on the same frame as the one under the mouse");
2130
2131 /* Key-map: Enable with `Ctrl-Alt`. */
2132 prop = RNA_def_boolean(ot->srna,
2133 "channel",
2134 false,
2135 "Only Channel",
2136 "Select all the keyframes in the channel under the mouse");
2138}
2139
Low-level operations for grease pencil.
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:549
#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)
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
#define SEL_OP_USE_PRE_DESELECT(sel_op)
std::string ED_select_circle_get_name(wmOperatorType *ot, PointerRNA *ptr)
Read Guarded memory(de)allocation.
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
#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:1621
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:1668
float UI_view2d_region_to_view_x(const View2D *v2d, float x)
Definition view2d.cc:1657
void UI_view2d_region_to_view_rctf(const View2D *v2d, const rctf *rect_src, rctf *rect_dst) ATTR_NONNULL()
Definition view2d.cc:1675
#define NC_ANIMATION
Definition WM_types.hh:388
@ OPTYPE_DEPENDS_ON_CURSOR
Definition WM_types.hh:218
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define ND_KEYFRAME
Definition WM_types.hh:494
#define ND_ANIMCHAN
Definition WM_types.hh:496
#define NA_SELECTED
Definition WM_types.hh:589
@ 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:401
bool ANIM_nla_mapping_allowed(const bAnimListElem *ale)
Definition anim_draw.cc:274
float ANIM_nla_tweakedit_remap(bAnimListElem *ale, const float cframe, const eNlaTime_ConvertModes mode)
Definition anim_draw.cc:324
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)
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)
nullptr float
#define SELECT
#define roundf(x)
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 GS(x)
#define filter
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[258]
Definition DNA_ID.h:432
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:763
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:4237
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)