Blender V4.3
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
9#include <cfloat>
10#include <cmath>
11#include <cstdlib>
12#include <cstring>
13
14#include "MEM_guardedalloc.h"
15
16#include "BLI_blenlib.h"
17#include "BLI_dlrbTree.h"
18#include "BLI_lasso_2d.hh"
19#include "BLI_utildefines.h"
20
21#include "DNA_anim_types.h"
23#include "DNA_mask_types.h"
24#include "DNA_object_types.h"
25#include "DNA_scene_types.h"
26
27#include "RNA_access.hh"
28#include "RNA_define.hh"
29
30#include "BKE_context.hh"
31#include "BKE_fcurve.hh"
32#include "BKE_gpencil_legacy.h"
33#include "BKE_grease_pencil.hh"
34#include "BKE_nla.hh"
35
36#include "UI_interface.hh"
37#include "UI_view2d.hh"
38
39#include "ED_anim_api.hh"
40#include "ED_gpencil_legacy.hh"
41#include "ED_grease_pencil.hh"
42#include "ED_keyframes_edit.hh"
44#include "ED_markers.hh"
45#include "ED_mask.hh"
46#include "ED_screen.hh"
47#include "ED_select_utils.hh"
48
49#include "WM_api.hh"
50#include "WM_types.hh"
51
52#include "action_intern.hh"
53
54using namespace blender;
55
56/* -------------------------------------------------------------------- */
61 eAnimFilter_Flags filter,
62 float region_x,
63 float region_y)
64{
65 View2D *v2d = &ac->region->v2d;
66
67 float view_x, view_y;
68 int channel_index;
69 UI_view2d_region_to_view(v2d, region_x, region_y, &view_x, &view_y);
72 0,
74 view_x,
75 view_y,
76 nullptr,
77 &channel_index);
78
79 ListBase anim_data = {nullptr, nullptr};
80 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
81
82 bAnimListElem *ale = static_cast<bAnimListElem *>(BLI_findlink(&anim_data, channel_index));
83 if (ale != nullptr) {
84 BLI_remlink(&anim_data, ale);
85 ale->next = ale->prev = nullptr;
86 }
87 ANIM_animdata_freelist(&anim_data);
88
89 return ale;
90}
91
93 AnimKeylist *keylist,
94 bAnimListElem *ale)
95{
96 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
97
98 bDopeSheet *ads = nullptr;
100 ads = static_cast<bDopeSheet *>(ac->data);
101 }
102
103 blender::float2 range = {ac->region->v2d.cur.xmin, ac->region->v2d.cur.xmax};
104
105 if (ale->key_data) {
106 switch (ale->datatype) {
107 case ALE_SCE: {
108 Scene *scene = (Scene *)ale->key_data;
109 scene_to_keylist(ads, scene, keylist, 0, range);
110 break;
111 }
112 case ALE_OB: {
113 Object *ob = (Object *)ale->key_data;
114 ob_to_keylist(ads, ob, keylist, 0, range);
115 break;
116 }
117 case ALE_ACTION_LAYERED: {
118 bAction *action = (bAction *)ale->key_data;
119 action_to_keylist(adt, action, keylist, 0, range);
120 break;
121 }
122 case ALE_ACTION_SLOT: {
123 animrig::Action *action = static_cast<animrig::Action *>(ale->key_data);
124 animrig::Slot *slot = static_cast<animrig::Slot *>(ale->data);
125 BLI_assert(action);
126 BLI_assert(slot);
127 action_slot_to_keylist(adt, *action, slot->handle, keylist, 0, range);
128 break;
129 }
130 case ALE_ACT: {
131 bAction *act = (bAction *)ale->key_data;
132 action_to_keylist(adt, act, keylist, 0, range);
133 break;
134 }
135 case ALE_FCURVE: {
136 FCurve *fcu = (FCurve *)ale->key_data;
137 fcurve_to_keylist(adt, fcu, keylist, 0, range);
138 break;
139 }
140 case ALE_NONE:
141 case ALE_GPFRAME:
142 case ALE_MASKLAY:
143 case ALE_NLASTRIP:
144 case ALE_ALL:
145 case ALE_GROUP:
149 break;
150 }
151 }
152 else if (ale->type == ANIMTYPE_SUMMARY) {
153 /* dopesheet summary covers everything */
154 summary_to_keylist(ac, keylist, 0, range);
155 }
156 else if (ale->type == ANIMTYPE_GROUP) {
157 /* TODO: why don't we just give groups key_data too? */
158 bActionGroup *agrp = (bActionGroup *)ale->data;
159 action_group_to_keylist(adt, agrp, keylist, 0, range);
160 }
161 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
162 /* TODO: why don't we just give grease pencil layers key_data too? */
164 adt, static_cast<const GreasePencilLayer *>(ale->data), keylist, 0);
165 }
166 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER_GROUP) {
167 /* TODO: why don't we just give grease pencil layers key_data too? */
169 adt, static_cast<const GreasePencilLayerTreeGroup *>(ale->data), keylist, 0);
170 }
171 else if (ale->type == ANIMTYPE_GREASE_PENCIL_DATABLOCK) {
172 /* TODO: why don't we just give grease pencil layers key_data too? */
174 adt, static_cast<const GreasePencil *>(ale->data), keylist, 0, false);
175 }
176 else if (ale->type == ANIMTYPE_GPLAYER) {
177 /* TODO: why don't we just give gplayers key_data too? */
178 bGPDlayer *gpl = (bGPDlayer *)ale->data;
179 gpl_to_keylist(ads, gpl, keylist);
180 }
181 else if (ale->type == ANIMTYPE_MASKLAYER) {
182 /* TODO: why don't we just give masklayers key_data too? */
183 MaskLayer *masklay = (MaskLayer *)ale->data;
184 mask_to_keylist(ads, masklay, keylist);
185 }
186}
187
189 bAnimListElem *ale,
190 float region_x,
191 float *r_selx,
192 float *r_frame,
193 bool *r_found,
194 bool *r_is_selected)
195{
196 *r_found = false;
197
198 View2D *v2d = &ac->region->v2d;
199
200 AnimKeylist *keylist = ED_keylist_create();
201 actkeys_list_element_to_keylist(ac, keylist, ale);
203
204 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
205
206 /* standard channel height (to allow for some slop) */
207 float key_hsize = ANIM_UI_get_channel_height() * 0.8f;
208 /* half-size (for either side), but rounded up to nearest int (for easier targeting) */
209 key_hsize = roundf(key_hsize / 2.0f);
210
211 const Range2f range = {
212 UI_view2d_region_to_view_x(v2d, region_x - int(key_hsize)),
213 UI_view2d_region_to_view_x(v2d, region_x + int(key_hsize)),
214 };
215 const ActKeyColumn *ak = ED_keylist_find_any_between(keylist, range);
216 if (ak) {
217
218 /* set the frame to use, and apply inverse-correction for NLA-mapping
219 * so that the frame will get selected by the selection functions without
220 * requiring to map each frame once again...
221 */
223 *r_frame = ak->cfra;
224 *r_found = true;
225 *r_is_selected = (ak->sel & SELECT) != 0;
226 }
227
228 /* cleanup temporary lists */
229 ED_keylist_free(keylist);
230}
231
233 eAnimFilter_Flags filter,
234 float region_x,
235 float region_y,
236 bAnimListElem **r_ale,
237 float *r_selx,
238 float *r_frame,
239 bool *r_found,
240 bool *r_is_selected)
241
242{
243 *r_found = false;
244 *r_ale = actkeys_find_list_element_at_position(ac, filter, region_x, region_y);
245
246 if (*r_ale != nullptr) {
248 ac, *r_ale, region_x, r_selx, r_frame, r_found, r_is_selected);
249 }
250}
251
252static bool actkeys_is_key_at_position(bAnimContext *ac, float region_x, float region_y)
253{
254 bAnimListElem *ale;
255 float selx, frame;
256 bool found;
257 bool is_selected;
258
262 ac, filter, region_x, region_y, &ale, &selx, &frame, &found, &is_selected);
263
264 if (ale != nullptr) {
265 MEM_freeN(ale);
266 }
267 return found;
268}
269
272/* -------------------------------------------------------------------- */
281/* Deselects keyframes in the action editor
282 * - This is called by the deselect all operator, as well as other ones!
283 *
284 * - test: check if select or deselect all
285 * - sel: how to select keyframes (SELECT_*)
286 */
288{
289 ListBase anim_data = {nullptr, nullptr};
291
292 KeyframeEditData ked = {{nullptr}};
293 KeyframeEditFunc test_cb, sel_cb;
294
295 /* determine type-based settings */
297
298 /* filter data */
299 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
300
301 /* init BezTriple looping data */
303
304 /* See if we should be selecting or deselecting */
305 if (test) {
306 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
307 if (ale->type == ANIMTYPE_GPLAYER) {
308 if (ED_gpencil_layer_frame_select_check(static_cast<bGPDlayer *>(ale->data))) {
309 sel = SELECT_SUBTRACT;
310 break;
311 }
312 }
313 else if (ale->type == ANIMTYPE_MASKLAYER) {
314 if (ED_masklayer_frame_select_check(static_cast<MaskLayer *>(ale->data))) {
315 sel = SELECT_SUBTRACT;
316 break;
317 }
318 }
319 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
321 static_cast<GreasePencilLayer *>(ale->data)->wrap()))
322 {
323 sel = SELECT_SUBTRACT;
324 }
325 break;
326 }
327 else {
329 &ked, static_cast<FCurve *>(ale->key_data), nullptr, test_cb, nullptr))
330 {
331 sel = SELECT_SUBTRACT;
332 break;
333 }
334 }
335 }
336 }
337
338 /* convert sel to selectmode, and use that to get editor */
339 sel_cb = ANIM_editkeyframes_select(sel);
340
341 /* Now set the flags */
342 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
343 if (ale->type == ANIMTYPE_GPLAYER) {
344 ED_gpencil_layer_frame_select_set(static_cast<bGPDlayer *>(ale->data), sel);
345 ale->update |= ANIM_UPDATE_DEPS;
346 }
347 else if (ale->type == ANIMTYPE_MASKLAYER) {
348 ED_masklayer_frame_select_set(static_cast<MaskLayer *>(ale->data), sel);
349 }
350 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
352 static_cast<GreasePencilLayer *>(ale->data)->wrap(), sel);
353 ale->update |= ANIM_UPDATE_DEPS;
354 }
355 else {
357 &ked, static_cast<FCurve *>(ale->key_data), nullptr, sel_cb, nullptr);
358 }
359 }
360
361 /* Cleanup */
362 ANIM_animdata_update(ac, &anim_data);
363 ANIM_animdata_freelist(&anim_data);
364}
365
366/* ------------------- */
367
369{
370 bAnimContext ac;
371
372 /* get editor data */
373 if (ANIM_animdata_get_context(C, &ac) == 0) {
374 return OPERATOR_CANCELLED;
375 }
376
377 /* 'standard' behavior - check if selected, then apply relevant selection */
378 const int action = RNA_enum_get(op->ptr, "action");
379 switch (action) {
380 case SEL_TOGGLE:
382 break;
383 case SEL_SELECT:
385 break;
386 case SEL_DESELECT:
388 break;
389 case SEL_INVERT:
391 break;
392 default:
393 BLI_assert(0);
394 break;
395 }
396
397 /* set notifier that keyframe selection have changed */
401 }
402 return OPERATOR_FINISHED;
403}
404
406{
407 /* identifiers */
408 ot->name = "Select All";
409 ot->idname = "ACTION_OT_select_all";
410 ot->description = "Toggle selection of all keyframes";
411
412 /* api callbacks */
415
416 /* flags */
418
419 /* properties */
421}
422
425/* -------------------------------------------------------------------- */
436/* defines for box_select mode */
437enum {
441} /*eActKeys_BoxSelect_Mode*/;
442
450
451static void box_select_elem(
452 BoxSelectData *sel_data, bAnimListElem *ale, float xmin, float xmax, bool summary)
453{
454 bAnimContext *ac = sel_data->ac;
455
456 switch (ale->type) {
457#if 0 /* XXX: Keyframes are not currently shown here */
459 bGPdata *gpd = ale->data;
460 bGPDlayer *gpl;
461 for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
462 ED_gpencil_layer_frames_select_box(gpl, xmin, xmax, data->selectmode);
463 }
464 ale->update |= ANIM_UPDATE_DEPS;
465 break;
466 }
467#endif
469 GreasePencil *grease_pencil = static_cast<GreasePencil *>(ale->data);
470 for (blender::bke::greasepencil::Layer *layer : grease_pencil->layers_for_write()) {
472 layer->wrap().as_node(), xmin, xmax, sel_data->selectmode);
473 }
474 ale->update |= ANIM_UPDATE_DEPS;
475 break;
476 }
480 static_cast<GreasePencilLayerTreeNode *>(ale->data)->wrap(),
481 xmin,
482 xmax,
483 sel_data->selectmode);
484 ale->update |= ANIM_UPDATE_DEPS;
485 break;
486 case ANIMTYPE_GPLAYER: {
488 static_cast<bGPDlayer *>(ale->data), xmin, xmax, sel_data->selectmode);
489 ale->update |= ANIM_UPDATE_DEPS;
490 break;
491 }
493 Mask *mask = static_cast<Mask *>(ale->data);
494 MaskLayer *masklay;
495 for (masklay = static_cast<MaskLayer *>(mask->masklayers.first); masklay;
496 masklay = masklay->next)
497 {
498 ED_masklayer_frames_select_box(masklay, xmin, xmax, sel_data->selectmode);
499 }
500 break;
501 }
502 case ANIMTYPE_MASKLAYER: {
504 static_cast<MaskLayer *>(ale->data), xmin, xmax, sel_data->selectmode);
505 break;
506 }
507 default: {
508 if (summary) {
509 break;
510 }
511
512 if (ale->type == ANIMTYPE_SUMMARY) {
513 ListBase anim_data = {nullptr, nullptr};
515 ac, &anim_data, ANIMFILTER_DATA_VISIBLE, ac->data, eAnimCont_Types(ac->datatype));
516
517 LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
518 box_select_elem(sel_data, ale2, xmin, xmax, true);
519 }
520
521 ANIM_animdata_update(ac, &anim_data);
522 ANIM_animdata_freelist(&anim_data);
523 }
524
527 &sel_data->ked, ac->ads, ale, sel_data->ok_cb, sel_data->select_cb, nullptr);
528 }
529 }
530 }
531}
532
534 const rcti rect,
535 short mode,
536 const eEditKeyframes_Select selectmode)
537{
538 ListBase anim_data = {nullptr, nullptr};
539 bAnimListElem *ale;
541
542 BoxSelectData sel_data{};
543 sel_data.ac = ac;
544 sel_data.selectmode = selectmode;
545
546 View2D *v2d = &ac->region->v2d;
547 rctf rectf;
548
549 /* Convert mouse coordinates to frame ranges and channel
550 * coordinates corrected for view pan/zoom. */
551 UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin + 2, &rectf.xmin, &rectf.ymin);
552 UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax - 2, &rectf.xmax, &rectf.ymax);
553
554 /* filter data */
556 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
557
558 /* Get beztriple editing/validation functions. */
559 sel_data.select_cb = ANIM_editkeyframes_select(selectmode);
560
563 }
564 else {
565 sel_data.ok_cb = nullptr;
566 }
567
568 /* init editing data */
569 memset(&sel_data.ked, 0, sizeof(KeyframeEditData));
570
571 float ymax = ANIM_UI_get_first_channel_top(v2d);
572 const float channel_step = ANIM_UI_get_channel_step();
573
574 /* loop over data, doing box select */
575 for (ale = static_cast<bAnimListElem *>(anim_data.first); ale;
576 ale = ale->next, ymax -= channel_step)
577 {
578 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
579
580 /* get new vertical minimum extent of channel */
581 float ymin = ymax - channel_step;
582
583 /* set horizontal range (if applicable) */
585 /* if channel is mapped in NLA, apply correction */
586 if (adt) {
587 sel_data.ked.iterflags &= ~(KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP);
588 sel_data.ked.f1 = BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP);
589 sel_data.ked.f2 = BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP);
590 }
591 else {
592 sel_data.ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */
593 sel_data.ked.f1 = rectf.xmin;
594 sel_data.ked.f2 = rectf.xmax;
595 }
596 }
597
598 /* perform vertical suitability check (if applicable) */
599 if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) || !((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
600 box_select_elem(&sel_data, ale, rectf.xmin, rectf.xmax, false);
601 }
602 }
603
604 /* cleanup */
605 ANIM_animdata_update(ac, &anim_data);
606 ANIM_animdata_freelist(&anim_data);
607}
608
609/* ------------------- */
610
611static int actkeys_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
612{
613 bAnimContext ac;
614 if (ANIM_animdata_get_context(C, &ac) == 0) {
615 return OPERATOR_CANCELLED;
616 }
617
618 bool tweak = RNA_boolean_get(op->ptr, "tweak");
619 if (tweak) {
620 int mval[2];
621 WM_event_drag_start_mval(event, ac.region, mval);
622 if (actkeys_is_key_at_position(&ac, mval[0], mval[1])) {
624 }
625 }
626
627 return WM_gesture_box_invoke(C, op, event);
628}
629
631{
632 bAnimContext ac;
633 rcti rect;
634 short mode = 0;
635
636 /* get editor data */
637 if (ANIM_animdata_get_context(C, &ac) == 0) {
638 return OPERATOR_CANCELLED;
639 }
640
641 const eSelectOp sel_op = eSelectOp(RNA_enum_get(op->ptr, "mode"));
642 const eEditKeyframes_Select selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT;
643 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
645 }
646
647 /* get settings from operator */
649
650 /* selection 'mode' depends on whether box_select region only matters on one axis */
651 if (RNA_boolean_get(op->ptr, "axis_range")) {
652 /* Mode depends on which axis of the range is larger to determine which axis to use:
653 * - checking this in region-space is fine,
654 * as it's fundamentally still going to be a different rect size.
655 * - the frame-range select option is favored over the channel one (x over y),
656 * as frame-range one is often used for tweaking timing when "blocking",
657 * while channels is not that useful...
658 */
659 if (BLI_rcti_size_x(&rect) >= BLI_rcti_size_y(&rect)) {
661 }
662 else {
664 }
665 }
666 else {
668 }
669
670 /* apply box_select action */
671 box_select_action(&ac, rect, mode, selectmode);
672
673 /* set notifier that keyframe selection have changed */
677 }
678 return OPERATOR_FINISHED;
679}
680
682{
683 /* identifiers */
684 ot->name = "Box Select";
685 ot->idname = "ACTION_OT_select_box";
686 ot->description = "Select all keyframes within the specified region";
687
688 /* api callbacks */
693
695
696 /* flags */
698
699 /* rna */
700 ot->prop = RNA_def_boolean(ot->srna, "axis_range", false, "Axis Range", "");
701
702 /* properties */
705
707 ot->srna, "tweak", false, "Tweak", "Operator has been activated using a click-drag event");
709}
710
713/* -------------------------------------------------------------------- */
729
730static void region_select_elem(RegionSelectData *sel_data, bAnimListElem *ale, bool summary)
731{
732 bAnimContext *ac = sel_data->ac;
733
734 switch (ale->type) {
735#if 0 /* XXX: Keyframes are not currently shown here */
737 bGPdata *gpd = ale->data;
738 bGPDlayer *gpl;
739 for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
741 &rdata->ked, ale->data, rdata->mode, rdata->selectmode);
742 }
743 break;
744 }
745#endif
746 case ANIMTYPE_GPLAYER: {
748 static_cast<bGPDlayer *>(ale->data),
749 sel_data->mode,
750 sel_data->selectmode);
751 ale->update |= ANIM_UPDATE_DEPS;
752 break;
753 }
757 &sel_data->ked,
758 static_cast<GreasePencilLayerTreeNode *>(ale->data)->wrap(),
759 sel_data->mode,
760 sel_data->selectmode);
761 ale->update |= ANIM_UPDATE_DEPS;
762 break;
763 }
765 ListBase anim_data = {nullptr, nullptr};
767 ac, &anim_data, ANIMFILTER_DATA_VISIBLE, ac->data, eAnimCont_Types(ac->datatype));
768
769 LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
770 if ((ale2->type == ANIMTYPE_GREASE_PENCIL_LAYER) && (ale2->id == ale->data)) {
771 region_select_elem(sel_data, ale2, true);
772 }
773 }
774
775 ANIM_animdata_update(ac, &anim_data);
776 ANIM_animdata_freelist(&anim_data);
777 break;
778 }
780 Mask *mask = static_cast<Mask *>(ale->data);
781 MaskLayer *masklay;
782 for (masklay = static_cast<MaskLayer *>(mask->masklayers.first); masklay;
783 masklay = masklay->next)
784 {
786 &sel_data->ked, masklay, sel_data->mode, sel_data->selectmode);
787 }
788 break;
789 }
790 case ANIMTYPE_MASKLAYER: {
792 static_cast<MaskLayer *>(ale->data),
793 sel_data->mode,
794 sel_data->selectmode);
795 break;
796 }
797 default: {
798 if (summary) {
799 break;
800 }
801
802 if (ale->type == ANIMTYPE_SUMMARY) {
803 ListBase anim_data = {nullptr, nullptr};
805 ac, &anim_data, ANIMFILTER_DATA_VISIBLE, ac->data, eAnimCont_Types(ac->datatype));
806
807 LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
808 region_select_elem(sel_data, ale2, true);
809 }
810
811 ANIM_animdata_update(ac, &anim_data);
812 ANIM_animdata_freelist(&anim_data);
813 }
814
817 &sel_data->ked, ac->ads, ale, sel_data->ok_cb, sel_data->select_cb, nullptr);
818 }
819 }
820 }
821}
822
824 const rctf *rectf_view,
825 short mode,
826 eEditKeyframes_Select selectmode,
827 void *data)
828{
829 ListBase anim_data = {nullptr, nullptr};
830 bAnimListElem *ale;
832
833 RegionSelectData sel_data{};
834 sel_data.ac = ac;
835 sel_data.mode = mode;
836 sel_data.selectmode = selectmode;
837 View2D *v2d = &ac->region->v2d;
838 rctf rectf, scaled_rectf;
839
840 /* Convert mouse coordinates to frame ranges and channel
841 * coordinates corrected for view pan/zoom. */
842 UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf);
843
844 /* filter data */
846 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
847
848 /* Get beztriple editing/validation functions. */
849 sel_data.select_cb = ANIM_editkeyframes_select(selectmode);
850 sel_data.ok_cb = ANIM_editkeyframes_ok(mode);
851
852 /* init editing data */
853 memset(&sel_data.ked, 0, sizeof(KeyframeEditData));
854 if (mode == BEZT_OK_CHANNEL_LASSO) {
855 KeyframeEdit_LassoData *data_lasso = static_cast<KeyframeEdit_LassoData *>(data);
856 data_lasso->rectf_scaled = &scaled_rectf;
857 sel_data.ked.data = data_lasso;
858 }
859 else if (mode == BEZT_OK_CHANNEL_CIRCLE) {
860 KeyframeEdit_CircleData *data_circle = static_cast<KeyframeEdit_CircleData *>(data);
861 data_circle->rectf_scaled = &scaled_rectf;
862 sel_data.ked.data = data;
863 }
864 else {
865 sel_data.ked.data = &scaled_rectf;
866 }
867
868 float ymax = ANIM_UI_get_first_channel_top(v2d);
869 const float channel_step = ANIM_UI_get_channel_step();
870
871 /* loop over data, doing region select */
872 for (ale = static_cast<bAnimListElem *>(anim_data.first); ale;
873 ale = ale->next, ymax -= channel_step)
874 {
875 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
876
877 /* get new vertical minimum extent of channel */
878 const float ymin = ymax - channel_step;
879
880 /* compute midpoint of channel (used for testing if the key is in the region or not) */
881 sel_data.ked.channel_y = (ymin + ymax) / 2.0f;
882
883 /* if channel is mapped in NLA, apply correction
884 * - Apply to the bounds being checked, not all the keyframe points,
885 * to avoid having scaling everything
886 * - Save result to the scaled_rect, which is all that these operators
887 * will read from
888 */
889 if (adt) {
890 sel_data.ked.iterflags &= ~(KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP);
891 sel_data.ked.f1 = BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP);
892 sel_data.ked.f2 = BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP);
893 }
894 else {
895 sel_data.ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */
896 sel_data.ked.f1 = rectf.xmin;
897 sel_data.ked.f2 = rectf.xmax;
898 }
899
900 /* Update values for scaled_rectf - which is used to compute the mapping in the callbacks
901 * NOTE: Since summary tracks need late-binding remapping, the callbacks may overwrite these
902 * with the properly remapped ked.f1/f2 values, when needed
903 */
904 scaled_rectf.xmin = sel_data.ked.f1;
905 scaled_rectf.xmax = sel_data.ked.f2;
906 scaled_rectf.ymin = ymin;
907 scaled_rectf.ymax = ymax;
908
909 /* perform vertical suitability check (if applicable) */
910 if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) || !((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
911 region_select_elem(&sel_data, ale, false);
912 }
913 }
914
915 /* cleanup */
916 ANIM_animdata_update(ac, &anim_data);
917 ANIM_animdata_freelist(&anim_data);
918}
919
920/* ----------------------------------- */
921
923{
924 bAnimContext ac;
925
926 KeyframeEdit_LassoData data_lasso;
927 rcti rect;
928 rctf rect_fl;
929
930 /* get editor data */
931 if (ANIM_animdata_get_context(C, &ac) == 0) {
932 return OPERATOR_CANCELLED;
933 }
934
935 data_lasso.rectf_view = &rect_fl;
936 data_lasso.mcoords = WM_gesture_lasso_path_to_array(C, op);
937 if (data_lasso.mcoords.is_empty()) {
938 return OPERATOR_CANCELLED;
939 }
940
941 const eSelectOp sel_op = eSelectOp(RNA_enum_get(op->ptr, "mode"));
942 const eEditKeyframes_Select selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT;
943 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
945 }
946
947 /* get settings from operator */
948 BLI_lasso_boundbox(&rect, data_lasso.mcoords);
949 BLI_rctf_rcti_copy(&rect_fl, &rect);
950
951 /* apply box_select action */
952 region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso);
953
954 /* send notifier that keyframe selection has changed */
958 }
959 return OPERATOR_FINISHED;
960}
961
963{
964 /* identifiers */
965 ot->name = "Lasso Select";
966 ot->description = "Select keyframe points using lasso selection";
967 ot->idname = "ACTION_OT_select_lasso";
968
969 /* api callbacks */
975
976 /* flags */
978
979 /* properties */
982}
983
984/* ------------------- */
985
987{
988 bAnimContext ac;
989
990 KeyframeEdit_CircleData data = {nullptr};
991 rctf rect_fl;
992
993 float x = RNA_int_get(op->ptr, "x");
994 float y = RNA_int_get(op->ptr, "y");
995 float radius = RNA_int_get(op->ptr, "radius");
996
997 /* get editor data */
998 if (ANIM_animdata_get_context(C, &ac) == 0) {
999 return OPERATOR_CANCELLED;
1000 }
1001
1002 const eSelectOp sel_op = ED_select_op_modal(
1003 eSelectOp(RNA_enum_get(op->ptr, "mode")),
1004 WM_gesture_is_modal_first(static_cast<wmGesture *>(op->customdata)));
1005 const eEditKeyframes_Select selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT;
1006 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
1008 }
1009
1010 data.mval[0] = x;
1011 data.mval[1] = y;
1012 data.radius_squared = radius * radius;
1013 data.rectf_view = &rect_fl;
1014
1015 rect_fl.xmin = x - radius;
1016 rect_fl.xmax = x + radius;
1017 rect_fl.ymin = y - radius;
1018 rect_fl.ymax = y + radius;
1019
1020 /* apply region select action */
1021 region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_CIRCLE, selectmode, &data);
1022
1023 /* send notifier that keyframe selection has changed */
1027 }
1028 return OPERATOR_FINISHED;
1029}
1030
1032{
1033 ot->name = "Circle Select";
1034 ot->description = "Select keyframe points using circle selection";
1035 ot->idname = "ACTION_OT_select_circle";
1036
1043
1044 /* flags */
1045 ot->flag = OPTYPE_UNDO;
1046
1047 /* properties */
1050}
1051
1054/* -------------------------------------------------------------------- */
1064/* defines for column-select mode */
1066 {ACTKEYS_COLUMNSEL_KEYS, "KEYS", 0, "On Selected Keyframes", ""},
1067 {ACTKEYS_COLUMNSEL_CFRA, "CFRA", 0, "On Current Frame", ""},
1068 {ACTKEYS_COLUMNSEL_MARKERS_COLUMN, "MARKERS_COLUMN", 0, "On Selected Markers", ""},
1070 "MARKERS_BETWEEN",
1071 0,
1072 "Between Min/Max Selected Markers",
1073 ""},
1074 {0, nullptr, 0, nullptr, nullptr},
1075};
1076
1077/* ------------------- */
1078
1079/* Selects all visible keyframes between the specified markers */
1080/* TODO(@ideasman42): this is almost an _exact_ duplicate of a function of the same name in
1081 * `graph_select.cc` should de-duplicate. */
1083{
1084 ListBase anim_data = {nullptr, nullptr};
1086
1087 KeyframeEditFunc ok_cb, select_cb;
1088 KeyframeEditData ked = {{nullptr}};
1089 float min, max;
1090
1091 /* get extreme markers */
1092 ED_markers_get_minmax(ac->markers, 1, &min, &max);
1093 min -= 0.5f;
1094 max += 0.5f;
1095
1096 /* Get editing functions + data. */
1099
1100 ked.f1 = min;
1101 ked.f2 = max;
1102
1103 /* filter data */
1105 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1106
1107 /* select keys in-between */
1108 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1109 switch (ale->type) {
1112 static_cast<GreasePencilLayerTreeNode *>(ale->data)->wrap(), min, max, SELECT_ADD);
1113 ale->update |= ANIM_UPDATE_DEPS;
1114 break;
1115 case ANIMTYPE_GPLAYER:
1117 static_cast<bGPDlayer *>(ale->data), min, max, SELECT_ADD);
1118 ale->update |= ANIM_UPDATE_DEPS;
1119 break;
1120
1121 case ANIMTYPE_MASKLAYER:
1122 ED_masklayer_frames_select_box(static_cast<MaskLayer *>(ale->data), min, max, SELECT_ADD);
1123 break;
1124
1125 case ANIMTYPE_FCURVE: {
1126 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
1127 FCurve *fcurve = static_cast<FCurve *>(ale->key_data);
1128 if (adt) {
1129 ANIM_nla_mapping_apply_fcurve(adt, fcurve, false, true);
1130 ANIM_fcurve_keyframes_loop(&ked, fcurve, ok_cb, select_cb, nullptr);
1131 ANIM_nla_mapping_apply_fcurve(adt, fcurve, true, true);
1132 }
1133 else {
1134 ANIM_fcurve_keyframes_loop(&ked, fcurve, ok_cb, select_cb, nullptr);
1135 }
1136 break;
1137 }
1138
1139 default:
1140 BLI_assert_msg(false, "Keys cannot be selected into this animation type.");
1141 }
1142 }
1143
1144 /* Cleanup */
1145 ANIM_animdata_update(ac, &anim_data);
1146 ANIM_animdata_freelist(&anim_data);
1147}
1148
1149/* Selects all visible keyframes in the same frames as the specified elements */
1150static void columnselect_action_keys(bAnimContext *ac, short mode)
1151{
1152 ListBase anim_data = {nullptr, nullptr};
1154
1155 Scene *scene = ac->scene;
1156 CfraElem *ce;
1157 KeyframeEditFunc select_cb, ok_cb;
1158 KeyframeEditData ked = {{nullptr}};
1159
1160 /* build list of columns */
1161 switch (mode) {
1162 case ACTKEYS_COLUMNSEL_KEYS: /* list of selected keys */
1163 if (ac->datatype == ANIMCONT_GPENCIL) {
1165 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1166
1167 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1168 switch (ale->type) {
1169 case ANIMTYPE_GPLAYER:
1171 static_cast<bGPDlayer *>(ale->data), &ked.list, true);
1172 break;
1174 blender::ed::greasepencil ::create_keyframe_edit_data_selected_frames_list(
1175 &ked, static_cast<GreasePencilLayer *>(ale->data)->wrap());
1176 break;
1177 default:
1178 /* Invalid channel type. */
1180 }
1181 }
1182 }
1183 else {
1185 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1186
1187 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1188 if (ale->datatype == ALE_GPFRAME) {
1189 ED_gpencil_layer_make_cfra_list(static_cast<bGPDlayer *>(ale->data), &ked.list, true);
1190 }
1191 else {
1193 &ked, static_cast<FCurve *>(ale->key_data), nullptr, bezt_to_cfraelem, nullptr);
1194 }
1195 }
1196 }
1197 ANIM_animdata_freelist(&anim_data);
1198 break;
1199
1200 case ACTKEYS_COLUMNSEL_CFRA: /* current frame */
1201 /* make a single CfraElem for storing this */
1202 ce = MEM_cnew<CfraElem>("cfraElem");
1203 BLI_addtail(&ked.list, ce);
1204
1205 ce->cfra = float(scene->r.cfra);
1206 break;
1207
1208 case ACTKEYS_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */
1209 ED_markers_make_cfra_list(ac->markers, &ked.list, true);
1210 break;
1211
1212 default: /* invalid option */
1213 return;
1214 }
1215
1216 /* set up BezTriple edit callbacks */
1219
1220 /* loop through all of the keys and select additional keyframes
1221 * based on the keys found to be selected above
1222 */
1224 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1225
1226 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1227 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
1228
1229 /* loop over cfraelems (stored in the KeyframeEditData->list)
1230 * - we need to do this here, as we can apply fewer NLA-mapping conversions
1231 */
1232 LISTBASE_FOREACH (CfraElem *, ce, &ked.list) {
1233 /* set frame for validation callback to refer to */
1234 if (adt) {
1236 }
1237 else {
1238 ked.f1 = ce->cfra;
1239 }
1240
1241 /* select elements with frame number matching cfraelem */
1242 if (ale->type == ANIMTYPE_GPLAYER) {
1243 ED_gpencil_select_frame(static_cast<bGPDlayer *>(ale->data), ce->cfra, SELECT_ADD);
1244 ale->update |= ANIM_UPDATE_DEPS;
1245 }
1246 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1248 static_cast<GreasePencilLayer *>(ale->data)->wrap(), ce->cfra, SELECT_ADD);
1249 ale->update |= ANIM_UPDATE_DEPS;
1250 }
1251 else if (ale->type == ANIMTYPE_MASKLAYER) {
1252 ED_mask_select_frame(static_cast<MaskLayer *>(ale->data), ce->cfra, SELECT_ADD);
1253 }
1254 else {
1256 &ked, static_cast<FCurve *>(ale->key_data), ok_cb, select_cb, nullptr);
1257 }
1258 }
1259 }
1260
1261 /* free elements */
1262 BLI_freelistN(&ked.list);
1263
1264 ANIM_animdata_update(ac, &anim_data);
1265 ANIM_animdata_freelist(&anim_data);
1266}
1267
1268/* ------------------- */
1269
1271{
1272 bAnimContext ac;
1273 short mode;
1274
1275 /* get editor data */
1276 if (ANIM_animdata_get_context(C, &ac) == 0) {
1277 return OPERATOR_CANCELLED;
1278 }
1279
1280 /* action to take depends on the mode */
1281 mode = RNA_enum_get(op->ptr, "mode");
1282
1285 }
1286 else {
1287 columnselect_action_keys(&ac, mode);
1288 }
1289
1290 /* set notifier that keyframe selection have changed */
1294 }
1295 return OPERATOR_FINISHED;
1296}
1297
1299{
1300 /* identifiers */
1301 ot->name = "Select All";
1302 ot->idname = "ACTION_OT_select_column";
1303 ot->description = "Select all keyframes on the specified frame(s)";
1304
1305 /* api callbacks */
1308
1309 /* flags */
1311
1312 /* props */
1313 ot->prop = RNA_def_enum(ot->srna, "mode", prop_column_select_types, 0, "Mode", "");
1315}
1316
1319/* -------------------------------------------------------------------- */
1324{
1325 bAnimContext ac;
1326
1327 ListBase anim_data = {nullptr, nullptr};
1329
1332
1333 /* get editor data */
1334 if (ANIM_animdata_get_context(C, &ac) == 0) {
1335 return OPERATOR_CANCELLED;
1336 }
1337
1338 /* loop through all of the keys and select additional keyframes based on these */
1341 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
1342
1343 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1344 FCurve *fcu = (FCurve *)ale->key_data;
1345
1346 /* check if anything selected? */
1347 if (ANIM_fcurve_keyframes_loop(nullptr, fcu, nullptr, ok_cb, nullptr)) {
1348 /* select every keyframe in this curve then */
1349 ANIM_fcurve_keyframes_loop(nullptr, fcu, nullptr, sel_cb, nullptr);
1350 }
1351 }
1352
1353 /* Cleanup */
1354 ANIM_animdata_freelist(&anim_data);
1355
1356 /* set notifier that keyframe selection has changed */
1360 }
1361 return OPERATOR_FINISHED;
1362}
1363
1365{
1366 /* identifiers */
1367 ot->name = "Select Linked";
1368 ot->idname = "ACTION_OT_select_linked";
1369 ot->description = "Select keyframes occurring in the same F-Curves as selected ones";
1370
1371 /* api callbacks */
1374
1375 /* flags */
1377}
1378
1381/* -------------------------------------------------------------------- */
1385/* Common code to perform selection */
1386static void select_moreless_action_keys(bAnimContext *ac, short mode)
1387{
1388 ListBase anim_data = {nullptr, nullptr};
1390
1391 KeyframeEditData ked = {{nullptr}};
1392 KeyframeEditFunc build_cb;
1393
1394 /* init selmap building data */
1395 build_cb = ANIM_editkeyframes_buildselmap(mode);
1396
1397 /* loop through all of the keys and select additional keyframes based on these */
1400 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1401
1402 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1403
1404 /* TODO: other types. */
1405 if (ale->datatype != ALE_FCURVE) {
1406 continue;
1407 }
1408
1409 /* only continue if F-Curve has keyframes */
1410 FCurve *fcu = (FCurve *)ale->key_data;
1411 if (fcu->bezt == nullptr) {
1412 continue;
1413 }
1414
1415 /* build up map of whether F-Curve's keyframes should be selected or not */
1416 ked.data = MEM_callocN(fcu->totvert, "selmap actEdit more");
1417 ANIM_fcurve_keyframes_loop(&ked, fcu, nullptr, build_cb, nullptr);
1418
1419 /* based on this map, adjust the selection status of the keyframes */
1420 ANIM_fcurve_keyframes_loop(&ked, fcu, nullptr, bezt_selmap_flush, nullptr);
1421
1422 /* free the selmap used here */
1423 MEM_freeN(ked.data);
1424 ked.data = nullptr;
1425 }
1426
1427 /* Cleanup */
1428 ANIM_animdata_freelist(&anim_data);
1429}
1430
1431/* ----------------- */
1432
1434{
1435 bAnimContext ac;
1436
1437 /* get editor data */
1438 if (ANIM_animdata_get_context(C, &ac) == 0) {
1439 return OPERATOR_CANCELLED;
1440 }
1441
1442 /* perform select changes */
1444
1445 /* set notifier that keyframe selection has changed */
1449 }
1450 return OPERATOR_FINISHED;
1451}
1452
1454{
1455 /* identifiers */
1456 ot->name = "Select More";
1457 ot->idname = "ACTION_OT_select_more";
1458 ot->description = "Select keyframes beside already selected ones";
1459
1460 /* api callbacks */
1463
1464 /* flags */
1466}
1467
1468/* ----------------- */
1469
1471{
1472 bAnimContext ac;
1473
1474 /* get editor data */
1475 if (ANIM_animdata_get_context(C, &ac) == 0) {
1476 return OPERATOR_CANCELLED;
1477 }
1478
1479 /* perform select changes */
1481
1482 /* set notifier that keyframe selection has changed */
1486 }
1487 return OPERATOR_FINISHED;
1488}
1489
1491{
1492 /* identifiers */
1493 ot->name = "Select Less";
1494 ot->idname = "ACTION_OT_select_less";
1495 ot->description = "Deselect keyframes on ends of selection islands";
1496
1497 /* api callbacks */
1500
1501 /* flags */
1503}
1504
1507/* -------------------------------------------------------------------- */
1513/* defines for left-right select tool */
1515 {ACTKEYS_LRSEL_TEST, "CHECK", 0, "Check if Select Left or Right", ""},
1516 {ACTKEYS_LRSEL_LEFT, "LEFT", 0, "Before Current Frame", ""},
1517 {ACTKEYS_LRSEL_RIGHT, "RIGHT", 0, "After Current Frame", ""},
1518 {0, nullptr, 0, nullptr, nullptr},
1519};
1520
1521/* --------------------------------- */
1522
1524 short leftright,
1525 eEditKeyframes_Select select_mode)
1526{
1527 ListBase anim_data = {nullptr, nullptr};
1529
1530 KeyframeEditFunc ok_cb, select_cb;
1531 KeyframeEditData ked = {{nullptr}};
1532 Scene *scene = ac->scene;
1533
1534 /* if select mode is replace, deselect all keyframes (and channels) first */
1535 if (select_mode == SELECT_REPLACE) {
1536 select_mode = SELECT_ADD;
1537
1538 /* - deselect all other keyframes, so that just the newly selected remain
1539 * - channels aren't deselected, since we don't re-select any as a consequence
1540 */
1542 }
1543
1544 /* set callbacks and editing data */
1546 select_cb = ANIM_editkeyframes_select(select_mode);
1547
1548 if (leftright == ACTKEYS_LRSEL_LEFT) {
1549 ked.f1 = MINAFRAMEF;
1550 ked.f2 = float(scene->r.cfra + 0.1f);
1551 }
1552 else {
1553 ked.f1 = float(scene->r.cfra - 0.1f);
1554 ked.f2 = MAXFRAMEF;
1555 }
1556
1557 /* filter data */
1559 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1560
1561 /* select keys */
1562 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1563 switch (ale->type) {
1566 static_cast<GreasePencilLayerTreeNode *>(ale->data)->wrap(),
1567 ked.f1,
1568 ked.f2,
1569 select_mode);
1570 ale->update |= ANIM_UPDATE_DEPS;
1571 break;
1572 case ANIMTYPE_GPLAYER:
1574 static_cast<bGPDlayer *>(ale->data), ked.f1, ked.f2, select_mode);
1575 ale->update |= ANIM_UPDATE_DEPS;
1576 break;
1577
1578 case ANIMTYPE_MASKLAYER:
1580 static_cast<MaskLayer *>(ale->data), ked.f1, ked.f2, select_mode);
1581 break;
1582
1583 case ANIMTYPE_FCURVE: {
1584 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
1585 FCurve *fcurve = static_cast<FCurve *>(ale->key_data);
1586 if (adt) {
1587 ANIM_nla_mapping_apply_fcurve(adt, fcurve, false, true);
1588 ANIM_fcurve_keyframes_loop(&ked, fcurve, ok_cb, select_cb, nullptr);
1589 ANIM_nla_mapping_apply_fcurve(adt, fcurve, true, true);
1590 }
1591 else {
1592 ANIM_fcurve_keyframes_loop(&ked, fcurve, ok_cb, select_cb, nullptr);
1593 }
1594 break;
1595 }
1596
1597 default:
1598 BLI_assert_msg(false, "Keys cannot be selected into this animation type.");
1599 }
1600 }
1601
1602 /* Sync marker support */
1603 if (select_mode == SELECT_ADD) {
1604 SpaceAction *saction = (SpaceAction *)ac->sl;
1605
1606 if ((saction) && (saction->flag & SACTION_MARKERS_MOVE)) {
1608 LISTBASE_FOREACH (TimeMarker *, marker, markers) {
1609 if (((leftright == ACTKEYS_LRSEL_LEFT) && (marker->frame < scene->r.cfra)) ||
1610 ((leftright == ACTKEYS_LRSEL_RIGHT) && (marker->frame >= scene->r.cfra)))
1611 {
1612 marker->flag |= SELECT;
1613 }
1614 else {
1615 marker->flag &= ~SELECT;
1616 }
1617 }
1618 }
1619 }
1620
1621 /* Cleanup */
1622 ANIM_animdata_update(ac, &anim_data);
1623 ANIM_animdata_freelist(&anim_data);
1624}
1625
1626/* ----------------- */
1627
1629{
1630 bAnimContext ac;
1631 short leftright = RNA_enum_get(op->ptr, "mode");
1632 eEditKeyframes_Select selectmode;
1633
1634 /* get editor data */
1635 if (ANIM_animdata_get_context(C, &ac) == 0) {
1636 return OPERATOR_CANCELLED;
1637 }
1638
1639 /* select mode is either replace (deselect all, then add) or add/extend */
1640 if (RNA_boolean_get(op->ptr, "extend")) {
1641 selectmode = SELECT_INVERT;
1642 }
1643 else {
1644 selectmode = SELECT_REPLACE;
1645 }
1646
1647 /* if "test" mode is set, we don't have any info to set this with */
1648 if (leftright == ACTKEYS_LRSEL_TEST) {
1649 return OPERATOR_CANCELLED;
1650 }
1651
1652 /* do the selecting now */
1653 actkeys_select_leftright(&ac, leftright, selectmode);
1654
1655 /* set notifier that keyframe selection (and channels too) have changed */
1658
1659 return OPERATOR_FINISHED;
1660}
1661
1663{
1664 bAnimContext ac;
1665 short leftright = RNA_enum_get(op->ptr, "mode");
1666
1667 /* get editor data */
1668 if (ANIM_animdata_get_context(C, &ac) == 0) {
1669 return OPERATOR_CANCELLED;
1670 }
1671
1672 /* handle mode-based testing */
1673 if (leftright == ACTKEYS_LRSEL_TEST) {
1674 Scene *scene = ac.scene;
1675 ARegion *region = ac.region;
1676 View2D *v2d = &region->v2d;
1677 float x;
1678
1679 /* determine which side of the current frame mouse is on */
1680 x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
1681 if (x < scene->r.cfra) {
1682 RNA_enum_set(op->ptr, "mode", ACTKEYS_LRSEL_LEFT);
1683 }
1684 else {
1685 RNA_enum_set(op->ptr, "mode", ACTKEYS_LRSEL_RIGHT);
1686 }
1687 }
1688
1689 /* perform selection */
1690 return actkeys_select_leftright_exec(C, op);
1691}
1692
1694{
1695 PropertyRNA *prop;
1696
1697 /* identifiers */
1698 ot->name = "Select Left/Right";
1699 ot->idname = "ACTION_OT_select_leftright";
1700 ot->description = "Select keyframes to the left or the right of the current frame";
1701
1702 /* api callbacks */
1706
1707 /* flags */
1709
1710 /* properties */
1711 ot->prop = RNA_def_enum(
1714
1715 prop = RNA_def_boolean(ot->srna, "extend", false, "Extend Select", "");
1717}
1718
1721/* -------------------------------------------------------------------- */
1734/* option 1) select keyframe directly under mouse */
1736 bAnimListElem *ale,
1737 const eEditKeyframes_Select select_mode,
1738 float selx)
1739{
1740 KeyframeEditData ked = {{nullptr}};
1741 KeyframeEditFunc select_cb, ok_cb;
1742
1743 /* get functions for selecting keyframes */
1744 select_cb = ANIM_editkeyframes_select(select_mode);
1746 ked.f1 = selx;
1748
1749 /* select the nominated keyframe on the given frame */
1750 if (ale->type == ANIMTYPE_GPLAYER) {
1751 ED_gpencil_select_frame(static_cast<bGPDlayer *>(ale->data), selx, select_mode);
1752 ale->update |= ANIM_UPDATE_DEPS;
1753 }
1754 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1756 static_cast<GreasePencilLayer *>(ale->data)->wrap(), selx, select_mode);
1757 ale->update |= ANIM_UPDATE_DEPS;
1758 }
1759 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER_GROUP) {
1761 static_cast<GreasePencilLayerTreeGroup *>(ale->data)->wrap(), selx, select_mode);
1762 }
1763 else if (ale->type == ANIMTYPE_GREASE_PENCIL_DATABLOCK) {
1764 ListBase anim_data = {nullptr, nullptr};
1766
1768 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1769
1770 /* Loop over all keys that are represented by this data-block key. */
1771 LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
1772 if ((ale2->type != ANIMTYPE_GREASE_PENCIL_LAYER) || (ale2->id != ale->data)) {
1773 continue;
1774 }
1776 static_cast<GreasePencilLayer *>(ale2->data)->wrap(), selx, select_mode);
1777 ale2->update |= ANIM_UPDATE_DEPS;
1778 }
1779 }
1780 else if (ale->type == ANIMTYPE_MASKLAYER) {
1781 ED_mask_select_frame(static_cast<MaskLayer *>(ale->data), selx, select_mode);
1782 }
1783 else {
1784 if (ale->type == ANIMTYPE_SUMMARY && ale->datatype == ALE_ALL) {
1785 ListBase anim_data = {nullptr, nullptr};
1787
1789 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1790
1791 /* Loop over all keys that are represented by this summary key. */
1792 LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
1793 switch (ale2->type) {
1794 case ANIMTYPE_GPLAYER:
1795 ED_gpencil_select_frame(static_cast<bGPDlayer *>(ale2->data), selx, select_mode);
1796 ale2->update |= ANIM_UPDATE_DEPS;
1797 break;
1798
1799 case ANIMTYPE_MASKLAYER:
1800 ED_mask_select_frame(static_cast<MaskLayer *>(ale2->data), selx, select_mode);
1801 break;
1802
1805 static_cast<GreasePencilLayer *>(ale2->data)->wrap(), selx, select_mode);
1806 ale2->update |= ANIM_UPDATE_DEPS;
1807 break;
1808
1809 default:
1810 break;
1811 }
1812 }
1813
1814 ANIM_animdata_update(ac, &anim_data);
1815 ANIM_animdata_freelist(&anim_data);
1816 }
1817
1819 ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, nullptr);
1820 }
1821 }
1822}
1823
1824/* Option 2) Selects all the keyframes on either side of the current frame
1825 * (depends on which side the mouse is on) */
1826/* (see actkeys_select_leftright) */
1827
1828/* Option 3) Selects all visible keyframes in the same frame as the mouse click */
1829static void actkeys_mselect_column(bAnimContext *ac, eEditKeyframes_Select select_mode, float selx)
1830{
1831 ListBase anim_data = {nullptr, nullptr};
1833
1834 KeyframeEditFunc select_cb, ok_cb;
1835 KeyframeEditData ked = {{nullptr}};
1836
1837 /* set up BezTriple edit callbacks */
1838 select_cb = ANIM_editkeyframes_select(select_mode);
1840
1841 /* loop through all of the keys and select additional keyframes
1842 * based on the keys found to be selected above
1843 */
1845 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1846
1847 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1848 /* select elements with frame number matching cfra */
1849 if (ale->type == ANIMTYPE_GPLAYER) {
1850 ED_gpencil_select_frame(static_cast<bGPDlayer *>(ale->data), selx, select_mode);
1851 ale->update |= ANIM_UPDATE_DEPS;
1852 }
1853 else if (ale->type == ANIMTYPE_MASKLAYER) {
1854 ED_mask_select_frame(static_cast<MaskLayer *>(ale->data), selx, select_mode);
1855 }
1856 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1858 static_cast<GreasePencilLayer *>(ale->data)->wrap(), selx, select_mode);
1859 ale->update |= ANIM_UPDATE_DEPS;
1860 }
1861 else {
1862 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
1863
1864 /* set frame for validation callback to refer to */
1865 if (adt) {
1867 }
1868 else {
1869 ked.f1 = selx;
1870 }
1871
1873 &ked, static_cast<FCurve *>(ale->key_data), ok_cb, select_cb, nullptr);
1874 }
1875 }
1876
1877 /* free elements */
1878 BLI_freelistN(&ked.list);
1879
1880 ANIM_animdata_update(ac, &anim_data);
1881 ANIM_animdata_freelist(&anim_data);
1882}
1883
1884/* option 4) select all keyframes in same channel */
1886 bAnimListElem *ale,
1887 eEditKeyframes_Select select_mode)
1888{
1889 KeyframeEditFunc select_cb;
1890
1891 /* get functions for selecting keyframes */
1892 select_cb = ANIM_editkeyframes_select(select_mode);
1893
1894 /* select all keyframes in this channel */
1895 if (ale->type == ANIMTYPE_GPLAYER) {
1896 ED_gpencil_select_frames(static_cast<bGPDlayer *>(ale->data), select_mode);
1897 ale->update = ANIM_UPDATE_DEPS;
1898 }
1899 else if (ale->type == ANIMTYPE_MASKLAYER) {
1900 ED_mask_select_frames(static_cast<MaskLayer *>(ale->data), select_mode);
1901 }
1902 else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
1904 static_cast<GreasePencilLayer *>(ale->data)->wrap(), select_mode);
1905 ale->update |= ANIM_UPDATE_DEPS;
1906 }
1907 else {
1908 if (ale->type == ANIMTYPE_SUMMARY && ale->datatype == ALE_ALL) {
1909 ListBase anim_data = {nullptr, nullptr};
1911
1913 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
1914
1915 LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
1916 if (ale2->type == ANIMTYPE_GPLAYER) {
1917 ED_gpencil_select_frames(static_cast<bGPDlayer *>(ale2->data), select_mode);
1918 ale2->update |= ANIM_UPDATE_DEPS;
1919 }
1920 else if (ale2->type == ANIMTYPE_MASKLAYER) {
1921 ED_mask_select_frames(static_cast<MaskLayer *>(ale2->data), select_mode);
1922 }
1923 }
1924
1925 ANIM_animdata_update(ac, &anim_data);
1926 ANIM_animdata_freelist(&anim_data);
1927 }
1928
1930 ANIM_animchannel_keyframes_loop(nullptr, ac->ads, ale, nullptr, select_cb, nullptr);
1931 }
1932 }
1933}
1934
1935/* ------------------- */
1936
1938 const int mval[2],
1939 eEditKeyframes_Select select_mode,
1940 const bool deselect_all,
1941 const bool column,
1942 const bool same_channel,
1943 bool wait_to_deselect_others)
1944{
1947
1948 bAnimListElem *ale = nullptr;
1949 bool found = false;
1950 bool is_selected = false;
1951 float frame = 0.0f; /* frame of keyframe under mouse - NLA corrections not applied/included */
1952 float selx = 0.0f; /* frame of keyframe under mouse */
1953 int ret_value = OPERATOR_FINISHED;
1954
1956 ac, filter, mval[0], mval[1], &ale, &selx, &frame, &found, &is_selected);
1957
1958 if (select_mode != SELECT_REPLACE) {
1959 wait_to_deselect_others = false;
1960 }
1961
1962 /* For replacing selection, if we have something to select, we have to clear existing selection.
1963 * The same goes if we found nothing to select, and deselect_all is true
1964 * (deselect on nothing behavior). */
1965 if ((select_mode == SELECT_REPLACE && found) || (!found && deselect_all)) {
1966 /* reset selection mode for next steps */
1967 select_mode = SELECT_ADD;
1968
1969 /* Rather than deselecting others, users may want to drag to box-select (drag from empty space)
1970 * or tweak-translate an already selected item. If these cases may apply, delay deselection. */
1971 if (wait_to_deselect_others && (!found || is_selected)) {
1972 ret_value = OPERATOR_RUNNING_MODAL;
1973 }
1974 else {
1975 /* deselect all keyframes */
1977
1978 /* highlight channel clicked on */
1980 /* deselect all other channels first */
1982
1983 /* Highlight Action-Group or F-Curve? */
1984 if (ale != nullptr && ale->data) {
1985 if (ale->type == ANIMTYPE_GROUP) {
1986 bActionGroup *agrp = static_cast<bActionGroup *>(ale->data);
1987
1988 agrp->flag |= AGRP_SELECTED;
1990 ac, ac->data, eAnimCont_Types(ac->datatype), filter, agrp, ANIMTYPE_GROUP);
1991 }
1992 else if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
1993 FCurve *fcu = static_cast<FCurve *>(ale->data);
1994
1995 fcu->flag |= FCURVE_SELECTED;
1997 ac->data,
1999 filter,
2000 fcu,
2001 eAnim_ChannelType(ale->type));
2002 }
2003 else if (ale->type == ANIMTYPE_GPLAYER) {
2004 bGPdata *gpd = (bGPdata *)ale->id;
2005 bGPDlayer *gpl = static_cast<bGPDlayer *>(ale->data);
2006
2008 }
2009 else if (ale->type == ANIMTYPE_ACTION_SLOT) {
2011 "fcurve_owner_id of an Action Slot should be an Action");
2012 animrig::Action *action = reinterpret_cast<animrig::Action *>(ale->fcurve_owner_id);
2013 animrig::Slot *slot = static_cast<animrig::Slot *>(ale->data);
2014 slot->set_selected(true);
2015 action->slot_active_set(slot->handle);
2016 }
2017 }
2018 }
2019 else if (ac->datatype == ANIMCONT_GPENCIL) {
2020 /* Deselect all other channels first. */
2022
2023 /* Highlight the grease pencil channel, and set the corresponding layer as active. */
2024 if (ale != nullptr && ale->data != nullptr && ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
2026 *reinterpret_cast<GreasePencil *>(ale->id),
2027 static_cast<blender::bke::greasepencil::Layer *>(ale->data));
2028 }
2029
2030 /* Highlight GPencil Layer (Legacy). */
2031 if (ale != nullptr && ale->data != nullptr && ale->type == ANIMTYPE_GPLAYER) {
2032 bGPdata *gpd = (bGPdata *)ale->id;
2033 bGPDlayer *gpl = static_cast<bGPDlayer *>(ale->data);
2034
2036 }
2037 }
2038 else if (ac->datatype == ANIMCONT_MASK) {
2039 /* deselect all other channels first */
2041
2042 if (ale != nullptr && ale->data != nullptr && ale->type == ANIMTYPE_MASKLAYER) {
2043 MaskLayer *masklay = static_cast<MaskLayer *>(ale->data);
2044
2045 masklay->flag |= MASK_LAYERFLAG_SELECT;
2046 }
2047 }
2048 }
2049 }
2050
2051 /* only select keyframes if we clicked on a valid channel and hit something */
2052 if (ale != nullptr) {
2053 if (found) {
2054 /* apply selection to keyframes */
2055 if (column) {
2056 /* select all keyframes in the same frame as the one we hit on the active channel
2057 * [#41077]: "frame" not "selx" here (i.e. no NLA corrections yet) as the code here
2058 * does that itself again as it needs to work on multiple data-blocks.
2059 */
2060 actkeys_mselect_column(ac, select_mode, frame);
2061 }
2062 else if (same_channel) {
2063 /* select all keyframes in the active channel */
2064 actkeys_mselect_channel_only(ac, ale, select_mode);
2065 }
2066 else {
2067 /* select the nominated keyframe on the given frame */
2068 actkeys_mselect_single(ac, ale, select_mode, selx);
2069 }
2070 }
2071
2072 /* flush tagged updates
2073 * NOTE: We temporarily add this channel back to the list so that this can happen
2074 */
2075 ListBase anim_data = {ale, ale};
2076 ANIM_animdata_update(ac, &anim_data);
2077
2078 /* free this channel */
2079 MEM_freeN(ale);
2080 }
2081
2082 return ret_value;
2083}
2084
2085/* handle clicking */
2087{
2088 bAnimContext ac;
2089 int ret_value;
2090
2091 /* get editor data */
2092 if (ANIM_animdata_get_context(C, &ac) == 0) {
2093 return OPERATOR_CANCELLED;
2094 }
2095
2096 /* get useful pointers from animation context data */
2097 // region = ac.region; /* UNUSED. */
2098
2099 /* select mode is either replace (deselect all, then add) or add/extend */
2100 const eEditKeyframes_Select selectmode = RNA_boolean_get(op->ptr, "extend") ? SELECT_INVERT :
2102 const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
2103 const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
2104 int mval[2];
2105
2106 /* column selection */
2107 const bool column = RNA_boolean_get(op->ptr, "column");
2108 const bool channel = RNA_boolean_get(op->ptr, "channel");
2109
2110 mval[0] = RNA_int_get(op->ptr, "mouse_x");
2111 mval[1] = RNA_int_get(op->ptr, "mouse_y");
2112
2113 /* Select keyframe(s) based upon mouse position. */
2114 ret_value = mouse_action_keys(
2115 &ac, mval, selectmode, deselect_all, column, channel, wait_to_deselect_others);
2116
2117 /* set notifier that keyframe selection (and channels too) have changed */
2120
2121 /* for tweak grab to work */
2122 return ret_value | OPERATOR_PASS_THROUGH;
2123}
2124
2126{
2127 PropertyRNA *prop;
2128
2129 /* identifiers */
2130 ot->name = "Select Keyframes";
2131 ot->idname = "ACTION_OT_clickselect";
2132 ot->description = "Select keyframes by clicking on them";
2133
2134 /* callbacks */
2139
2140 /* flags */
2141 ot->flag = OPTYPE_UNDO;
2142
2143 /* properties */
2145 /* Key-map: Enable with `Shift`. */
2146 prop = RNA_def_boolean(
2147 ot->srna,
2148 "extend",
2149 false,
2150 "Extend Select",
2151 "Toggle keyframe selection instead of leaving newly selected keyframes only");
2153
2154 prop = RNA_def_boolean(ot->srna,
2155 "deselect_all",
2156 false,
2157 "Deselect On Nothing",
2158 "Deselect all when nothing under the cursor");
2160
2161 /* Key-map: Enable with `Alt`. */
2162 prop = RNA_def_boolean(
2163 ot->srna,
2164 "column",
2165 false,
2166 "Column Select",
2167 "Select all keyframes that occur on the same frame as the one under the mouse");
2169
2170 /* Key-map: Enable with `Ctrl-Alt`. */
2171 prop = RNA_def_boolean(ot->srna,
2172 "channel",
2173 false,
2174 "Only Channel",
2175 "Select all the keyframes in the channel under the mouse");
2177}
2178
Low-level operations for grease pencil.
float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, short mode)
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:513
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
void BLI_lasso_boundbox(rcti *rect, blender::Span< blender::int2 > mcoords)
#define LISTBASE_FOREACH(type, var, list)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:193
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
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_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_GPDATABLOCK
@ 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 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
eSelectOp
@ SEL_OP_SUB
Read Guarded memory(de)allocation.
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ PROP_HIDDEN
Definition RNA_types.hh:239
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:1616
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:1663
float UI_view2d_region_to_view_x(const View2D *v2d, float x)
Definition view2d.cc:1652
void UI_view2d_region_to_view_rctf(const View2D *v2d, const rctf *rect_src, rctf *rect_dst) ATTR_NONNULL()
Definition view2d.cc:1670
@ OPTYPE_DEPENDS_ON_CURSOR
Definition WM_types.hh:198
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NC_ANIMATION
Definition WM_types.hh:355
#define ND_KEYFRAME
Definition WM_types.hh:461
#define ND_ANIMCHAN
Definition WM_types.hh:463
#define NA_SELECTED
Definition WM_types.hh:555
@ ACTKEYS_LRSEL_TEST
@ ACTKEYS_LRSEL_LEFT
@ ACTKEYS_LRSEL_RIGHT
@ ACTKEYS_COLUMNSEL_CFRA
@ ACTKEYS_COLUMNSEL_MARKERS_BETWEEN
@ ACTKEYS_COLUMNSEL_MARKERS_COLUMN
@ ACTKEYS_COLUMNSEL_KEYS
static bool actkeys_is_key_at_position(bAnimContext *ac, float region_x, float region_y)
static int 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)
@ ACTKEYS_BORDERSEL_ALLKEYS
@ ACTKEYS_BORDERSEL_CHANNELS
@ ACTKEYS_BORDERSEL_FRAMERANGE
static int actkeys_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void ACTION_OT_select_column(wmOperatorType *ot)
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 int actkeys_clickselect_exec(bContext *C, wmOperator *op)
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 int actkeys_box_select_exec(bContext *C, wmOperator *op)
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 int actkeys_columnselect_exec(bContext *C, wmOperator *op)
static int action_circle_select_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem prop_actkeys_leftright_select_types[]
static void region_select_elem(RegionSelectData *sel_data, bAnimListElem *ale, bool summary)
static int actkeys_select_leftright_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
void ACTION_OT_select_all(wmOperatorType *ot)
static bAnimListElem * actkeys_find_list_element_at_position(bAnimContext *ac, eAnimFilter_Flags filter, float region_x, float region_y)
static int actkeys_deselectall_exec(bContext *C, wmOperator *op)
void ACTION_OT_select_lasso(wmOperatorType *ot)
static int actkeys_select_less_exec(bContext *C, wmOperator *)
void ACTION_OT_select_leftright(wmOperatorType *ot)
static void markers_selectkeys_between(bAnimContext *ac)
static void columnselect_action_keys(bAnimContext *ac, short mode)
static void select_moreless_action_keys(bAnimContext *ac, short mode)
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 int actkeys_select_leftright_exec(bContext *C, wmOperator *op)
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[]
static int actkeys_select_more_exec(bContext *C, wmOperator *)
static int actkeys_select_linked_exec(bContext *C, wmOperator *)
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:457
void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
Definition anim_deps.cc:350
AnimData * ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
Definition anim_draw.cc:210
void ANIM_nla_mapping_apply_fcurve(AnimData *adt, FCurve *fcu, bool restore, bool only_keys)
Definition anim_draw.cc:290
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)
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)
draw_view in_light_buf[] float
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
const vector< Marker > & markers
#define GS(x)
Definition iris.cc:202
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 scene_to_keylist(bDopeSheet *ads, Scene *sce, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
const ActKeyColumn * ED_keylist_find_any_between(const AnimKeylist *keylist, const Range2f frame_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 fcurve_to_keylist(AnimData *adt, FCurve *fcu, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
void action_slot_to_keylist(AnimData *adt, animrig::Action &action, const animrig::slot_handle_t slot_handle, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
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_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
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)
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.c:32
KeyframeEditFunc select_cb
KeyframeEditFunc ok_cb
KeyframeEditData ked
bAnimContext * ac
BezTriple * bezt
unsigned int totvert
char name[66]
Definition DNA_ID.h:425
eKeyframeIterFlags iterflags
blender::Array< blender::int2 > mcoords
void * first
struct MaskLayer * next
KeyframeEditFunc ok_cb
bAnimContext * ac
KeyframeEditFunc select_cb
KeyframeEditData ked
SpaceLink * sl
ListBase * markers
eAnimCont_Types datatype
bDopeSheet * ads
ARegion * region
bAnimListElem * next
eAnim_ChannelType type
eAnim_Update_Flags update
eAnim_KeyType datatype
bAnimListElem * prev
struct bGPDlayer * next
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
int mval[2]
Definition WM_types.hh:728
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
std::string(* get_name)(wmOperatorType *ot, PointerRNA *ptr)
Definition WM_types.hh:1068
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
struct PointerRNA * ptr
float max
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:4125
bool WM_gesture_is_modal_first(const wmGesture *gesture)
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_circle_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Array< int2 > WM_gesture_lasso_path_to_array(bContext *, wmOperator *op)
void WM_gesture_circle_cancel(bContext *C, wmOperator *op)
int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
void WM_gesture_lasso_cancel(bContext *C, wmOperator *op)
int 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)
int WM_generic_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event)