Blender V4.3
graph_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_lasso_2d.hh"
17#include "BLI_math_vector.h"
18#include "BLI_utildefines.h"
19
20#include "DNA_anim_types.h"
21#include "DNA_scene_types.h"
22#include "DNA_screen_types.h"
23#include "DNA_space_types.h"
24
25#include "RNA_access.hh"
26#include "RNA_define.hh"
27
28#include "BKE_fcurve.hh"
29#include "BKE_nla.hh"
30
31#include "UI_interface_c.hh"
32#include "UI_resources.hh"
33#include "UI_view2d.hh"
34
35#include "ED_anim_api.hh"
36#include "ED_keyframes_edit.hh"
37#include "ED_markers.hh"
38#include "ED_select_utils.hh"
39
40#include "WM_api.hh"
41#include "WM_types.hh"
42
43#include "graph_intern.hh"
44
45/* -------------------------------------------------------------------- */
49/* temp info for caching handle vertices close */
52
53 FCurve *fcu; /* F-Curve that keyframe comes from */
54
55 BezTriple *bezt; /* keyframe to consider */
56 FPoint *fpt; /* sample point to consider */
57
58 short hpoint; /* the handle index that we hit (eHandleIndex) */
59 short sel; /* whether the handle is selected or not */
60 int dist; /* distance from mouse to vert */
61
62 eAnim_ChannelType ctype; /* type of animation channel this FCurve comes from */
63
64 float frame; /* frame that point was on when it matched (global time) */
65};
66
67/* Tags for the type of graph vert that we have */
73
74/* Tolerance for absolute radius (in pixels) of the vert from the cursor to use */
75/* TODO: perhaps this should depend a bit on the size that the user set the vertices to be? */
76#define GVERTSEL_TOL (10 * U.pixelsize)
77
78/* ....... */
79
80/* check if its ok to select a handle */
81/* XXX also need to check for int-values only? */
83{
84 if (sipo->flag & SIPO_NOHANDLES) {
85 return false;
86 }
87 if ((sipo->flag & SIPO_SELVHANDLESONLY) && BEZT_ISSEL_ANY(bezt) == 0) {
88 return false;
89 }
90 return true;
91}
92
93/* check if the given vertex is within bounds or not */
94/* TODO: should we return if we hit something? */
96 View2D *v2d,
97 FCurve *fcu,
99 BezTriple *bezt,
100 FPoint *fpt,
101 short hpoint,
102 const int mval[2],
103 float unit_scale,
104 float offset)
105{
106 /* Keyframes or Samples? */
107 if (bezt) {
108 int screen_co[2], dist;
109
110 /* convert from data-space to screen coordinates
111 * NOTE: `hpoint +1` gives us 0,1,2 respectively for each handle,
112 * needed to access the relevant vertex coordinates in the 3x3 'vec' matrix */
114 bezt->vec[hpoint + 1][0],
115 (bezt->vec[hpoint + 1][1] + offset) * unit_scale,
116 &screen_co[0],
117 &screen_co[1]) &&
118 /* check if distance from mouse cursor to vert in screen space is within tolerance */
119 ((dist = len_v2v2_int(mval, screen_co)) <= GVERTSEL_TOL))
120 {
121 tNearestVertInfo *nvi = (tNearestVertInfo *)matches->last;
122 bool replace = false;
123
124 /* If there is already a point for the F-Curve,
125 * check if this point is closer than that was. */
126 if ((nvi) && (nvi->fcu == fcu)) {
127 /* replace if we are closer, or if equal and that one wasn't selected but we are... */
128 if ((nvi->dist > dist) || ((nvi->sel == 0) && BEZT_ISSEL_ANY(bezt))) {
129 replace = true;
130 }
131 }
132 /* add new if not replacing... */
133 if (replace == 0) {
134 nvi = static_cast<tNearestVertInfo *>(
135 MEM_callocN(sizeof(tNearestVertInfo), "Nearest Graph Vert Info - Bezt"));
136 }
137
138 /* store values */
139 nvi->fcu = fcu;
140 nvi->ctype = ctype;
141
142 nvi->bezt = bezt;
143 nvi->hpoint = hpoint;
144 nvi->dist = dist;
145
146 nvi->frame = bezt->vec[1][0]; /* currently in global time... */
147
148 /* NOTE: `hpoint` is -1,0,1, but `BEZT_ISSEL_IDX` expects 0,1,2. */
149 nvi->sel = BEZT_ISSEL_IDX(bezt, hpoint + 1);
150
151 /* add to list of matches if appropriate... */
152 if (replace == 0) {
153 BLI_addtail(matches, nvi);
154 }
155 }
156 }
157 else if (fpt) {
158 /* TODO: support #FPoint. */
159 }
160}
161
162/* helper for find_nearest_fcurve_vert() - build the list of nearest matches */
163static void get_nearest_fcurve_verts_list(bAnimContext *ac, const int mval[2], ListBase *matches)
164{
165 ListBase anim_data = {nullptr, nullptr};
166 int filter;
167
168 SpaceGraph *sipo = (SpaceGraph *)ac->sl;
169 View2D *v2d = &ac->region->v2d;
170 short mapping_flag = 0;
171
172 /* get curves to search through
173 * - if the option to only show keyframes that belong to selected F-Curves is enabled,
174 * include the 'only selected' flag...
175 */
178 /* FIXME: this should really be check for by the filtering code. */
179 if (U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) {
180 filter |= ANIMFILTER_SEL;
181 }
182 mapping_flag |= ANIM_get_normalization_flags(ac->sl);
184 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
185
186 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
187 FCurve *fcu = (FCurve *)ale->key_data;
188 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
189 float offset;
190 float unit_scale = ANIM_unit_mapping_get_factor(
191 ac->scene, ale->id, fcu, mapping_flag, &offset);
192
193 /* apply NLA mapping to all the keyframes */
194 if (adt) {
195 ANIM_nla_mapping_apply_fcurve(adt, static_cast<FCurve *>(ale->key_data), false, false);
196 }
197
198 if (fcu->bezt) {
199 BezTriple *bezt1 = fcu->bezt, *prevbezt = nullptr;
200 int i;
201
202 for (i = 0; i < fcu->totvert; i++, prevbezt = bezt1, bezt1++) {
203 /* keyframe */
205 v2d,
206 fcu,
207 eAnim_ChannelType(ale->type),
208 bezt1,
209 nullptr,
211 mval,
212 unit_scale,
213 offset);
214
215 /* Handles. */
216 if (fcurve_handle_sel_check(sipo, bezt1)) {
217 /* first handle only visible if previous segment had handles */
218 if ((!prevbezt && (bezt1->ipo == BEZT_IPO_BEZ)) ||
219 (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ)))
220 {
222 v2d,
223 fcu,
224 eAnim_ChannelType(ale->type),
225 bezt1,
226 nullptr,
228 mval,
229 unit_scale,
230 offset);
231 }
232
233 /* second handle only visible if this segment is bezier */
234 if (bezt1->ipo == BEZT_IPO_BEZ) {
236 v2d,
237 fcu,
238 eAnim_ChannelType(ale->type),
239 bezt1,
240 nullptr,
242 mval,
243 unit_scale,
244 offset);
245 }
246 }
247 }
248 }
249 else if (fcu->fpt) {
250 /* TODO: do this for samples too. */
251 }
252
253 /* un-apply NLA mapping from all the keyframes */
254 if (adt) {
255 ANIM_nla_mapping_apply_fcurve(adt, static_cast<FCurve *>(ale->key_data), true, false);
256 }
257 }
258
259 /* free channels */
260 ANIM_animdata_freelist(&anim_data);
261}
262
263/* helper for find_nearest_fcurve_vert() - get the best match to use */
265{
266 /* abort if list is empty */
267 if (BLI_listbase_is_empty(matches)) {
268 return nullptr;
269 }
270
271 /* if list only has 1 item, remove it from the list and return */
272 if (BLI_listbase_is_single(matches)) {
273 /* need to remove from the list, otherwise it gets freed and then we can't return it */
274 return static_cast<tNearestVertInfo *>(BLI_pophead(matches));
275 }
276
277 /* The goal of the remaining code below is to prioritize selecting verts on
278 * selected fcurves, but to still cycle through the vertices in `matches` if
279 * a selected-fcurve vertex is already selected. */
280
281 /* Try to find the first selected vert in `matches`. Additionally, if
282 * one exists, rotate `matches` to put it last in the list and the vert
283 * following it first, since that's the order we'll want to scan in. */
284 tNearestVertInfo *nvi_first_selected = nullptr;
285 LISTBASE_FOREACH (tNearestVertInfo *, nvi, matches) {
286 if (nvi->sel) {
287 nvi_first_selected = nvi;
288 BLI_listbase_rotate_last(matches, nvi_first_selected);
289 break;
290 }
291 }
292
293 /* Try to find the next vert that's on the active fcurve, falling back
294 * to the next vert on any selected fcurve if that's not found. */
295 tNearestVertInfo *nvi_to_select = nullptr;
296 LISTBASE_FOREACH (tNearestVertInfo *, nvi, matches) {
297 if (nvi == nvi_first_selected) {
298 continue;
299 }
300
301 if (nvi->fcu->flag & FCURVE_ACTIVE) {
302 nvi_to_select = nvi;
303 break;
304 }
305
306 if (nvi->fcu->flag & FCURVE_SELECTED && !nvi_to_select) {
307 nvi_to_select = nvi;
308 }
309 }
310
311 /* If we found a vert on a selected fcurve, return it. */
312 if (nvi_to_select) {
313 BLI_remlink(matches, nvi_to_select);
314 return nvi_to_select;
315 }
316
317 /* If we're still here, that means we didn't find any verts on selected
318 * fcurves. So return the head (which is also the item following
319 * `nvi_first_selected` if that was found). */
320 return static_cast<tNearestVertInfo *>(BLI_pophead(matches));
321}
322
330{
331 ListBase matches = {nullptr, nullptr};
332 tNearestVertInfo *nvi;
333
334 /* step 1: get the nearest verts */
335 get_nearest_fcurve_verts_list(ac, mval, &matches);
336
337 /* step 2: find the best vert */
338 nvi = get_best_nearest_fcurve_vert(&matches);
339
340 BLI_freelistN(&matches);
341
342 /* return the best vert found */
343 return nvi;
344}
345
348/* -------------------------------------------------------------------- */
357void deselect_graph_keys(bAnimContext *ac, bool test, eEditKeyframes_Select sel, bool do_channels)
358{
359 ListBase anim_data = {nullptr, nullptr};
360 int filter;
361
362 KeyframeEditData ked = {{nullptr}};
363 KeyframeEditFunc test_cb, sel_cb;
364
365 /* determine type-based settings */
368
369 /* filter data */
371 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
372
373 /* init BezTriple looping data */
375
376 /* See if we should be selecting or deselecting */
377 if (test) {
378 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
380 &ked, static_cast<FCurve *>(ale->key_data), nullptr, test_cb, nullptr))
381 {
382 sel = SELECT_SUBTRACT;
383 break;
384 }
385 }
386 }
387
388 /* convert sel to selectmode, and use that to get editor */
389 sel_cb = ANIM_editkeyframes_select(sel);
390
391 /* Now set the flags */
392 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
393 FCurve *fcu = (FCurve *)ale->key_data;
394
395 /* Keyframes First */
397 &ked, static_cast<FCurve *>(ale->key_data), nullptr, sel_cb, nullptr);
398
399 /* affect channel selection status? */
400 if (do_channels) {
401 /* Only change selection of channel when the visibility of keyframes
402 * doesn't depend on this. */
403 if ((U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) == 0) {
404 /* deactivate the F-Curve, and deselect if deselecting keyframes.
405 * otherwise select the F-Curve too since we've selected all the keyframes
406 */
407 if (sel == SELECT_SUBTRACT) {
408 fcu->flag &= ~FCURVE_SELECTED;
409 }
410 else {
411 fcu->flag |= FCURVE_SELECTED;
412 }
413 }
414
415 /* always deactivate all F-Curves if we perform batch ops for selection */
416 fcu->flag &= ~FCURVE_ACTIVE;
417 }
418 }
419
420 /* Cleanup */
421 ANIM_animdata_freelist(&anim_data);
422}
423
424/* ------------------- */
425
427{
428 bAnimContext ac;
429 bAnimListElem *ale_active = nullptr;
430
431 /* get editor data */
432 if (ANIM_animdata_get_context(C, &ac) == 0) {
433 return OPERATOR_CANCELLED;
434 }
435
436 /* find active F-Curve, and preserve this for later
437 * or else it becomes annoying with the current active
438 * curve keeps fading out even while you're editing it
439 */
440 ale_active = get_active_fcurve_channel(&ac);
441
442 /* 'standard' behavior - check if selected, then apply relevant selection */
443 const int action = RNA_enum_get(op->ptr, "action");
444 switch (action) {
445 case SEL_TOGGLE:
446 deselect_graph_keys(&ac, true, SELECT_ADD, true);
447 break;
448 case SEL_SELECT:
449 deselect_graph_keys(&ac, false, SELECT_ADD, true);
450 break;
451 case SEL_DESELECT:
452 deselect_graph_keys(&ac, false, SELECT_SUBTRACT, true);
453 break;
454 case SEL_INVERT:
455 deselect_graph_keys(&ac, false, SELECT_INVERT, true);
456 break;
457 default:
458 BLI_assert(0);
459 break;
460 }
461
462 /* restore active F-Curve... */
463 if (ale_active) {
464 FCurve *fcu = (FCurve *)ale_active->data;
465
466 /* all others should not be disabled, so we should be able to just set this directly...
467 * - selection needs to be set too, or else this won't work...
468 */
470
471 MEM_freeN(ale_active);
472 ale_active = nullptr;
473 }
474
475 /* set notifier that things have changed */
477
478 return OPERATOR_FINISHED;
479}
480
482{
483 /* identifiers */
484 ot->name = "Select All";
485 ot->idname = "GRAPH_OT_select_all";
486 ot->description = "Toggle selection of all keyframes";
487
488 /* api callbacks */
491
492 /* flags */
494
495 /* properties */
497}
498
501/* -------------------------------------------------------------------- */
514static rctf initialize_box_select_coords(const bAnimContext *ac, const rctf *rectf_view)
515{
516 const View2D *v2d = &ac->region->v2d;
517 rctf rectf;
518
519 /* Convert mouse coordinates to frame ranges and
520 * channel coordinates corrected for view pan/zoom. */
521 UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf);
522 return rectf;
523}
524
534
536{
537 ListBase anim_data = {nullptr, nullptr};
539 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
540 return anim_data;
541}
542
543static void initialize_box_select_key_editing_data(const bool incl_handles,
544 const short mode,
545 bAnimContext *ac,
546 void *data,
547 rctf *scaled_rectf,
548 KeyframeEditData *r_ked,
549 int *r_mapping_flag)
550{
551 memset(r_ked, 0, sizeof(KeyframeEditData));
552 switch (mode) {
554 KeyframeEdit_LassoData *data_lasso = static_cast<KeyframeEdit_LassoData *>(data);
555 data_lasso->rectf_scaled = scaled_rectf;
556 r_ked->data = data_lasso;
557 break;
558 }
560 KeyframeEdit_CircleData *data_circle = static_cast<KeyframeEdit_CircleData *>(data);
561 data_circle->rectf_scaled = scaled_rectf;
562 r_ked->data = data_circle;
563 break;
564 }
565 default:
566 r_ked->data = scaled_rectf;
567 break;
568 }
569 SpaceGraph *sipo = (SpaceGraph *)ac->sl;
570 if (sipo->flag & SIPO_SELVHANDLESONLY) {
572 }
573
574 /* Enable handles selection. (used in keyframes_edit.cc > keyframe_ok_checks function) */
575 if (incl_handles) {
577 *r_mapping_flag = 0;
578 }
579 else {
580 *r_mapping_flag = ANIM_UNITCONV_ONLYKEYS;
581 }
582
583 *r_mapping_flag |= ANIM_get_normalization_flags(ac->sl);
584}
585
596 const rctf *rectf_view,
597 short mode,
598 eEditKeyframes_Select selectmode,
599 bool incl_handles,
600 void *data)
601{
602 const rctf rectf = initialize_box_select_coords(ac, rectf_view);
603 const int filter = initialize_animdata_selection_filter();
604 ListBase anim_data = initialize_box_select_anim_data(filter, ac);
605 rctf scaled_rectf;
607 int mapping_flag;
609 incl_handles, mode, ac, data, &scaled_rectf, &ked, &mapping_flag);
610
611 /* Get beztriple editing/validation functions. */
612 const KeyframeEditFunc select_cb = ANIM_editkeyframes_select(selectmode);
613 const KeyframeEditFunc ok_cb = ANIM_editkeyframes_ok(mode);
614
615 /* This variable will be set to true if any key is selected or deselected. */
616 bool any_key_selection_changed = false;
617
618 /* First loop over data, doing box select. try selecting keys only. */
619 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
620 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
621 FCurve *fcu = (FCurve *)ale->key_data;
622 float offset;
623 const float unit_scale = ANIM_unit_mapping_get_factor(
624 ac->scene, ale->id, fcu, mapping_flag, &offset);
625
626 /* Apply NLA mapping to all the keyframes, since it's easier than trying to
627 * guess when a callback might use something different.
628 */
629 if (adt) {
631 adt, static_cast<FCurve *>(ale->key_data), false, incl_handles == 0);
632 }
633
634 scaled_rectf.xmin = rectf.xmin;
635 scaled_rectf.xmax = rectf.xmax;
636 scaled_rectf.ymin = rectf.ymin / unit_scale - offset;
637 scaled_rectf.ymax = rectf.ymax / unit_scale - offset;
638
639 /* Set horizontal range (if applicable).
640 * NOTE: these values are only used for x-range and y-range but not region
641 * (which uses ked.data, i.e. rectf)
642 */
643 if (mode != BEZT_OK_VALUERANGE) {
644 ked.f1 = rectf.xmin;
645 ked.f2 = rectf.xmax;
646 }
647 else {
648 ked.f1 = rectf.ymin;
649 ked.f2 = rectf.ymax;
650 }
651
652 /* Firstly, check if any keyframes will be hit by this. */
653 if (ANIM_fcurve_keyframes_loop(&ked, fcu, nullptr, ok_cb, nullptr)) {
654 /* select keyframes that are in the appropriate places */
655 ANIM_fcurve_keyframes_loop(&ked, fcu, ok_cb, select_cb, nullptr);
656 any_key_selection_changed = true;
657 /* Only change selection of channel when the visibility of keyframes
658 * doesn't depend on this. */
659 if ((U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) == 0) {
660 /* select the curve too now that curve will be touched */
661 if (selectmode == SELECT_ADD) {
662 fcu->flag |= FCURVE_SELECTED;
663 }
664 }
665 }
666
667 /* Un-apply NLA mapping from all the keyframes. */
668 if (adt) {
670 adt, static_cast<FCurve *>(ale->key_data), true, incl_handles == 0);
671 }
672 }
673
674 /* Cleanup. */
675 ANIM_animdata_freelist(&anim_data);
676
677 return any_key_selection_changed;
678}
679
684static short ok_bezier_always_ok(KeyframeEditData * /*ked*/, BezTriple * /*bezt*/)
685{
687}
688
689#define ABOVE 1
690#define INSIDE 0
691#define BELOW -1
692static int rectf_curve_zone_y(const FCurve *fcu,
693 const rctf *rectf,
694 const float offset,
695 const float unit_scale,
696 const float eval_x)
697{
698 const float fcurve_y = (evaluate_fcurve(fcu, eval_x) + offset) * unit_scale;
699 return fcurve_y < rectf->ymin ? BELOW : fcurve_y <= rectf->ymax ? INSIDE : ABOVE;
700}
701
702/* Checks whether the given rectangle intersects the given fcurve's calculated curve (i.e. not
703 * only keyframes, but also all the interpolated values). This is done by sampling the curve at
704 * different points between the xmin and the xmax of the rectangle.
705 */
706static bool rectf_curve_intersection(const float offset,
707 const float unit_scale,
708 const rctf *rectf,
709 AnimData *adt,
710 const FCurve *fcu)
711{
712 /* 30 sampling points. This worked well in tests. */
713 int num_steps = 30;
714
715 /* Remap the range at which to evaluate the fcurves. This enables us to avoid remapping
716 * the keys themselves. */
717 const float mapped_max = BKE_nla_tweakedit_remap(adt, rectf->xmax, NLATIME_CONVERT_UNMAP);
718 const float mapped_min = BKE_nla_tweakedit_remap(adt, rectf->xmin, NLATIME_CONVERT_UNMAP);
719 const float eval_step = (mapped_max - mapped_min) / num_steps;
720
721 /* Sample points on the given fcurve in the interval defined by the
722 * mapped_min and mapped_max of the selected rectangle.
723 * For each point, check if it is inside of the selection box. If it is, then select
724 * all the keyframes of the curve, the curve, and stop the loop.
725 */
726 struct {
727 float eval_x;
728 int zone;
729 } cur, prev;
730
731 prev.eval_x = mapped_min;
732 prev.zone = rectf_curve_zone_y(fcu, rectf, offset, unit_scale, prev.eval_x);
733 if (prev.zone == INSIDE) {
734 return true;
735 }
736
737 while (num_steps--) {
738 cur.eval_x = prev.eval_x + eval_step;
739 cur.zone = rectf_curve_zone_y(fcu, rectf, offset, unit_scale, cur.eval_x);
740 if (cur.zone != prev.zone) {
741 return true;
742 }
743
744 prev = cur;
745 }
746 return false;
747}
748#undef ABOVE
749#undef INSIDE
750#undef BELOW
751
760 const rctf *rectf_view,
761 const short mode,
762 const eEditKeyframes_Select selectmode,
763 const bool incl_handles,
764 void *data)
765{
766 const int filter = initialize_animdata_selection_filter();
767 ListBase anim_data = initialize_box_select_anim_data(filter, ac);
768 rctf scaled_rectf;
770 int mapping_flag;
772 incl_handles, mode, ac, data, &scaled_rectf, &ked, &mapping_flag);
773
774 FCurve *last_selected_curve = nullptr;
775
776 /* Go through all the curves and try selecting them. This function is only called
777 * if no keyframe is in the selection area, so we only have to check if the curve
778 * intersects the area in order to check if the selection/deselection must happen.
779 */
780
781 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
782 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
783 FCurve *fcu = (FCurve *)ale->key_data;
784 float offset;
785 const float unit_scale = ANIM_unit_mapping_get_factor(
786 ac->scene, ale->id, fcu, mapping_flag, &offset);
787
788 const rctf rectf = initialize_box_select_coords(ac, rectf_view);
789
790 /* scaled_rectf is declared at the top of the block because it is required by the
791 * initialize_box_select_key_editing_data function (which does
792 * data_xxx->rectf_scaled = scaled_rectf). The below assignment therefore modifies the
793 * data we use to iterate over the curves (ked).
794 */
795 scaled_rectf.xmin = rectf.xmin;
796 scaled_rectf.xmax = rectf.xmax;
797 scaled_rectf.ymin = rectf.ymin / unit_scale - offset;
798 scaled_rectf.ymax = rectf.ymax / unit_scale - offset;
799
800 const KeyframeEditFunc select_cb = ANIM_editkeyframes_select(selectmode);
801 if (rectf_curve_intersection(offset, unit_scale, &rectf, adt, fcu)) {
802 if ((selectmode & SELECT_ADD) || (selectmode & SELECT_REPLACE)) {
803 fcu->flag |= FCURVE_SELECTED;
804 last_selected_curve = fcu;
805 }
806 else {
807 fcu->flag &= ~FCURVE_SELECTED;
808 }
809 ANIM_fcurve_keyframes_loop(&ked, fcu, ok_bezier_always_ok, select_cb, nullptr);
810 }
811 }
812
813 /* Make sure that one of the selected curves is active in the end. */
814 if (last_selected_curve != nullptr) {
816 ac->data,
818 eAnimFilter_Flags(filter),
819 last_selected_curve,
821 }
822
823 ANIM_animdata_freelist(&anim_data);
824}
825
826/* ------------------- */
827
829{
830 bAnimContext ac;
831 if (ANIM_animdata_get_context(C, &ac) == 0) {
832 return OPERATOR_CANCELLED;
833 }
834
835 if (RNA_boolean_get(op->ptr, "tweak")) {
836 int mval[2];
837 WM_event_drag_start_mval(event, ac.region, mval);
838 tNearestVertInfo *under_mouse = find_nearest_fcurve_vert(&ac, mval);
839 bool mouse_is_over_element = under_mouse != nullptr;
840 if (under_mouse) {
841 MEM_freeN(under_mouse);
842 }
843
844 if (mouse_is_over_element) {
846 }
847 }
848
849 return WM_gesture_box_invoke(C, op, event);
850}
851
853{
854 bAnimContext ac;
855 rcti rect;
856 rctf rect_fl;
857 short mode = 0;
858
859 /* get editor data */
860 if (ANIM_animdata_get_context(C, &ac) == 0) {
861 return OPERATOR_CANCELLED;
862 }
863
864 const eSelectOp sel_op = eSelectOp(RNA_enum_get(op->ptr, "mode"));
865 const eEditKeyframes_Select selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT;
866 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
867 deselect_graph_keys(&ac, true, SELECT_SUBTRACT, true);
868 }
869
870 /* 'include_handles' from the operator specifies whether to include handles in the selection. */
871 const bool incl_handles = RNA_boolean_get(op->ptr, "include_handles");
872
873 /* Get settings from operator. */
875
876 /* Selection 'mode' depends on whether box_select region only matters on one axis. */
877 if (RNA_boolean_get(op->ptr, "axis_range")) {
878 /* Mode depends on which axis of the range is larger to determine which axis to use
879 * - Checking this in region-space is fine, as it's fundamentally still going to be a
880 * different rect size.
881 * - The frame-range select option is favored over the channel one (x over y),
882 * as frame-range one is often used for tweaking timing when "blocking",
883 * while channels is not that useful.
884 */
885 if (BLI_rcti_size_x(&rect) >= BLI_rcti_size_y(&rect)) {
886 mode = BEZT_OK_FRAMERANGE;
887 }
888 else {
889 mode = BEZT_OK_VALUERANGE;
890 }
891 }
892 else {
893 mode = BEZT_OK_REGION;
894 }
895
896 BLI_rctf_rcti_copy(&rect_fl, &rect);
897
898 /* Apply box_select action. */
899 const bool any_key_selection_changed = box_select_graphkeys(
900 &ac, &rect_fl, mode, selectmode, incl_handles, nullptr);
901 const bool use_curve_selection = RNA_boolean_get(op->ptr, "use_curve_selection");
902 if (use_curve_selection && !any_key_selection_changed) {
903 box_select_graphcurves(&ac, &rect_fl, mode, selectmode, incl_handles, nullptr);
904 }
905 /* Send notifier that keyframe selection has changed. */
907
908 return OPERATOR_FINISHED;
909}
910
912{
913 /* Identifiers. */
914 ot->name = "Box Select";
915 ot->idname = "GRAPH_OT_select_box";
916 ot->description = "Select all keyframes within the specified region";
917
918 /* API callbacks. */
923
925
926 /* Flags. */
928
929 /* Properties. */
930 ot->prop = RNA_def_boolean(ot->srna, "axis_range", false, "Axis Range", "");
932
933 PropertyRNA *prop;
934 prop = RNA_def_boolean(ot->srna,
935 "include_handles",
936 true,
937 "Include Handles",
938 "Are handles tested individually against the selection criteria");
940
941 prop = RNA_def_boolean(
942 ot->srna, "tweak", false, "Tweak", "Operator has been activated using a click-drag event");
944
945 prop = RNA_def_boolean(
946 ot->srna,
947 "use_curve_selection",
948 true,
949 "Select Curves",
950 "Allow selecting all the keyframes of a curve by selecting the calculated F-curve");
952
955}
956
957/* ------------------- */
958
960{
961 bAnimContext ac;
962
963 KeyframeEdit_LassoData data_lasso{};
964 rcti rect;
965 rctf rect_fl;
966
967 bool incl_handles;
968
969 /* Get editor data. */
970 if (ANIM_animdata_get_context(C, &ac) == 0) {
971 return OPERATOR_CANCELLED;
972 }
973
974 data_lasso.rectf_view = &rect_fl;
975 data_lasso.mcoords = WM_gesture_lasso_path_to_array(C, op);
976 if (data_lasso.mcoords.is_empty()) {
977 return OPERATOR_CANCELLED;
978 }
979
980 const eSelectOp sel_op = eSelectOp(RNA_enum_get(op->ptr, "mode"));
981 const eEditKeyframes_Select selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT;
982 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
983 deselect_graph_keys(&ac, false, SELECT_SUBTRACT, true);
984 }
985
986 {
987 SpaceGraph *sipo = (SpaceGraph *)ac.sl;
988 if (selectmode == SELECT_ADD) {
989 incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) || (sipo->flag & SIPO_NOHANDLES)) == 0;
990 }
991 else {
992 incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0;
993 }
994 }
995
996 /* Get settings from operator. */
997 BLI_lasso_boundbox(&rect, data_lasso.mcoords);
998 BLI_rctf_rcti_copy(&rect_fl, &rect);
999
1000 /* Apply box_select action. */
1001 const bool any_key_selection_changed = box_select_graphkeys(
1002 &ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso);
1003 const bool use_curve_selection = RNA_boolean_get(op->ptr, "use_curve_selection");
1004 if (use_curve_selection && !any_key_selection_changed) {
1006 &ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso);
1007 }
1008
1009 /* Send notifier that keyframe selection has changed. */
1011
1012 return OPERATOR_FINISHED;
1013}
1014
1016{
1017 /* Identifiers. */
1018 ot->name = "Lasso Select";
1019 ot->description = "Select keyframe points using lasso selection";
1020 ot->idname = "GRAPH_OT_select_lasso";
1021
1022 /* API callbacks. */
1028
1029 /* Flags. */
1031
1032 /* Properties. */
1036 ot->srna,
1037 "use_curve_selection",
1038 true,
1039 "Select Curves",
1040 "Allow selecting all the keyframes of a curve by selecting the curve itself");
1042}
1043
1044/* ------------------- */
1045
1047{
1048 bAnimContext ac;
1049 bool incl_handles = false;
1050
1051 KeyframeEdit_CircleData data = {nullptr};
1052 rctf rect_fl;
1053
1054 float x = RNA_int_get(op->ptr, "x");
1055 float y = RNA_int_get(op->ptr, "y");
1056 float radius = RNA_int_get(op->ptr, "radius");
1057
1058 /* Get editor data. */
1059 if (ANIM_animdata_get_context(C, &ac) == 0) {
1060 return OPERATOR_CANCELLED;
1061 }
1062
1063 const eSelectOp sel_op = ED_select_op_modal(
1064 eSelectOp(RNA_enum_get(op->ptr, "mode")),
1065 WM_gesture_is_modal_first(static_cast<const wmGesture *>(op->customdata)));
1066 const eEditKeyframes_Select selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT;
1067 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
1068 deselect_graph_keys(&ac, false, SELECT_SUBTRACT, true);
1069 }
1070
1071 data.mval[0] = x;
1072 data.mval[1] = y;
1073 data.radius_squared = radius * radius;
1074 data.rectf_view = &rect_fl;
1075
1076 rect_fl.xmin = x - radius;
1077 rect_fl.xmax = x + radius;
1078 rect_fl.ymin = y - radius;
1079 rect_fl.ymax = y + radius;
1080
1081 {
1082 SpaceGraph *sipo = (SpaceGraph *)ac.sl;
1083 if (selectmode == SELECT_ADD) {
1084 incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) || (sipo->flag & SIPO_NOHANDLES)) == 0;
1085 }
1086 else {
1087 incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0;
1088 }
1089 }
1090
1091 /* Apply box_select action. */
1092 const bool any_key_selection_changed = box_select_graphkeys(
1093 &ac, &rect_fl, BEZT_OK_REGION_CIRCLE, selectmode, incl_handles, &data);
1094 if (any_key_selection_changed) {
1095 /* If any key was selected at any time during this process, the entire-curve selection should
1096 * be disabled. Otherwise, sliding over any keyless part of the curve will immediately cause
1097 * the entire curve to be selected. */
1098 RNA_boolean_set(op->ptr, "use_curve_selection", false);
1099 }
1100 const bool use_curve_selection = RNA_boolean_get(op->ptr, "use_curve_selection");
1101 if (use_curve_selection && !any_key_selection_changed) {
1102 box_select_graphcurves(&ac, &rect_fl, BEZT_OK_REGION_CIRCLE, selectmode, incl_handles, &data);
1103 }
1104
1105 /* Send notifier that keyframe selection has changed. */
1107
1108 return OPERATOR_FINISHED;
1109}
1110
1112{
1113 ot->name = "Circle Select";
1114 ot->description = "Select keyframe points using circle selection";
1115 ot->idname = "GRAPH_OT_select_circle";
1116
1123
1124 /* flags */
1125 ot->flag = OPTYPE_UNDO;
1126
1127 /* properties */
1131 ot->srna,
1132 "use_curve_selection",
1133 true,
1134 "Select Curves",
1135 "Allow selecting all the keyframes of a curve by selecting the curve itself");
1137}
1138
1141/* -------------------------------------------------------------------- */
1151/* defines for column-select mode */
1153 {GRAPHKEYS_COLUMNSEL_KEYS, "KEYS", 0, "On Selected Keyframes", ""},
1154 {GRAPHKEYS_COLUMNSEL_CFRA, "CFRA", 0, "On Current Frame", ""},
1155 {GRAPHKEYS_COLUMNSEL_MARKERS_COLUMN, "MARKERS_COLUMN", 0, "On Selected Markers", ""},
1157 "MARKERS_BETWEEN",
1158 0,
1159 "Between Min/Max Selected Markers",
1160 ""},
1161 {0, nullptr, 0, nullptr, nullptr},
1162};
1163
1164/* ------------------- */
1165
1166/* Selects all visible keyframes between the specified markers */
1167/* TODO(@ideasman42): this is almost an _exact_ duplicate of a function of the same name in
1168 * `action_select.cc` should de-duplicate. */
1170{
1171 ListBase anim_data = {nullptr, nullptr};
1172 int filter;
1173
1174 KeyframeEditFunc ok_cb, select_cb;
1175 KeyframeEditData ked = {{nullptr}};
1176 float min, max;
1177
1178 /* get extreme markers */
1179 ED_markers_get_minmax(ac->markers, 1, &min, &max);
1180 min -= 0.5f;
1181 max += 0.5f;
1182
1183 /* Get editing functions + data. */
1186
1187 ked.f1 = min;
1188 ked.f2 = max;
1189
1190 /* filter data */
1194 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
1195
1196 /* select keys in-between */
1197 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1198 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
1199
1200 if (adt) {
1201 ANIM_nla_mapping_apply_fcurve(adt, static_cast<FCurve *>(ale->key_data), false, true);
1203 &ked, static_cast<FCurve *>(ale->key_data), ok_cb, select_cb, nullptr);
1204 ANIM_nla_mapping_apply_fcurve(adt, static_cast<FCurve *>(ale->key_data), true, true);
1205 }
1206 else {
1208 &ked, static_cast<FCurve *>(ale->key_data), ok_cb, select_cb, nullptr);
1209 }
1210 }
1211
1212 /* Cleanup */
1213 ANIM_animdata_freelist(&anim_data);
1214}
1215
1216/* Selects all visible keyframes in the same frames as the specified elements */
1217static void columnselect_graph_keys(bAnimContext *ac, short mode)
1218{
1219 ListBase anim_data = {nullptr, nullptr};
1220 int filter;
1221
1222 Scene *scene = ac->scene;
1223 CfraElem *ce;
1224 KeyframeEditFunc select_cb, ok_cb;
1225 KeyframeEditData ked;
1226
1227 /* initialize keyframe editing data */
1228 memset(&ked, 0, sizeof(KeyframeEditData));
1229
1230 /* build list of columns */
1231 switch (mode) {
1232 case GRAPHKEYS_COLUMNSEL_KEYS: /* list of selected keys */
1236 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
1237
1238 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1240 &ked, static_cast<FCurve *>(ale->key_data), nullptr, bezt_to_cfraelem, nullptr);
1241 }
1242
1243 ANIM_animdata_freelist(&anim_data);
1244 break;
1245
1246 case GRAPHKEYS_COLUMNSEL_CFRA: /* current frame */
1247 /* make a single CfraElem for storing this */
1248 ce = static_cast<CfraElem *>(MEM_callocN(sizeof(CfraElem), "cfraElem"));
1249 BLI_addtail(&ked.list, ce);
1250
1251 ce->cfra = float(scene->r.cfra);
1252 break;
1253
1254 case GRAPHKEYS_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */
1255 ED_markers_make_cfra_list(ac->markers, &ked.list, true);
1256 break;
1257
1258 default: /* invalid option */
1259 return;
1260 }
1261
1262 /* set up BezTriple edit callbacks */
1265
1266 /* loop through all of the keys and select additional keyframes
1267 * based on the keys found to be selected above
1268 */
1272 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
1273
1274 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1275 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
1276
1277 /* loop over cfraelems (stored in the KeyframeEditData->list)
1278 * - we need to do this here, as we can apply fewer NLA-mapping conversions
1279 */
1280 LISTBASE_FOREACH (CfraElem *, ce, &ked.list) {
1281 /* set frame for validation callback to refer to */
1283
1284 /* select elements with frame number matching cfraelem */
1286 &ked, static_cast<FCurve *>(ale->key_data), ok_cb, select_cb, nullptr);
1287 }
1288 }
1289
1290 /* free elements */
1291 BLI_freelistN(&ked.list);
1292 ANIM_animdata_freelist(&anim_data);
1293}
1294
1295/* ------------------- */
1296
1298{
1299 bAnimContext ac;
1300 short mode;
1301
1302 /* get editor data */
1303 if (ANIM_animdata_get_context(C, &ac) == 0) {
1304 return OPERATOR_CANCELLED;
1305 }
1306
1307 /* action to take depends on the mode */
1308 mode = RNA_enum_get(op->ptr, "mode");
1309
1312 }
1313 else {
1314 columnselect_graph_keys(&ac, mode);
1315 }
1316
1317 /* set notifier that keyframe selection has changed */
1319
1320 return OPERATOR_FINISHED;
1321}
1322
1324{
1325 /* identifiers */
1326 ot->name = "Select All";
1327 ot->idname = "GRAPH_OT_select_column";
1328 ot->description = "Select all keyframes on the specified frame(s)";
1329
1330 /* api callbacks */
1333
1334 /* flags */
1336
1337 /* props */
1338 ot->prop = RNA_def_enum(ot->srna, "mode", prop_column_select_types, 0, "Mode", "");
1340}
1341
1344/* -------------------------------------------------------------------- */
1349{
1350 bAnimContext ac;
1351
1352 ListBase anim_data = {nullptr, nullptr};
1353 int filter;
1354
1357
1358 /* get editor data */
1359 if (ANIM_animdata_get_context(C, &ac) == 0) {
1360 return OPERATOR_CANCELLED;
1361 }
1362
1363 /* loop through all of the keys and select additional keyframes based on these */
1367 &ac, &anim_data, eAnimFilter_Flags(filter), ac.data, eAnimCont_Types(ac.datatype));
1368
1369 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1370 FCurve *fcu = (FCurve *)ale->key_data;
1371
1372 /* check if anything selected? */
1373 if (ANIM_fcurve_keyframes_loop(nullptr, fcu, nullptr, ok_cb, nullptr)) {
1374 /* select every keyframe in this curve then */
1375 ANIM_fcurve_keyframes_loop(nullptr, fcu, nullptr, sel_cb, nullptr);
1376 }
1377 }
1378
1379 /* Cleanup */
1380 ANIM_animdata_freelist(&anim_data);
1381
1382 /* set notifier that keyframe selection has changed */
1384
1385 return OPERATOR_FINISHED;
1386}
1387
1389{
1390 /* identifiers */
1391 ot->name = "Select Linked";
1392 ot->idname = "GRAPH_OT_select_linked";
1393 ot->description = "Select keyframes occurring in the same F-Curves as selected ones";
1394
1395 /* api callbacks */
1398
1399 /* flags */
1401}
1402
1405/* -------------------------------------------------------------------- */
1409/* Common code to perform selection */
1410static void select_moreless_graph_keys(bAnimContext *ac, short mode)
1411{
1412 ListBase anim_data = {nullptr, nullptr};
1413 int filter;
1414
1415 KeyframeEditData ked;
1416 KeyframeEditFunc build_cb;
1417
1418 /* init selmap building data */
1419 build_cb = ANIM_editkeyframes_buildselmap(mode);
1420 memset(&ked, 0, sizeof(KeyframeEditData));
1421
1422 /* loop through all of the keys and select additional keyframes based on these */
1426 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
1427
1428 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1429 FCurve *fcu = (FCurve *)ale->key_data;
1430
1431 /* only continue if F-Curve has keyframes */
1432 if (fcu->bezt == nullptr) {
1433 continue;
1434 }
1435
1436 /* build up map of whether F-Curve's keyframes should be selected or not */
1437 ked.data = MEM_callocN(fcu->totvert, "selmap graphEdit");
1438 ANIM_fcurve_keyframes_loop(&ked, fcu, nullptr, build_cb, nullptr);
1439
1440 /* based on this map, adjust the selection status of the keyframes */
1441 ANIM_fcurve_keyframes_loop(&ked, fcu, nullptr, bezt_selmap_flush, nullptr);
1442
1443 /* free the selmap used here */
1444 MEM_freeN(ked.data);
1445 ked.data = nullptr;
1446 }
1447
1448 /* Cleanup */
1449 ANIM_animdata_freelist(&anim_data);
1450}
1451
1452/* ----------------- */
1453
1455{
1456 bAnimContext ac;
1457
1458 /* get editor data */
1459 if (ANIM_animdata_get_context(C, &ac) == 0) {
1460 return OPERATOR_CANCELLED;
1461 }
1462
1463 /* perform select changes */
1465
1466 /* set notifier that keyframe selection has changed */
1468
1469 return OPERATOR_FINISHED;
1470}
1471
1473{
1474 /* identifiers */
1475 ot->name = "Select More";
1476 ot->idname = "GRAPH_OT_select_more";
1477 ot->description = "Select keyframes beside already selected ones";
1478
1479 /* api callbacks */
1482
1483 /* flags */
1485}
1486
1487/* ----------------- */
1488
1490{
1491 bAnimContext ac;
1492
1493 /* get editor data */
1494 if (ANIM_animdata_get_context(C, &ac) == 0) {
1495 return OPERATOR_CANCELLED;
1496 }
1497
1498 /* perform select changes */
1500
1501 /* set notifier that keyframe selection has changed */
1503
1504 return OPERATOR_FINISHED;
1505}
1506
1508{
1509 /* identifiers */
1510 ot->name = "Select Less";
1511 ot->idname = "GRAPH_OT_select_less";
1512 ot->description = "Deselect keyframes on ends of selection islands";
1513
1514 /* api callbacks */
1517
1518 /* flags */
1520}
1521
1524/* -------------------------------------------------------------------- */
1530/* defines for left-right select tool */
1532 {GRAPHKEYS_LRSEL_TEST, "CHECK", 0, "Check if Select Left or Right", ""},
1533 {GRAPHKEYS_LRSEL_LEFT, "LEFT", 0, "Before Current Frame", ""},
1534 {GRAPHKEYS_LRSEL_RIGHT, "RIGHT", 0, "After Current Frame", ""},
1535 {0, nullptr, 0, nullptr, nullptr},
1536};
1537
1538/* --------------------------------- */
1539
1541 short leftright,
1542 eEditKeyframes_Select select_mode)
1543{
1544 ListBase anim_data = {nullptr, nullptr};
1545 int filter;
1546
1547 KeyframeEditFunc ok_cb, select_cb;
1548 KeyframeEditData ked = {{nullptr}};
1549 Scene *scene = ac->scene;
1550
1551 /* if select mode is replace, deselect all keyframes (and channels) first */
1552 if (select_mode == SELECT_REPLACE) {
1553 select_mode = SELECT_ADD;
1554
1555 /* - deselect all other keyframes, so that just the newly selected remain
1556 * - channels aren't deselected, since we don't re-select any as a consequence
1557 */
1558 deselect_graph_keys(ac, false, SELECT_SUBTRACT, false);
1559 }
1560
1561 /* set callbacks and editing data */
1563 select_cb = ANIM_editkeyframes_select(select_mode);
1564
1565 if (leftright == GRAPHKEYS_LRSEL_LEFT) {
1566 ked.f1 = MINAFRAMEF;
1567 ked.f2 = float(scene->r.cfra + 0.1f);
1568 }
1569 else {
1570 ked.f1 = float(scene->r.cfra - 0.1f);
1571 ked.f2 = MAXFRAMEF;
1572 }
1573
1574 /* filter data */
1577 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
1578
1579 /* select keys */
1580 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1581 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
1582
1583 if (adt) {
1584 ANIM_nla_mapping_apply_fcurve(adt, static_cast<FCurve *>(ale->key_data), false, true);
1586 &ked, static_cast<FCurve *>(ale->key_data), ok_cb, select_cb, nullptr);
1587 ANIM_nla_mapping_apply_fcurve(adt, static_cast<FCurve *>(ale->key_data), true, true);
1588 }
1589 else {
1591 &ked, static_cast<FCurve *>(ale->key_data), ok_cb, select_cb, nullptr);
1592 }
1593 }
1594
1595 /* Cleanup */
1596 ANIM_animdata_freelist(&anim_data);
1597}
1598
1599/* ----------------- */
1600
1602{
1603 bAnimContext ac;
1604 short leftright = RNA_enum_get(op->ptr, "mode");
1605 eEditKeyframes_Select selectmode;
1606
1607 /* get editor data */
1608 if (ANIM_animdata_get_context(C, &ac) == 0) {
1609 return OPERATOR_CANCELLED;
1610 }
1611
1612 /* select mode is either replace (deselect all, then add) or add/extend */
1613 if (RNA_boolean_get(op->ptr, "extend")) {
1614 selectmode = SELECT_INVERT;
1615 }
1616 else {
1617 selectmode = SELECT_REPLACE;
1618 }
1619
1620 /* if "test" mode is set, we don't have any info to set this with */
1621 if (leftright == GRAPHKEYS_LRSEL_TEST) {
1622 return OPERATOR_CANCELLED;
1623 }
1624
1625 /* do the selecting now */
1626 graphkeys_select_leftright(&ac, leftright, selectmode);
1627
1628 /* set notifier that keyframe selection (and channels too) have changed */
1631
1632 return OPERATOR_FINISHED;
1633}
1634
1636{
1637 bAnimContext ac;
1638 short leftright = RNA_enum_get(op->ptr, "mode");
1639
1640 /* get editor data */
1641 if (ANIM_animdata_get_context(C, &ac) == 0) {
1642 return OPERATOR_CANCELLED;
1643 }
1644
1645 /* handle mode-based testing */
1646 if (leftright == GRAPHKEYS_LRSEL_TEST) {
1647 Scene *scene = ac.scene;
1648 ARegion *region = ac.region;
1649 View2D *v2d = &region->v2d;
1650 float x;
1651
1652 /* determine which side of the current frame mouse is on */
1653 x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
1654 if (x < scene->r.cfra) {
1656 }
1657 else {
1659 }
1660 }
1661
1662 /* perform selection */
1663 return graphkeys_select_leftright_exec(C, op);
1664}
1665
1667{
1668 PropertyRNA *prop;
1669
1670 /* identifiers */
1671 ot->name = "Select Left/Right";
1672 ot->idname = "GRAPH_OT_select_leftright";
1673 ot->description = "Select keyframes to the left or the right of the current frame";
1674
1675 /* api callbacks */
1679
1680 /* flags */
1682
1683 /* id-props */
1684 ot->prop = RNA_def_enum(
1687
1688 prop = RNA_def_boolean(ot->srna, "extend", false, "Extend Select", "");
1690}
1691
1694/* -------------------------------------------------------------------- */
1706/* option 1) select keyframe directly under mouse */
1708 const int mval[2],
1709 eEditKeyframes_Select select_mode,
1710 const bool deselect_all,
1711 const bool curves_only,
1712 bool wait_to_deselect_others)
1713{
1714 SpaceGraph *sipo = (SpaceGraph *)ac->sl;
1715 tNearestVertInfo *nvi;
1716 BezTriple *bezt = nullptr;
1717 bool run_modal = false;
1718
1719 /* find the beztriple that we're selecting, and the handle that was clicked on */
1720 nvi = find_nearest_fcurve_vert(ac, mval);
1721
1722 if (select_mode != SELECT_REPLACE) {
1723 /* The modal execution to delay deselecting other items is only needed for normal click
1724 * selection, i.e. for SELECT_REPLACE. */
1725 wait_to_deselect_others = false;
1726 }
1727
1730
1731 const bool already_selected =
1732 (nvi != nullptr) && (((nvi->hpoint == NEAREST_HANDLE_KEY) && (nvi->bezt->f2 & SELECT)) ||
1733 ((nvi->hpoint == NEAREST_HANDLE_LEFT) && (nvi->bezt->f1 & SELECT)) ||
1734 ((nvi->hpoint == NEAREST_HANDLE_RIGHT) && (nvi->bezt->f3 & SELECT)));
1735
1736 if (wait_to_deselect_others && nvi && already_selected) {
1737 run_modal = true;
1738 }
1739 /* For replacing selection, if we have something to select, we have to clear existing selection.
1740 * The same goes if we found nothing to select, and deselect_all is true
1741 * (deselect on nothing behavior). */
1742 else if ((nvi != nullptr && select_mode == SELECT_REPLACE) || (nvi == nullptr && deselect_all)) {
1743 /* reset selection mode */
1744 select_mode = SELECT_ADD;
1745
1746 /* deselect all other keyframes (+ F-Curves too) */
1747 deselect_graph_keys(ac, false, SELECT_SUBTRACT, true);
1748
1749 /* Deselect other channels too, but only do this if selection of channel
1750 * when the visibility of keyframes doesn't depend on this. */
1751 if ((U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) == 0) {
1753 }
1754 }
1755
1756 if (nvi == nullptr) {
1757 return deselect_all ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1758 }
1759
1760 /* if points can be selected on this F-Curve */
1761 /* TODO: what about those with no keyframes? */
1762 bool something_was_selected = false;
1763 if (!curves_only && ((nvi->fcu->flag & FCURVE_PROTECTED) == 0)) {
1764 /* only if there's keyframe */
1765 if (nvi->bezt) {
1766 bezt = nvi->bezt; /* Used to check `bezt` selection is set. */
1767 if (select_mode == SELECT_INVERT) {
1768 if (nvi->hpoint == NEAREST_HANDLE_KEY) {
1769 bezt->f2 ^= SELECT;
1770 something_was_selected = (bezt->f2 & SELECT);
1771 }
1772 else if (nvi->hpoint == NEAREST_HANDLE_LEFT) {
1773 /* toggle selection */
1774 bezt->f1 ^= SELECT;
1775 something_was_selected = (bezt->f1 & SELECT);
1776 }
1777 else {
1778 /* toggle selection */
1779 bezt->f3 ^= SELECT;
1780 something_was_selected = (bezt->f3 & SELECT);
1781 }
1782 }
1783 else {
1784 if (nvi->hpoint == NEAREST_HANDLE_KEY) {
1785 bezt->f2 |= SELECT;
1786 }
1787 else if (nvi->hpoint == NEAREST_HANDLE_LEFT) {
1788 bezt->f1 |= SELECT;
1789 }
1790 else {
1791 bezt->f3 |= SELECT;
1792 }
1793 something_was_selected = true;
1794 }
1795
1796 if (!run_modal && BEZT_ISSEL_ANY(bezt)) {
1797 const bool may_activate = !already_selected ||
1800 if (may_activate) {
1802 }
1803 }
1804 }
1805 else if (nvi->fpt) {
1806 /* TODO: need to handle sample points */
1807 }
1808 }
1809 else {
1810 KeyframeEditFunc select_cb;
1811 KeyframeEditData ked;
1812
1813 /* initialize keyframe editing data */
1814 memset(&ked, 0, sizeof(KeyframeEditData));
1815
1816 /* set up BezTriple edit callbacks */
1817 select_cb = ANIM_editkeyframes_select(select_mode);
1818
1819 /* select all keyframes */
1820 ANIM_fcurve_keyframes_loop(&ked, nvi->fcu, nullptr, select_cb, nullptr);
1821 }
1822
1823 /* only change selection of channel when the visibility of keyframes doesn't depend on this */
1824 if ((U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) == 0) {
1825 /* select or deselect curve? */
1826 if (bezt) {
1827 /* take selection status from item that got hit, to prevent flip/flop on channel
1828 * selection status when shift-selecting (i.e. "SELECT_INVERT") points
1829 */
1830 if (BEZT_ISSEL_ANY(bezt)) {
1831 nvi->fcu->flag |= FCURVE_SELECTED;
1832 }
1833 else {
1834 nvi->fcu->flag &= ~FCURVE_SELECTED;
1835 }
1836 }
1837 else {
1838 /* Didn't hit any channel,
1839 * so just apply that selection mode to the curve's selection status. */
1840 if (select_mode == SELECT_INVERT) {
1841 nvi->fcu->flag ^= FCURVE_SELECTED;
1842 }
1843 else if (select_mode == SELECT_ADD) {
1844 nvi->fcu->flag |= FCURVE_SELECTED;
1845 }
1846 }
1847 }
1848
1849 /* Set active F-Curve when something was actually selected (so not on a deselect), except when
1850 * dragging the selected keys. Needs to be called with (sipo->flag & SIPO_SELCUVERTSONLY),
1851 * otherwise the active flag won't be set #26452. */
1852 if (!run_modal && (nvi->fcu->flag & FCURVE_SELECTED) && something_was_selected) {
1853 /* NOTE: Sync the filter flags with findnearest_fcurve_vert. */
1857 ac->data,
1859 eAnimFilter_Flags(filter),
1860 nvi->fcu,
1861 nvi->ctype);
1862 }
1863
1864 if (nvi->hpoint == NEAREST_HANDLE_LEFT) {
1866 }
1867 else if (nvi->hpoint == NEAREST_HANDLE_RIGHT) {
1869 }
1870
1871 /* free temp sample data for filtering */
1872 MEM_freeN(nvi);
1873
1874 return run_modal ? OPERATOR_RUNNING_MODAL : OPERATOR_FINISHED;
1875}
1876
1877/* Option 2) Selects all the keyframes on either side of the current frame
1878 * (depends on which side the mouse is on) */
1879/* (see graphkeys_select_leftright) */
1880
1881/* Option 3) Selects all visible keyframes in the same frame as the mouse click */
1883 const int mval[2],
1884 eEditKeyframes_Select select_mode,
1885 bool wait_to_deselect_others)
1886{
1887 ListBase anim_data = {nullptr, nullptr};
1888 int filter;
1889 bool run_modal = false;
1890
1891 KeyframeEditFunc select_cb, ok_cb;
1892 KeyframeEditData ked;
1893 tNearestVertInfo *nvi;
1894
1895 /* find the beztriple that we're selecting, and the handle that was clicked on */
1896 nvi = find_nearest_fcurve_vert(ac, mval);
1897
1898 /* check if anything to select */
1899 if (nvi == nullptr) {
1900 return OPERATOR_CANCELLED;
1901 }
1902
1903 /* get frame number on which elements should be selected */
1904 /* TODO: should we restrict to integer frames only? */
1905 const float selx = nvi->frame;
1906
1907 if (select_mode != SELECT_REPLACE) {
1908 /* Doesn't need to deselect anything -> Pass. */
1909 }
1910 else if (wait_to_deselect_others && (nvi->bezt->f2 & SELECT)) {
1911 run_modal = true;
1912 }
1913 /* If select mode is replace (and we don't do delayed deselection on mouse release), deselect all
1914 * keyframes first. */
1915 else {
1916 /* reset selection mode to add to selection */
1917 select_mode = SELECT_ADD;
1918
1919 /* - deselect all other keyframes, so that just the newly selected remain
1920 * - channels aren't deselected, since we don't re-select any as a consequence
1921 */
1922 deselect_graph_keys(ac, false, SELECT_SUBTRACT, false);
1923 }
1924
1925 /* initialize keyframe editing data */
1926 memset(&ked, 0, sizeof(KeyframeEditData));
1927
1928 /* set up BezTriple edit callbacks */
1929 select_cb = ANIM_editkeyframes_select(select_mode);
1931
1932 /* loop through all of the keys and select additional keyframes
1933 * based on the keys found to be selected above
1934 */
1938 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
1939
1940 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1941 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
1942
1943 /* set frame for validation callback to refer to */
1944 if (adt) {
1946 }
1947 else {
1948 ked.f1 = selx;
1949 }
1950
1951 /* select elements with frame number matching cfra */
1953 &ked, static_cast<FCurve *>(ale->key_data), ok_cb, select_cb, nullptr);
1954 }
1955
1956 /* free elements */
1957 MEM_freeN(nvi);
1958 BLI_freelistN(&ked.list);
1959 ANIM_animdata_freelist(&anim_data);
1960
1961 return run_modal ? OPERATOR_RUNNING_MODAL : OPERATOR_FINISHED;
1962}
1963
1966/* -------------------------------------------------------------------- */
1971{
1972 bAnimContext ac;
1973
1974 /* get editor data */
1975 if (ANIM_animdata_get_context(C, &ac) == 0) {
1976 return OPERATOR_CANCELLED;
1977 }
1978
1979 /* select mode is either replace (deselect all, then add) or add/extend */
1980 const short selectmode = RNA_boolean_get(op->ptr, "extend") ? SELECT_INVERT : SELECT_REPLACE;
1981 const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
1982 /* See #WM_operator_properties_generic_select() for a detailed description of the how and why of
1983 * this. */
1984 const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
1985 int mval[2];
1986 int ret_val;
1987
1988 mval[0] = RNA_int_get(op->ptr, "mouse_x");
1989 mval[1] = RNA_int_get(op->ptr, "mouse_y");
1990
1991 /* figure out action to take */
1992 if (RNA_boolean_get(op->ptr, "column")) {
1993 /* select all keyframes in the same frame as the one that was under the mouse */
1994 ret_val = graphkeys_mselect_column(
1995 &ac, mval, eEditKeyframes_Select(selectmode), wait_to_deselect_others);
1996 }
1997 else if (RNA_boolean_get(op->ptr, "curves")) {
1998 /* select all keyframes in the same F-Curve as the one under the mouse */
1999 ret_val = mouse_graph_keys(
2000 &ac, mval, eEditKeyframes_Select(selectmode), deselect_all, true, wait_to_deselect_others);
2001 }
2002 else {
2003 /* select keyframe under mouse */
2004 ret_val = mouse_graph_keys(&ac,
2005 mval,
2006 eEditKeyframes_Select(selectmode),
2007 deselect_all,
2008 false,
2009 wait_to_deselect_others);
2010 }
2011
2012 /* set notifier that keyframe selection (and also channel selection in some cases) has
2013 * changed */
2016
2017 /* for tweak grab to work */
2018 return ret_val | OPERATOR_PASS_THROUGH;
2019}
2020
2022{
2023 PropertyRNA *prop;
2024
2025 /* identifiers */
2026 ot->name = "Select Keyframes";
2027 ot->idname = "GRAPH_OT_clickselect";
2028 ot->description = "Select keyframes by clicking on them";
2029
2030 /* callbacks */
2035
2036 /* flags */
2037 ot->flag = OPTYPE_UNDO;
2038
2039 /* properties */
2041
2042 /* Key-map: Enable with `Shift`. */
2043 prop = RNA_def_boolean(ot->srna,
2044 "extend",
2045 false,
2046 "Extend Select",
2047 "Toggle keyframe selection instead of leaving newly selected "
2048 "keyframes only");
2050
2051 prop = RNA_def_boolean(ot->srna,
2052 "deselect_all",
2053 false,
2054 "Deselect On Nothing",
2055 "Deselect all when nothing under the cursor");
2057
2058 /* Key-map: Enable with `Alt`. */
2059 prop = RNA_def_boolean(ot->srna,
2060 "column",
2061 false,
2062 "Column Select",
2063 "Select all keyframes that occur on the same frame as the one under "
2064 "the mouse");
2066
2067 /* Key-map: Enable with `Ctrl-Atl`. */
2068 prop = RNA_def_boolean(
2069 ot->srna, "curves", false, "Only Curves", "Select all the keyframes in the curve");
2071}
2072
2075/* -------------------------------------------------------------------- */
2079/* Defines for key/handles select tool. */
2081 {GRAPHKEYS_KEYHANDLESSEL_SELECT, "SELECT", 0, "Select", ""},
2082 {GRAPHKEYS_KEYHANDLESSEL_DESELECT, "DESELECT", 0, "Deselect", ""},
2083 {GRAPHKEYS_KEYHANDLESSEL_KEEP, "KEEP", 0, "Keep", "Leave as is"},
2084 {0, nullptr, 0, nullptr, nullptr},
2085};
2086
2098 bAnimContext *ac,
2099 const enum eGraphKey_SelectKeyHandles_Action left_handle_action,
2100 const enum eGraphKey_SelectKeyHandles_Action key_action,
2101 const enum eGraphKey_SelectKeyHandles_Action right_handle_action)
2102{
2103 ListBase anim_data = {nullptr, nullptr};
2104
2108 ac, &anim_data, filter, ac->data, static_cast<eAnimCont_Types>(ac->datatype));
2109 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
2110 BLI_assert(ale->type & ANIMTYPE_FCURVE);
2111 FCurve *fcu = (FCurve *)ale->key_data;
2112
2113 /* Only continue if F-Curve has keyframes. */
2114 if (fcu->bezt == nullptr) {
2115 continue;
2116 }
2117
2118 for (int i = 0; i < fcu->totvert; i++) {
2119 BezTriple *bezt = &fcu->bezt[i];
2120
2121 if (!BEZT_ISSEL_ANY(bezt)) {
2122 continue;
2123 }
2124
2125 switch (left_handle_action) {
2127 BEZT_SEL_IDX(bezt, 0);
2128 break;
2130 BEZT_DESEL_IDX(bezt, 0);
2131 break;
2133 /* Do nothing. */
2134 break;
2135 }
2136
2137 switch (key_action) {
2139 BEZT_SEL_IDX(bezt, 1);
2140 break;
2142 BEZT_DESEL_IDX(bezt, 1);
2143 break;
2145 /* Do nothing. */
2146 break;
2147 }
2148
2149 switch (right_handle_action) {
2151 BEZT_SEL_IDX(bezt, 2);
2152 break;
2154 BEZT_DESEL_IDX(bezt, 2);
2155 break;
2157 /* Do nothing. */
2158 break;
2159 }
2160 }
2161 }
2162
2163 /* Cleanup */
2164 ANIM_animdata_freelist(&anim_data);
2165}
2166
2168{
2169 bAnimContext ac;
2170
2171 /* Get editor data. */
2172 if (ANIM_animdata_get_context(C, &ac) == 0) {
2173 return OPERATOR_CANCELLED;
2174 }
2175
2176 const eGraphKey_SelectKeyHandles_Action left_handle_action =
2177 static_cast<eGraphKey_SelectKeyHandles_Action>(RNA_enum_get(op->ptr, "left_handle_action"));
2178 const eGraphKey_SelectKeyHandles_Action key_action =
2179 static_cast<eGraphKey_SelectKeyHandles_Action>(RNA_enum_get(op->ptr, "key_action"));
2180 const eGraphKey_SelectKeyHandles_Action right_handle_action =
2181 static_cast<eGraphKey_SelectKeyHandles_Action>(RNA_enum_get(op->ptr, "right_handle_action"));
2182
2183 graphkeys_select_key_handles(&ac, left_handle_action, key_action, right_handle_action);
2184
2186
2187 return OPERATOR_FINISHED;
2188}
2189
2191{
2192 /* identifiers */
2193 ot->name = "Select Key / Handles";
2194 ot->idname = "GRAPH_OT_select_key_handles";
2195 ot->description =
2196 "For selected keyframes, select/deselect any combination of the key itself and its handles";
2197
2198 /* callbacks */
2201
2202 /* flags */
2204
2206 "left_handle_action",
2209 "Left Handle",
2210 "Effect on the left handle");
2212 "right_handle_action",
2215 "Right Handle",
2216 "Effect on the right handle");
2218 "key_action",
2221 "Key",
2222 "Effect on the key itself");
2223}
2224
int BKE_fcurve_active_keyframe_index(const FCurve *fcu)
void BKE_fcurve_active_keyframe_set(FCurve *fcu, const BezTriple *active_bezt)
float evaluate_fcurve(const FCurve *fcu, float evaltime)
float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, short mode)
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:513
#define BLI_assert(a)
Definition BLI_assert.h:50
void BLI_lasso_boundbox(rcti *rect, blender::Span< blender::int2 > mcoords)
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
void void BLI_listbase_rotate_last(struct ListBase *lb, void *vlink) ATTR_NONNULL(1
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void void BLI_INLINE bool BLI_listbase_is_single(const struct ListBase *lb)
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
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:251
MINLINE float len_v2v2_int(const int v1[2], const int v2[2])
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 FCURVE_ACTIVE_KEYFRAME_NONE
@ FCURVE_ACTIVE
@ FCURVE_SELECTED
@ FCURVE_PROTECTED
#define BEZT_DESEL_IDX(bezt, i)
#define BEZT_ISSEL_IDX(bezt, i)
#define BEZT_ISSEL_ANY(bezt)
@ BEZT_IPO_BEZ
#define BEZT_SEL_IDX(bezt, i)
#define MAXFRAMEF
#define MINAFRAMEF
@ SIPO_SELVHANDLESONLY
@ SIPO_NOHANDLES
@ SIPO_RUNTIME_FLAG_TWEAK_HANDLES_RIGHT
@ SIPO_RUNTIME_FLAG_TWEAK_HANDLES_LEFT
@ USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
@ ACHANNEL_SETFLAG_CLEAR
eAnim_ChannelType
@ ANIMTYPE_FCURVE
eAnimCont_Types
eAnimFilter_Flags
@ ANIMFILTER_FOREDIT
@ ANIMFILTER_DATA_VISIBLE
@ ANIMFILTER_CURVE_VISIBLE
@ ANIMFILTER_SELEDIT
@ ANIMFILTER_NODUPLIS
@ ANIMFILTER_FCURVESONLY
@ ANIMFILTER_SEL
@ ANIM_UNITCONV_ONLYKEYS
@ KEYFRAME_OK_KEY
@ KEYFRAME_OK_H1
@ KEYFRAME_OK_H2
@ BEZT_OK_FRAMERANGE
@ BEZT_OK_FRAME
@ BEZT_OK_VALUERANGE
@ BEZT_OK_SELECTED
@ BEZT_OK_REGION_LASSO
@ BEZT_OK_REGION_CIRCLE
@ BEZT_OK_REGION
@ KEYFRAME_ITER_HANDLES_DEFAULT_INVISIBLE
@ KEYFRAME_ITER_INCL_HANDLES
short(*)(KeyframeEditData *ked, BezTriple *bezt) KeyframeEditFunc
@ SELMAP_MORE
@ SELMAP_LESS
eEditKeyframes_Select
@ SELECT_INVERT
@ SELECT_SUBTRACT
@ SELECT_REPLACE
@ SELECT_ADD
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
bool UI_view2d_view_to_region_clip(const View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL()
Definition view2d.cc:1697
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
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
short ANIM_get_normalization_flags(SpaceLink *space_link)
Definition anim_draw.cc:320
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
float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag, float *r_offset)
Definition anim_draw.cc:529
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)
unsigned int U
Definition btGjkEpa3.h:78
#define SELECT
draw_view in_light_buf[] float
@ GRAPHKEYS_COLUMNSEL_MARKERS_BETWEEN
@ GRAPHKEYS_COLUMNSEL_KEYS
@ GRAPHKEYS_COLUMNSEL_MARKERS_COLUMN
@ GRAPHKEYS_COLUMNSEL_CFRA
bool graphop_visible_keyframes_poll(bContext *C)
bAnimListElem * get_active_fcurve_channel(bAnimContext *ac)
eGraphKey_SelectKeyHandles_Action
@ GRAPHKEYS_KEYHANDLESSEL_KEEP
@ GRAPHKEYS_KEYHANDLESSEL_SELECT
@ GRAPHKEYS_KEYHANDLESSEL_DESELECT
@ GRAPHKEYS_LRSEL_TEST
@ GRAPHKEYS_LRSEL_RIGHT
@ GRAPHKEYS_LRSEL_LEFT
static void initialize_box_select_key_editing_data(const bool incl_handles, const short mode, bAnimContext *ac, void *data, rctf *scaled_rectf, KeyframeEditData *r_ked, int *r_mapping_flag)
#define INSIDE
void GRAPH_OT_select_box(wmOperatorType *ot)
static int graphkeys_box_select_exec(bContext *C, wmOperator *op)
void GRAPH_OT_select_column(wmOperatorType *ot)
static void nearest_fcurve_vert_store(ListBase *matches, View2D *v2d, FCurve *fcu, eAnim_ChannelType ctype, BezTriple *bezt, FPoint *fpt, short hpoint, const int mval[2], float unit_scale, float offset)
static int graphkeys_select_linked_exec(bContext *C, wmOperator *)
#define BELOW
static tNearestVertInfo * get_best_nearest_fcurve_vert(ListBase *matches)
static void graphkeys_select_key_handles(bAnimContext *ac, const enum eGraphKey_SelectKeyHandles_Action left_handle_action, const enum eGraphKey_SelectKeyHandles_Action key_action, const enum eGraphKey_SelectKeyHandles_Action right_handle_action)
static rctf initialize_box_select_coords(const bAnimContext *ac, const rctf *rectf_view)
static const EnumPropertyItem prop_graphkeys_select_key_handles_actions[]
static int graphkeys_clickselect_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem prop_graphkeys_leftright_select_types[]
static short ok_bezier_always_ok(KeyframeEditData *, BezTriple *)
void GRAPH_OT_select_lasso(wmOperatorType *ot)
static int graphkeys_select_leftright_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int graphkeys_select_less_exec(bContext *C, wmOperator *)
static bool rectf_curve_intersection(const float offset, const float unit_scale, const rctf *rectf, AnimData *adt, const FCurve *fcu)
static void box_select_graphcurves(bAnimContext *ac, const rctf *rectf_view, const short mode, const eEditKeyframes_Select selectmode, const bool incl_handles, void *data)
static bool box_select_graphkeys(bAnimContext *ac, const rctf *rectf_view, short mode, eEditKeyframes_Select selectmode, bool incl_handles, void *data)
#define ABOVE
static int graphkeys_select_leftright_exec(bContext *C, wmOperator *op)
static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
void GRAPH_OT_select_circle(wmOperatorType *ot)
void GRAPH_OT_clickselect(wmOperatorType *ot)
static int graphkeys_mselect_column(bAnimContext *ac, const int mval[2], eEditKeyframes_Select select_mode, bool wait_to_deselect_others)
void GRAPH_OT_select_more(wmOperatorType *ot)
static void graphkeys_select_leftright(bAnimContext *ac, short leftright, eEditKeyframes_Select select_mode)
static int graphkeys_deselectall_exec(bContext *C, wmOperator *op)
static int mouse_graph_keys(bAnimContext *ac, const int mval[2], eEditKeyframes_Select select_mode, const bool deselect_all, const bool curves_only, bool wait_to_deselect_others)
#define GVERTSEL_TOL
static int graphkeys_select_more_exec(bContext *C, wmOperator *)
void GRAPH_OT_select_linked(wmOperatorType *ot)
static tNearestVertInfo * find_nearest_fcurve_vert(bAnimContext *ac, const int mval[2])
static int rectf_curve_zone_y(const FCurve *fcu, const rctf *rectf, const float offset, const float unit_scale, const float eval_x)
static void markers_selectkeys_between(bAnimContext *ac)
void deselect_graph_keys(bAnimContext *ac, bool test, eEditKeyframes_Select sel, bool do_channels)
void GRAPH_OT_select_key_handles(wmOperatorType *ot)
static int graphkeys_select_key_handles_exec(bContext *C, wmOperator *op)
static int graph_circle_select_exec(bContext *C, wmOperator *op)
static int initialize_animdata_selection_filter()
void GRAPH_OT_select_leftright(wmOperatorType *ot)
static int graphkeys_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static ListBase initialize_box_select_anim_data(const int filter, bAnimContext *ac)
eGraphVertIndex
@ NEAREST_HANDLE_LEFT
@ NEAREST_HANDLE_KEY
@ NEAREST_HANDLE_RIGHT
static bool fcurve_handle_sel_check(SpaceGraph *sipo, BezTriple *bezt)
static void select_moreless_graph_keys(bAnimContext *ac, short mode)
void GRAPH_OT_select_all(wmOperatorType *ot)
static const EnumPropertyItem prop_column_select_types[]
static void columnselect_graph_keys(bAnimContext *ac, short mode)
static void get_nearest_fcurve_verts_list(bAnimContext *ac, const int mval[2], ListBase *matches)
static int graphkeys_columnselect_exec(bContext *C, wmOperator *op)
void GRAPH_OT_select_less(wmOperatorType *ot)
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
short bezt_selmap_flush(KeyframeEditData *ked, BezTriple *bezt)
short bezt_to_cfraelem(KeyframeEditData *ked, BezTriple *bezt)
KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode)
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 MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
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
float vec[3][3]
FPoint * fpt
BezTriple * bezt
unsigned int totvert
eKeyframeIterFlags iterflags
void * last
SpaceGraph_Runtime runtime
SpaceLink * sl
ListBase * markers
eAnimCont_Types datatype
ARegion * region
float xmax
float xmin
float ymax
float ymin
BezTriple * bezt
eAnim_ChannelType ctype
tNearestVertInfo * next
tNearestVertInfo * prev
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)