Blender V5.0
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
8
9#include <cfloat>
10#include <cstdlib>
11#include <cstring>
12
13#include "MEM_guardedalloc.h"
14
15#include "BLI_lasso_2d.hh"
16#include "BLI_listbase.h"
17#include "BLI_math_vector.h"
18
19#include "DNA_anim_types.h"
20#include "DNA_scene_types.h"
21#include "DNA_screen_types.h"
22#include "DNA_space_types.h"
23
24#include "RNA_access.hh"
25#include "RNA_define.hh"
26
27#include "BKE_fcurve.hh"
28#include "BKE_nla.hh"
29
30#include "UI_interface_c.hh"
31#include "UI_view2d.hh"
32
33#include "ED_anim_api.hh"
34#include "ED_keyframes_edit.hh"
35#include "ED_markers.hh"
36#include "ED_select_utils.hh"
37
38#include "WM_api.hh"
39#include "WM_types.hh"
40
41#include "graph_intern.hh"
42
43/* -------------------------------------------------------------------- */
46
47/* temp info for caching handle vertices close */
50
51 FCurve *fcu; /* F-Curve that keyframe comes from */
52
53 BezTriple *bezt; /* keyframe to consider */
54 FPoint *fpt; /* sample point to consider */
55
56 short hpoint; /* the handle index that we hit (eHandleIndex) */
57 short sel; /* whether the handle is selected or not */
58 int dist; /* distance from mouse to vert */
59
60 eAnim_ChannelType ctype; /* type of animation channel this FCurve comes from */
61
62 float frame; /* frame that point was on when it matched (global time) */
63};
64
65/* Tags for the type of graph vert that we have */
71
72/* Tolerance for absolute radius (in pixels) of the vert from the cursor to use */
73/* TODO: perhaps this should depend a bit on the size that the user set the vertices to be? */
74#define GVERTSEL_TOL (10 * U.pixelsize)
75
76/* ....... */
77
78/* check if its ok to select a handle */
79/* XXX also need to check for int-values only? */
81{
82 if (sipo->flag & SIPO_NOHANDLES) {
83 return false;
84 }
85 if ((sipo->flag & SIPO_SELVHANDLESONLY) && BEZT_ISSEL_ANY(bezt) == 0) {
86 return false;
87 }
88 return true;
89}
90
91/* check if the given vertex is within bounds or not */
92/* TODO: should we return if we hit something? */
94 View2D *v2d,
95 FCurve *fcu,
97 BezTriple *bezt,
98 FPoint *fpt,
99 short hpoint,
100 const int mval[2],
101 float unit_scale,
102 float offset)
103{
104 /* Keyframes or Samples? */
105 if (bezt) {
106 int screen_co[2], dist;
107
108 /* convert from data-space to screen coordinates
109 * NOTE: `hpoint +1` gives us 0,1,2 respectively for each handle,
110 * needed to access the relevant vertex coordinates in the 3x3 'vec' matrix */
112 bezt->vec[hpoint + 1][0],
113 (bezt->vec[hpoint + 1][1] + offset) * unit_scale,
114 &screen_co[0],
115 &screen_co[1]) &&
116 /* check if distance from mouse cursor to vert in screen space is within tolerance */
117 ((dist = len_v2v2_int(mval, screen_co)) <= GVERTSEL_TOL))
118 {
119 tNearestVertInfo *nvi = (tNearestVertInfo *)matches->last;
120 bool replace = false;
121
122 /* If there is already a point for the F-Curve,
123 * check if this point is closer than that was. */
124 if ((nvi) && (nvi->fcu == fcu)) {
125 /* replace if we are closer, or if equal and that one wasn't selected but we are... */
126 if ((nvi->dist > dist) || ((nvi->sel == 0) && BEZT_ISSEL_ANY(bezt))) {
127 replace = true;
128 }
129 }
130 /* add new if not replacing... */
131 if (replace == 0) {
132 nvi = MEM_callocN<tNearestVertInfo>("Nearest Graph Vert Info - Bezt");
133 }
134
135 /* store values */
136 nvi->fcu = fcu;
137 nvi->ctype = ctype;
138
139 nvi->bezt = bezt;
140 nvi->hpoint = hpoint;
141 nvi->dist = dist;
142
143 nvi->frame = bezt->vec[1][0]; /* currently in global time... */
144
145 /* NOTE: `hpoint` is -1,0,1, but `BEZT_ISSEL_IDX` expects 0,1,2. */
146 nvi->sel = BEZT_ISSEL_IDX(bezt, hpoint + 1);
147
148 /* add to list of matches if appropriate... */
149 if (replace == 0) {
150 BLI_addtail(matches, nvi);
151 }
152 }
153 }
154 else if (fpt) {
155 /* TODO: support #FPoint. */
156 }
157}
158
159/* helper for find_nearest_fcurve_vert() - build the list of nearest matches */
160static void get_nearest_fcurve_verts_list(bAnimContext *ac, const int mval[2], ListBase *matches)
161{
162 ListBase anim_data = {nullptr, nullptr};
163 int filter;
164
165 SpaceGraph *sipo = (SpaceGraph *)ac->sl;
166 View2D *v2d = &ac->region->v2d;
167 short mapping_flag = 0;
168
169 /* get curves to search through
170 * - if the option to only show keyframes that belong to selected F-Curves is enabled,
171 * include the 'only selected' flag...
172 */
175 /* FIXME: this should really be check for by the filtering code. */
176 if (U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) {
178 }
179 mapping_flag |= ANIM_get_normalization_flags(ac->sl);
181 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
182
183 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
184 FCurve *fcu = (FCurve *)ale->key_data;
185 float offset;
186 float unit_scale = ANIM_unit_mapping_get_factor(
187 ac->scene, ale->id, fcu, mapping_flag, &offset);
188
189 /* apply NLA mapping to all the keyframes */
191 ale, static_cast<FCurve *>(ale->key_data), false, false);
192
193 if (fcu->bezt) {
194 BezTriple *bezt1 = fcu->bezt, *prevbezt = nullptr;
195 int i;
196
197 for (i = 0; i < fcu->totvert; i++, prevbezt = bezt1, bezt1++) {
198 /* keyframe */
200 v2d,
201 fcu,
202 eAnim_ChannelType(ale->type),
203 bezt1,
204 nullptr,
206 mval,
207 unit_scale,
208 offset);
209
210 /* Handles. */
211 if (fcurve_handle_sel_check(sipo, bezt1)) {
212 /* first handle only visible if previous segment had handles */
213 if ((!prevbezt && (bezt1->ipo == BEZT_IPO_BEZ)) ||
214 (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ)))
215 {
217 v2d,
218 fcu,
219 eAnim_ChannelType(ale->type),
220 bezt1,
221 nullptr,
223 mval,
224 unit_scale,
225 offset);
226 }
227
228 /* second handle only visible if this segment is bezier */
229 if (bezt1->ipo == BEZT_IPO_BEZ) {
231 v2d,
232 fcu,
233 eAnim_ChannelType(ale->type),
234 bezt1,
235 nullptr,
237 mval,
238 unit_scale,
239 offset);
240 }
241 }
242 }
243 }
244 else if (fcu->fpt) {
245 /* TODO: do this for samples too. */
246 }
247
248 /* un-apply NLA mapping from all the keyframes */
250 ale, static_cast<FCurve *>(ale->key_data), true, false);
251 }
252
253 /* free channels */
254 ANIM_animdata_freelist(&anim_data);
255}
256
257/* helper for find_nearest_fcurve_vert() - get the best match to use */
259{
260 /* abort if list is empty */
261 if (BLI_listbase_is_empty(matches)) {
262 return nullptr;
263 }
264
265 /* if list only has 1 item, remove it from the list and return */
266 if (BLI_listbase_is_single(matches)) {
267 /* need to remove from the list, otherwise it gets freed and then we can't return it */
268 return static_cast<tNearestVertInfo *>(BLI_pophead(matches));
269 }
270
271 /* The goal of the remaining code below is to prioritize selecting verts on
272 * selected fcurves, but to still cycle through the vertices in `matches` if
273 * a selected-fcurve vertex is already selected. */
274
275 /* Try to find the first selected vert in `matches`. Additionally, if
276 * one exists, rotate `matches` to put it last in the list and the vert
277 * following it first, since that's the order we'll want to scan in. */
278 tNearestVertInfo *nvi_first_selected = nullptr;
279 LISTBASE_FOREACH (tNearestVertInfo *, nvi, matches) {
280 if (nvi->sel) {
281 nvi_first_selected = nvi;
282 BLI_listbase_rotate_last(matches, nvi_first_selected);
283 break;
284 }
285 }
286
287 /* Try to find the next vert that's on the active fcurve, falling back
288 * to the next vert on any selected fcurve if that's not found. */
289 tNearestVertInfo *nvi_to_select = nullptr;
290 LISTBASE_FOREACH (tNearestVertInfo *, nvi, matches) {
291 if (nvi == nvi_first_selected) {
292 continue;
293 }
294
295 if (nvi->fcu->flag & FCURVE_ACTIVE) {
296 nvi_to_select = nvi;
297 break;
298 }
299
300 if (nvi->fcu->flag & FCURVE_SELECTED && !nvi_to_select) {
301 nvi_to_select = nvi;
302 }
303 }
304
305 /* If we found a vert on a selected fcurve, return it. */
306 if (nvi_to_select) {
307 BLI_remlink(matches, nvi_to_select);
308 return nvi_to_select;
309 }
310
311 /* If we're still here, that means we didn't find any verts on selected
312 * fcurves. So return the head (which is also the item following
313 * `nvi_first_selected` if that was found). */
314 return static_cast<tNearestVertInfo *>(BLI_pophead(matches));
315}
316
324{
325 ListBase matches = {nullptr, nullptr};
326 tNearestVertInfo *nvi;
327
328 /* step 1: get the nearest verts */
329 get_nearest_fcurve_verts_list(ac, mval, &matches);
330
331 /* step 2: find the best vert */
332 nvi = get_best_nearest_fcurve_vert(&matches);
333
334 BLI_freelistN(&matches);
335
336 /* return the best vert found */
337 return nvi;
338}
339
341
342/* -------------------------------------------------------------------- */
350
351void deselect_graph_keys(bAnimContext *ac, bool test, eEditKeyframes_Select sel, bool do_channels)
352{
353 ListBase anim_data = {nullptr, nullptr};
354 int filter;
355
356 KeyframeEditData ked = {{nullptr}};
357 KeyframeEditFunc test_cb, sel_cb;
358
359 /* determine type-based settings */
362
363 /* filter data */
365 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
366
367 /* init BezTriple looping data */
369
370 /* See if we should be selecting or deselecting */
371 if (test) {
372 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
374 &ked, static_cast<FCurve *>(ale->key_data), nullptr, test_cb, nullptr))
375 {
376 sel = SELECT_SUBTRACT;
377 break;
378 }
379 }
380 }
381
382 /* convert sel to selectmode, and use that to get editor */
383 sel_cb = ANIM_editkeyframes_select(sel);
384
385 /* Now set the flags */
386 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
387 FCurve *fcu = (FCurve *)ale->key_data;
388
389 /* Keyframes First */
391 &ked, static_cast<FCurve *>(ale->key_data), nullptr, sel_cb, nullptr);
392
393 /* affect channel selection status? */
394 if (do_channels) {
395 /* Only change selection of channel when the visibility of keyframes
396 * doesn't depend on this. */
397 if ((U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) == 0) {
398 /* deactivate the F-Curve, and deselect if deselecting keyframes.
399 * otherwise select the F-Curve too since we've selected all the keyframes
400 */
401 if (sel == SELECT_SUBTRACT) {
402 fcu->flag &= ~FCURVE_SELECTED;
403 }
404 else {
405 fcu->flag |= FCURVE_SELECTED;
406 }
407 }
408
409 /* always deactivate all F-Curves if we perform batch ops for selection */
410 fcu->flag &= ~FCURVE_ACTIVE;
411 }
412 }
413
414 /* Cleanup */
415 ANIM_animdata_freelist(&anim_data);
416}
417
418/* ------------------- */
419
421{
422 bAnimContext ac;
423 bAnimListElem *ale_active = nullptr;
424
425 /* get editor data */
426 if (ANIM_animdata_get_context(C, &ac) == 0) {
427 return OPERATOR_CANCELLED;
428 }
429
430 /* find active F-Curve, and preserve this for later
431 * or else it becomes annoying with the current active
432 * curve keeps fading out even while you're editing it
433 */
434 ale_active = get_active_fcurve_channel(&ac);
435
436 /* 'standard' behavior - check if selected, then apply relevant selection */
437 const int action = RNA_enum_get(op->ptr, "action");
438 switch (action) {
439 case SEL_TOGGLE:
440 deselect_graph_keys(&ac, true, SELECT_ADD, true);
441 break;
442 case SEL_SELECT:
443 deselect_graph_keys(&ac, false, SELECT_ADD, true);
444 break;
445 case SEL_DESELECT:
446 deselect_graph_keys(&ac, false, SELECT_SUBTRACT, true);
447 break;
448 case SEL_INVERT:
449 deselect_graph_keys(&ac, false, SELECT_INVERT, true);
450 break;
451 default:
452 BLI_assert(0);
453 break;
454 }
455
456 /* restore active F-Curve... */
457 if (ale_active) {
458 FCurve *fcu = (FCurve *)ale_active->data;
459
460 /* all others should not be disabled, so we should be able to just set this directly...
461 * - selection needs to be set too, or else this won't work...
462 */
464
465 MEM_freeN(ale_active);
466 ale_active = nullptr;
467 }
468
469 /* set notifier that things have changed */
471
472 return OPERATOR_FINISHED;
473}
474
476{
477 /* identifiers */
478 ot->name = "Select All";
479 ot->idname = "GRAPH_OT_select_all";
480 ot->description = "Toggle selection of all keyframes";
481
482 /* API callbacks. */
485
486 /* flags */
488
489 /* properties */
491}
492
494
495/* -------------------------------------------------------------------- */
507
508static rctf initialize_box_select_coords(const bAnimContext *ac, const rctf *rectf_view)
509{
510 const View2D *v2d = &ac->region->v2d;
511 rctf rectf;
512
513 /* Convert mouse coordinates to frame ranges and
514 * channel coordinates corrected for view pan/zoom. */
515 UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf);
516 return rectf;
517}
518
528
530{
531 ListBase anim_data = {nullptr, nullptr};
533 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
534 return anim_data;
535}
536
537static void initialize_box_select_key_editing_data(const bool incl_handles,
538 const short mode,
539 bAnimContext *ac,
540 void *data,
541 rctf *scaled_rectf,
542 KeyframeEditData *r_ked,
543 int *r_mapping_flag)
544{
545 memset(r_ked, 0, sizeof(KeyframeEditData));
546 switch (mode) {
548 KeyframeEdit_LassoData *data_lasso = static_cast<KeyframeEdit_LassoData *>(data);
549 data_lasso->rectf_scaled = scaled_rectf;
550 r_ked->data = data_lasso;
551 break;
552 }
554 KeyframeEdit_CircleData *data_circle = static_cast<KeyframeEdit_CircleData *>(data);
555 data_circle->rectf_scaled = scaled_rectf;
556 r_ked->data = data_circle;
557 break;
558 }
559 default:
560 r_ked->data = scaled_rectf;
561 break;
562 }
563 SpaceGraph *sgraph = (SpaceGraph *)ac->sl;
564
565 if (sgraph->flag & SIPO_NOHANDLES) {
567 }
568
569 if (sgraph->flag & SIPO_SELVHANDLESONLY) {
571 }
572
573 /* Consider handles selection. Used in #keyframe_ok_checks, #select_bezier_add,
574 * #select_bezier_subtract. */
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);
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 FCurve *fcu = (FCurve *)ale->key_data;
621 float offset;
622 const float unit_scale = ANIM_unit_mapping_get_factor(
623 ac->scene, ale->id, fcu, mapping_flag, &offset);
624
625 /* Apply NLA mapping to all the keyframes, since it's easier than trying to
626 * guess when a callback might use something different.
627 */
629 ale, static_cast<FCurve *>(ale->key_data), false, (mapping_flag & ANIM_UNITCONV_ONLYKEYS));
630
631 scaled_rectf.xmin = rectf.xmin;
632 scaled_rectf.xmax = rectf.xmax;
633 scaled_rectf.ymin = rectf.ymin / unit_scale - offset;
634 scaled_rectf.ymax = rectf.ymax / unit_scale - offset;
635
636 /* Set horizontal range (if applicable).
637 * NOTE: these values are only used for x-range and y-range but not region
638 * (which uses ked.data, i.e. rectf)
639 */
640 if (mode != BEZT_OK_VALUERANGE) {
641 ked.f1 = rectf.xmin;
642 ked.f2 = rectf.xmax;
643 }
644 else {
645 ked.f1 = rectf.ymin;
646 ked.f2 = rectf.ymax;
647 }
648
649 /* Firstly, check if any keyframes will be hit by this. */
650 if (ANIM_fcurve_keyframes_loop(&ked, fcu, nullptr, ok_cb, nullptr)) {
651 /* select keyframes that are in the appropriate places */
652 ANIM_fcurve_keyframes_loop(&ked, fcu, ok_cb, select_cb, nullptr);
653 any_key_selection_changed = true;
654 /* Only change selection of channel when the visibility of keyframes
655 * doesn't depend on this. */
656 if ((U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) == 0) {
657 /* select the curve too now that curve will be touched */
658 if (selectmode == SELECT_ADD) {
659 fcu->flag |= FCURVE_SELECTED;
660 }
661 }
662 }
663
664 /* Un-apply NLA mapping from all the keyframes. */
666 ale, static_cast<FCurve *>(ale->key_data), true, (mapping_flag & ANIM_UNITCONV_ONLYKEYS));
667 }
668
669 /* Cleanup. */
670 ANIM_animdata_freelist(&anim_data);
671
672 return any_key_selection_changed;
673}
674
679static short ok_bezier_always_ok(KeyframeEditData * /*ked*/, BezTriple * /*bezt*/)
680{
682}
683
684#define ABOVE 1
685#define INSIDE 0
686#define BELOW -1
687static int rectf_curve_zone_y(const FCurve *fcu,
688 const rctf *rectf,
689 const float offset,
690 const float unit_scale,
691 const float eval_x)
692{
693 const float fcurve_y = (evaluate_fcurve_only_curve(fcu, eval_x) + offset) * unit_scale;
694 return fcurve_y < rectf->ymin ? BELOW : fcurve_y <= rectf->ymax ? INSIDE : ABOVE;
695}
696
697/* Checks whether the given rectangle intersects the given fcurve's calculated curve (i.e. not
698 * only keyframes, but also all the interpolated values). This is done by sampling the curve at
699 * different points between the xmin and the xmax of the rectangle.
700 */
701static bool rectf_curve_intersection(const float offset,
702 const float unit_scale,
703 const rctf *rectf,
704 bAnimListElem *ale,
705 const FCurve *fcu)
706{
707 /* 30 sampling points. This worked well in tests. */
708 int num_steps = 30;
709
710 /* Remap the range at which to evaluate the fcurves. This enables us to avoid remapping
711 * the keys themselves. */
712 const float mapped_max = ANIM_nla_tweakedit_remap(ale, rectf->xmax, NLATIME_CONVERT_UNMAP);
713 const float mapped_min = ANIM_nla_tweakedit_remap(ale, rectf->xmin, NLATIME_CONVERT_UNMAP);
714 const float eval_step = (mapped_max - mapped_min) / num_steps;
715
716 /* Sample points on the given fcurve in the interval defined by the
717 * mapped_min and mapped_max of the selected rectangle.
718 * For each point, check if it is inside of the selection box. If it is, then select
719 * all the keyframes of the curve, the curve, and stop the loop.
720 */
721 struct {
722 float eval_x;
723 int zone;
724 } cur, prev;
725
726 prev.eval_x = mapped_min;
727 prev.zone = rectf_curve_zone_y(fcu, rectf, offset, unit_scale, prev.eval_x);
728 if (prev.zone == INSIDE) {
729 return true;
730 }
731
732 while (num_steps--) {
733 cur.eval_x = prev.eval_x + eval_step;
734 cur.zone = rectf_curve_zone_y(fcu, rectf, offset, unit_scale, cur.eval_x);
735 if (cur.zone != prev.zone) {
736 return true;
737 }
738
739 prev = cur;
740 }
741 return false;
742}
743#undef ABOVE
744#undef INSIDE
745#undef BELOW
746
755 const rctf *rectf_view,
756 const short mode,
757 const eEditKeyframes_Select selectmode,
758 const bool incl_handles,
759 void *data)
760{
763 rctf scaled_rectf;
765 int mapping_flag;
767 incl_handles, mode, ac, data, &scaled_rectf, &ked, &mapping_flag);
768
769 FCurve *last_selected_curve = nullptr;
770
771 /* Go through all the curves and try selecting them. This function is only called
772 * if no keyframe is in the selection area, so we only have to check if the curve
773 * intersects the area in order to check if the selection/deselection must happen.
774 */
775
776 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
777 FCurve *fcu = (FCurve *)ale->key_data;
778 float offset;
779 const float unit_scale = ANIM_unit_mapping_get_factor(
780 ac->scene, ale->id, fcu, mapping_flag, &offset);
781
782 const rctf rectf = initialize_box_select_coords(ac, rectf_view);
783
784 /* scaled_rectf is declared at the top of the block because it is required by the
785 * initialize_box_select_key_editing_data function (which does
786 * data_xxx->rectf_scaled = scaled_rectf). The below assignment therefore modifies the
787 * data we use to iterate over the curves (ked).
788 */
789 scaled_rectf.xmin = rectf.xmin;
790 scaled_rectf.xmax = rectf.xmax;
791 scaled_rectf.ymin = rectf.ymin / unit_scale - offset;
792 scaled_rectf.ymax = rectf.ymax / unit_scale - offset;
793
794 const KeyframeEditFunc select_cb = ANIM_editkeyframes_select(selectmode);
795 if (rectf_curve_intersection(offset, unit_scale, &rectf, ale, fcu)) {
796 if ((selectmode & SELECT_ADD) || (selectmode & SELECT_REPLACE)) {
797 fcu->flag |= FCURVE_SELECTED;
798 last_selected_curve = fcu;
799 }
800 else {
801 fcu->flag &= ~FCURVE_SELECTED;
802 }
803 ANIM_fcurve_keyframes_loop(&ked, fcu, ok_bezier_always_ok, select_cb, nullptr);
804 }
805 }
806
807 /* Make sure that one of the selected curves is active in the end. */
808 if (last_selected_curve != nullptr) {
810 ac->data,
813 last_selected_curve,
815 }
816
817 ANIM_animdata_freelist(&anim_data);
818}
819
820/* ------------------- */
821
823 wmOperator *op,
824 const wmEvent *event)
825{
826 bAnimContext ac;
827 if (ANIM_animdata_get_context(C, &ac) == 0) {
828 return OPERATOR_CANCELLED;
829 }
830
831 if (RNA_boolean_get(op->ptr, "tweak")) {
832 int mval[2];
833 WM_event_drag_start_mval(event, ac.region, mval);
834 tNearestVertInfo *under_mouse = find_nearest_fcurve_vert(&ac, mval);
835 bool mouse_is_over_element = under_mouse != nullptr;
836 if (under_mouse) {
837 MEM_freeN(under_mouse);
838 }
839
840 if (mouse_is_over_element) {
842 }
843 }
844
845 return WM_gesture_box_invoke(C, op, event);
846}
847
849{
850 bAnimContext ac;
851 rcti rect;
852 rctf rect_fl;
853 short mode = 0;
854
855 /* get editor data */
856 if (ANIM_animdata_get_context(C, &ac) == 0) {
857 return OPERATOR_CANCELLED;
858 }
859
860 const eSelectOp sel_op = eSelectOp(RNA_enum_get(op->ptr, "mode"));
861 const eEditKeyframes_Select selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT;
862 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
863 deselect_graph_keys(&ac, true, SELECT_SUBTRACT, true);
864 }
865
866 /* 'include_handles' from the operator specifies whether to include handles in the selection. */
867 bool incl_handles = RNA_boolean_get(op->ptr, "include_handles");
868
869 /* Get settings from operator. */
871
872 /* Selection 'mode' depends on whether box_select region only matters on one axis. */
873 if (RNA_boolean_get(op->ptr, "axis_range")) {
874 /* Mode depends on which axis of the range is larger to determine which axis to use
875 * - Checking this in region-space is fine, as it's fundamentally still going to be a
876 * different rect size.
877 * - The frame-range select option is favored over the channel one (x over y),
878 * as frame-range one is often used for tweaking timing when "blocking",
879 * while channels is not that useful.
880 */
881 if (BLI_rcti_size_x(&rect) >= BLI_rcti_size_y(&rect)) {
882 mode = BEZT_OK_FRAMERANGE;
883 }
884 else {
885 mode = BEZT_OK_VALUERANGE;
886 }
887 }
888 else {
889 mode = BEZT_OK_REGION;
890 }
891
892 BLI_rctf_rcti_copy(&rect_fl, &rect);
893
894 /* Apply box_select action. */
895 const bool any_key_selection_changed = box_select_graphkeys(
896 &ac, &rect_fl, mode, selectmode, incl_handles, nullptr);
897 const bool use_curve_selection = RNA_boolean_get(op->ptr, "use_curve_selection");
898 if (use_curve_selection && !any_key_selection_changed) {
899 box_select_graphcurves(&ac, &rect_fl, mode, selectmode, incl_handles, nullptr);
900 }
901 /* Send notifier that keyframe selection has changed. */
903
904 return OPERATOR_FINISHED;
905}
906
908{
909 /* Identifiers. */
910 ot->name = "Box Select";
911 ot->idname = "GRAPH_OT_select_box";
912 ot->description = "Select all keyframes within the specified region";
913
914 /* API callbacks. */
917 ot->modal = WM_gesture_box_modal;
918 ot->cancel = WM_gesture_box_cancel;
919
921
922 /* Flags. */
923 ot->flag = OPTYPE_UNDO;
924
925 /* Properties. */
926 ot->prop = RNA_def_boolean(ot->srna, "axis_range", false, "Axis Range", "");
928
929 PropertyRNA *prop;
930 prop = RNA_def_boolean(
931 ot->srna,
932 "include_handles",
933 true,
934 "Include Handles",
935 "Are handles tested individually against the selection criteria, independently from their "
936 "keys. When unchecked, handles are (de)selected in unison with their keys");
938
939 prop = RNA_def_boolean(
940 ot->srna, "tweak", false, "Tweak", "Operator has been activated using a click-drag event");
942
943 prop = RNA_def_boolean(
944 ot->srna,
945 "use_curve_selection",
946 true,
947 "Select Curves",
948 "Allow selecting all the keyframes of a curve by selecting the calculated F-curve");
950
953}
954
955/* ------------------- */
956
958{
959 bAnimContext ac;
960
961 KeyframeEdit_LassoData data_lasso{};
962 rcti rect;
963 rctf rect_fl;
964
965 /* Get editor data. */
966 if (ANIM_animdata_get_context(C, &ac) == 0) {
967 return OPERATOR_CANCELLED;
968 }
969
970 data_lasso.rectf_view = &rect_fl;
971 data_lasso.mcoords = WM_gesture_lasso_path_to_array(C, op);
972 if (data_lasso.mcoords.is_empty()) {
973 return OPERATOR_CANCELLED;
974 }
975
976 const eSelectOp sel_op = eSelectOp(RNA_enum_get(op->ptr, "mode"));
977 const eEditKeyframes_Select selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT;
978 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
979 deselect_graph_keys(&ac, false, SELECT_SUBTRACT, true);
980 }
981
982 /* Get settings from operator. */
983 BLI_lasso_boundbox(&rect, data_lasso.mcoords);
984 BLI_rctf_rcti_copy(&rect_fl, &rect);
985
986 /* 'include_handles' from the operator specifies whether to consider handles in the selection. */
987 const bool incl_handles = RNA_boolean_get(op->ptr, "include_handles");
988
989 /* Apply box_select action. */
990 const bool any_key_selection_changed = box_select_graphkeys(
991 &ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso);
992 const bool use_curve_selection = RNA_boolean_get(op->ptr, "use_curve_selection");
993 if (use_curve_selection && !any_key_selection_changed) {
995 &ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso);
996 }
997
998 /* Send notifier that keyframe selection has changed. */
1000
1001 return OPERATOR_FINISHED;
1002}
1003
1005{
1006 /* Identifiers. */
1007 ot->name = "Lasso Select";
1008 ot->description = "Select keyframe points using lasso selection";
1009 ot->idname = "GRAPH_OT_select_lasso";
1010
1011 /* API callbacks. */
1012 ot->invoke = WM_gesture_lasso_invoke;
1013 ot->modal = WM_gesture_lasso_modal;
1016 ot->cancel = WM_gesture_lasso_cancel;
1017
1018 /* Flags. */
1020
1021 /* Properties. */
1024
1025 PropertyRNA *prop;
1026 prop = RNA_def_boolean(
1027 ot->srna,
1028 "include_handles",
1029 true,
1030 "Include Handles",
1031 "Are handles tested individually against the selection criteria, independently from their "
1032 "keys. When unchecked, handles are (de)selected in unison with their keys");
1034
1035 prop = RNA_def_boolean(
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
1050 KeyframeEdit_CircleData data = {nullptr};
1051 rctf rect_fl;
1052
1053 float x = RNA_int_get(op->ptr, "x");
1054 float y = RNA_int_get(op->ptr, "y");
1055 float radius = RNA_int_get(op->ptr, "radius");
1056
1057 /* Get editor data. */
1058 if (ANIM_animdata_get_context(C, &ac) == 0) {
1059 return OPERATOR_CANCELLED;
1060 }
1061
1062 const eSelectOp sel_op = ED_select_op_modal(
1063 eSelectOp(RNA_enum_get(op->ptr, "mode")),
1064 WM_gesture_is_modal_first(static_cast<const wmGesture *>(op->customdata)));
1065 const eEditKeyframes_Select selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT;
1066 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
1067 deselect_graph_keys(&ac, false, SELECT_SUBTRACT, true);
1068 }
1069
1070 data.mval[0] = x;
1071 data.mval[1] = y;
1072 data.radius_squared = radius * radius;
1073 data.rectf_view = &rect_fl;
1074
1075 rect_fl.xmin = x - radius;
1076 rect_fl.xmax = x + radius;
1077 rect_fl.ymin = y - radius;
1078 rect_fl.ymax = y + radius;
1079
1080 /* 'include_handles' from the operator specifies whether to consider handles in the selection. */
1081 const bool incl_handles = RNA_boolean_get(op->ptr, "include_handles");
1082
1083 /* Apply box_select action. */
1084 const bool any_key_selection_changed = box_select_graphkeys(
1085 &ac, &rect_fl, BEZT_OK_REGION_CIRCLE, selectmode, incl_handles, &data);
1086 if (any_key_selection_changed) {
1087 /* If any key was selected at any time during this process, the entire-curve selection should
1088 * be disabled. Otherwise, sliding over any keyless part of the curve will immediately cause
1089 * the entire curve to be selected. */
1090 RNA_boolean_set(op->ptr, "use_curve_selection", false);
1091 }
1092 const bool use_curve_selection = RNA_boolean_get(op->ptr, "use_curve_selection");
1093 if (use_curve_selection && !any_key_selection_changed) {
1094 box_select_graphcurves(&ac, &rect_fl, BEZT_OK_REGION_CIRCLE, selectmode, incl_handles, &data);
1095 }
1096
1097 /* Send notifier that keyframe selection has changed. */
1099
1100 return OPERATOR_FINISHED;
1101}
1102
1104{
1105 ot->name = "Circle Select";
1106 ot->description = "Select keyframe points using circle selection";
1107 ot->idname = "GRAPH_OT_select_circle";
1108
1109 ot->invoke = WM_gesture_circle_invoke;
1110 ot->modal = WM_gesture_circle_modal;
1113 ot->cancel = WM_gesture_circle_cancel;
1114 ot->get_name = ED_select_circle_get_name;
1115
1116 /* flags */
1117 ot->flag = OPTYPE_UNDO;
1118
1119 /* properties */
1122
1123 PropertyRNA *prop;
1124 prop = RNA_def_boolean(
1125 ot->srna,
1126 "include_handles",
1127 true,
1128 "Include Handles",
1129 "Are handles tested individually against the selection criteria, independently from their "
1130 "keys. When unchecked, handles are (de)selected in unison with their keys");
1132
1133 prop = RNA_def_boolean(
1134 ot->srna,
1135 "use_curve_selection",
1136 true,
1137 "Select Curves",
1138 "Allow selecting all the keyframes of a curve by selecting the curve itself");
1140}
1141
1143
1144/* -------------------------------------------------------------------- */
1153
1154/* defines for column-select mode */
1156 {GRAPHKEYS_COLUMNSEL_KEYS, "KEYS", 0, "On Selected Keyframes", ""},
1157 {GRAPHKEYS_COLUMNSEL_CFRA, "CFRA", 0, "On Current Frame", ""},
1158 {GRAPHKEYS_COLUMNSEL_MARKERS_COLUMN, "MARKERS_COLUMN", 0, "On Selected Markers", ""},
1160 "MARKERS_BETWEEN",
1161 0,
1162 "Between Min/Max Selected Markers",
1163 ""},
1164 {0, nullptr, 0, nullptr, nullptr},
1165};
1166
1167/* ------------------- */
1168
1169/* Selects all visible keyframes between the specified markers */
1170/* TODO(@ideasman42): this is almost an _exact_ duplicate of a function of the same name in
1171 * `action_select.cc` should de-duplicate. */
1173{
1174 ListBase anim_data = {nullptr, nullptr};
1175 int filter;
1176
1177 KeyframeEditFunc ok_cb, select_cb;
1178 KeyframeEditData ked = {{nullptr}};
1179 float min, max;
1180
1181 /* get extreme markers */
1183 min -= 0.5f;
1184 max += 0.5f;
1185
1186 /* Get editing functions + data. */
1189
1190 ked.f1 = min;
1191 ked.f2 = max;
1192
1193 /* filter data */
1197 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
1198
1199 /* select keys in-between */
1200 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1202 ale, static_cast<FCurve *>(ale->key_data), false, true);
1204 &ked, static_cast<FCurve *>(ale->key_data), ok_cb, select_cb, nullptr);
1205 ANIM_nla_mapping_apply_if_needed_fcurve(ale, static_cast<FCurve *>(ale->key_data), true, true);
1206 }
1207
1208 /* Cleanup */
1209 ANIM_animdata_freelist(&anim_data);
1210}
1211
1212/* Selects all visible keyframes in the same frames as the specified elements */
1213static void columnselect_graph_keys(bAnimContext *ac, short mode)
1214{
1215 ListBase anim_data = {nullptr, nullptr};
1216 int filter;
1217
1218 Scene *scene = ac->scene;
1219 CfraElem *ce;
1220 KeyframeEditFunc select_cb, ok_cb;
1221 KeyframeEditData ked;
1222
1223 /* initialize keyframe editing data */
1224 memset(&ked, 0, sizeof(KeyframeEditData));
1225
1226 /* build list of columns */
1227 switch (mode) {
1228 case GRAPHKEYS_COLUMNSEL_KEYS: /* list of selected keys */
1232 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
1233
1234 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1235 ked.data = ale;
1237 &ked, static_cast<FCurve *>(ale->key_data), nullptr, bezt_to_cfraelem, nullptr);
1238 }
1239
1240 ANIM_animdata_freelist(&anim_data);
1241 break;
1242
1243 case GRAPHKEYS_COLUMNSEL_CFRA: /* current frame */
1244 /* make a single CfraElem for storing this */
1245 ce = MEM_callocN<CfraElem>("cfraElem");
1246 BLI_addtail(&ked.list, ce);
1247
1248 ce->cfra = float(scene->r.cfra);
1249 break;
1250
1251 case GRAPHKEYS_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */
1252 ED_markers_make_cfra_list(ac->markers, &ked.list, true);
1253 break;
1254
1255 default: /* invalid option */
1256 return;
1257 }
1258
1259 /* set up BezTriple edit callbacks */
1262
1263 /* loop through all of the keys and select additional keyframes
1264 * based on the keys found to be selected above
1265 */
1269 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
1270
1271 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1272 /* loop over cfraelems (stored in the KeyframeEditData->list)
1273 * - we need to do this here, as we can apply fewer NLA-mapping conversions
1274 */
1275 LISTBASE_FOREACH (CfraElem *, ce, &ked.list) {
1276 /* set frame for validation callback to refer to */
1278
1279 /* select elements with frame number matching cfraelem */
1281 &ked, static_cast<FCurve *>(ale->key_data), ok_cb, select_cb, nullptr);
1282 }
1283 }
1284
1285 /* free elements */
1286 BLI_freelistN(&ked.list);
1287 ANIM_animdata_freelist(&anim_data);
1288}
1289
1290/* ------------------- */
1291
1293{
1294 bAnimContext ac;
1295 short mode;
1296
1297 /* get editor data */
1298 if (ANIM_animdata_get_context(C, &ac) == 0) {
1299 return OPERATOR_CANCELLED;
1300 }
1301
1302 /* action to take depends on the mode */
1303 mode = RNA_enum_get(op->ptr, "mode");
1304
1307 }
1308 else {
1309 columnselect_graph_keys(&ac, mode);
1310 }
1311
1312 /* set notifier that keyframe selection has changed */
1314
1315 return OPERATOR_FINISHED;
1316}
1317
1319{
1320 /* identifiers */
1321 ot->name = "Select All";
1322 ot->idname = "GRAPH_OT_select_column";
1323 ot->description = "Select all keyframes on the specified frame(s)";
1324
1325 /* API callbacks. */
1328
1329 /* flags */
1330 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1331
1332 /* props */
1333 ot->prop = RNA_def_enum(ot->srna, "mode", prop_column_select_types, 0, "Mode", "");
1335}
1336
1338
1339/* -------------------------------------------------------------------- */
1342
1344{
1345 bAnimContext ac;
1346
1347 ListBase anim_data = {nullptr, nullptr};
1348 int filter;
1349
1352
1353 /* get editor data */
1354 if (ANIM_animdata_get_context(C, &ac) == 0) {
1355 return OPERATOR_CANCELLED;
1356 }
1357
1358 /* loop through all of the keys and select additional keyframes based on these */
1362 &ac, &anim_data, eAnimFilter_Flags(filter), ac.data, eAnimCont_Types(ac.datatype));
1363
1364 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1365 FCurve *fcu = (FCurve *)ale->key_data;
1366
1367 /* check if anything selected? */
1368 if (ANIM_fcurve_keyframes_loop(nullptr, fcu, nullptr, ok_cb, nullptr)) {
1369 /* select every keyframe in this curve then */
1370 ANIM_fcurve_keyframes_loop(nullptr, fcu, nullptr, sel_cb, nullptr);
1371 }
1372 }
1373
1374 /* Cleanup */
1375 ANIM_animdata_freelist(&anim_data);
1376
1377 /* set notifier that keyframe selection has changed */
1379
1380 return OPERATOR_FINISHED;
1381}
1382
1384{
1385 /* identifiers */
1386 ot->name = "Select Linked";
1387 ot->idname = "GRAPH_OT_select_linked";
1388 ot->description = "Select keyframes occurring in the same F-Curves as selected ones";
1389
1390 /* API callbacks. */
1393
1394 /* flags */
1395 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1396}
1397
1399
1400/* -------------------------------------------------------------------- */
1403
1404/* Common code to perform selection */
1405static void select_moreless_graph_keys(bAnimContext *ac, short mode)
1406{
1407 ListBase anim_data = {nullptr, nullptr};
1408 int filter;
1409
1410 KeyframeEditData ked;
1411 KeyframeEditFunc build_cb;
1412
1413 /* init selmap building data */
1414 build_cb = ANIM_editkeyframes_buildselmap(mode);
1415 memset(&ked, 0, sizeof(KeyframeEditData));
1416
1417 /* loop through all of the keys and select additional keyframes based on these */
1421 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
1422
1423 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1424 FCurve *fcu = (FCurve *)ale->key_data;
1425
1426 /* only continue if F-Curve has keyframes */
1427 if (fcu->bezt == nullptr) {
1428 continue;
1429 }
1430
1431 /* build up map of whether F-Curve's keyframes should be selected or not */
1432 ked.data = MEM_callocN(fcu->totvert, "selmap graphEdit");
1433 ANIM_fcurve_keyframes_loop(&ked, fcu, nullptr, build_cb, nullptr);
1434
1435 /* based on this map, adjust the selection status of the keyframes */
1436 ANIM_fcurve_keyframes_loop(&ked, fcu, nullptr, bezt_selmap_flush, nullptr);
1437
1438 /* free the selmap used here */
1439 MEM_freeN(ked.data);
1440 ked.data = nullptr;
1441 }
1442
1443 /* Cleanup */
1444 ANIM_animdata_freelist(&anim_data);
1445}
1446
1447/* ----------------- */
1448
1450{
1451 bAnimContext ac;
1452
1453 /* get editor data */
1454 if (ANIM_animdata_get_context(C, &ac) == 0) {
1455 return OPERATOR_CANCELLED;
1456 }
1457
1458 /* perform select changes */
1460
1461 /* set notifier that keyframe selection has changed */
1463
1464 return OPERATOR_FINISHED;
1465}
1466
1468{
1469 /* identifiers */
1470 ot->name = "Select More";
1471 ot->idname = "GRAPH_OT_select_more";
1472 ot->description = "Select keyframes beside already selected ones";
1473
1474 /* API callbacks. */
1477
1478 /* flags */
1479 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1480}
1481
1482/* ----------------- */
1483
1485{
1486 bAnimContext ac;
1487
1488 /* get editor data */
1489 if (ANIM_animdata_get_context(C, &ac) == 0) {
1490 return OPERATOR_CANCELLED;
1491 }
1492
1493 /* perform select changes */
1495
1496 /* set notifier that keyframe selection has changed */
1498
1499 return OPERATOR_FINISHED;
1500}
1501
1503{
1504 /* identifiers */
1505 ot->name = "Select Less";
1506 ot->idname = "GRAPH_OT_select_less";
1507 ot->description = "Deselect keyframes on ends of selection islands";
1508
1509 /* API callbacks. */
1512
1513 /* flags */
1514 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1515}
1516
1518
1519/* -------------------------------------------------------------------- */
1524
1525/* defines for left-right select tool */
1527 {GRAPHKEYS_LRSEL_TEST, "CHECK", 0, "Check if Select Left or Right", ""},
1528 {GRAPHKEYS_LRSEL_LEFT, "LEFT", 0, "Before Current Frame", ""},
1529 {GRAPHKEYS_LRSEL_RIGHT, "RIGHT", 0, "After Current Frame", ""},
1530 {0, nullptr, 0, nullptr, nullptr},
1531};
1532
1533/* --------------------------------- */
1534
1536 short leftright,
1537 eEditKeyframes_Select select_mode)
1538{
1539 ListBase anim_data = {nullptr, nullptr};
1540 int filter;
1541
1542 KeyframeEditFunc ok_cb, select_cb;
1543 KeyframeEditData ked = {{nullptr}};
1544 Scene *scene = ac->scene;
1545
1546 /* if select mode is replace, deselect all keyframes (and channels) first */
1547 if (select_mode == SELECT_REPLACE) {
1548 select_mode = SELECT_ADD;
1549
1550 /* - deselect all other keyframes, so that just the newly selected remain
1551 * - channels aren't deselected, since we don't re-select any as a consequence
1552 */
1553 deselect_graph_keys(ac, false, SELECT_SUBTRACT, false);
1554 }
1555
1556 /* set callbacks and editing data */
1558 select_cb = ANIM_editkeyframes_select(select_mode);
1559
1560 if (leftright == GRAPHKEYS_LRSEL_LEFT) {
1561 ked.f1 = MINAFRAMEF;
1562 ked.f2 = float(scene->r.cfra + 0.1f);
1563 }
1564 else {
1565 ked.f1 = float(scene->r.cfra - 0.1f);
1566 ked.f2 = MAXFRAMEF;
1567 }
1568
1569 /* filter data */
1572 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
1573
1574 /* select keys */
1575 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1577 ale, static_cast<FCurve *>(ale->key_data), false, true);
1579 &ked, static_cast<FCurve *>(ale->key_data), ok_cb, select_cb, nullptr);
1580 ANIM_nla_mapping_apply_if_needed_fcurve(ale, static_cast<FCurve *>(ale->key_data), true, true);
1581 }
1582
1583 /* Cleanup */
1584 ANIM_animdata_freelist(&anim_data);
1585}
1586
1587/* ----------------- */
1588
1590{
1591 bAnimContext ac;
1592 short leftright = RNA_enum_get(op->ptr, "mode");
1593 eEditKeyframes_Select selectmode;
1594
1595 /* get editor data */
1596 if (ANIM_animdata_get_context(C, &ac) == 0) {
1597 return OPERATOR_CANCELLED;
1598 }
1599
1600 /* select mode is either replace (deselect all, then add) or add/extend */
1601 if (RNA_boolean_get(op->ptr, "extend")) {
1602 selectmode = SELECT_INVERT;
1603 }
1604 else {
1605 selectmode = SELECT_REPLACE;
1606 }
1607
1608 /* if "test" mode is set, we don't have any info to set this with */
1609 if (leftright == GRAPHKEYS_LRSEL_TEST) {
1610 return OPERATOR_CANCELLED;
1611 }
1612
1613 /* do the selecting now */
1614 graphkeys_select_leftright(&ac, leftright, selectmode);
1615
1616 /* set notifier that keyframe selection (and channels too) have changed */
1619
1620 return OPERATOR_FINISHED;
1621}
1622
1624 wmOperator *op,
1625 const wmEvent *event)
1626{
1627 bAnimContext ac;
1628 short leftright = RNA_enum_get(op->ptr, "mode");
1629
1630 /* get editor data */
1631 if (ANIM_animdata_get_context(C, &ac) == 0) {
1632 return OPERATOR_CANCELLED;
1633 }
1634
1635 /* handle mode-based testing */
1636 if (leftright == GRAPHKEYS_LRSEL_TEST) {
1637 Scene *scene = ac.scene;
1638 ARegion *region = ac.region;
1639 View2D *v2d = &region->v2d;
1640 float x;
1641
1642 /* determine which side of the current frame mouse is on */
1643 x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
1644 if (x < scene->r.cfra) {
1646 }
1647 else {
1649 }
1650 }
1651
1652 /* perform selection */
1654}
1655
1657{
1658 PropertyRNA *prop;
1659
1660 /* identifiers */
1661 ot->name = "Select Left/Right";
1662 ot->idname = "GRAPH_OT_select_leftright";
1663 ot->description = "Select keyframes to the left or the right of the current frame";
1664
1665 /* API callbacks. */
1669
1670 /* flags */
1671 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1672
1673 /* id-props */
1674 ot->prop = RNA_def_enum(
1677
1678 prop = RNA_def_boolean(ot->srna, "extend", false, "Extend Select", "");
1680}
1681
1683
1684/* -------------------------------------------------------------------- */
1695
1696/* option 1) select keyframe directly under mouse */
1698 const int mval[2],
1699 eEditKeyframes_Select select_mode,
1700 const bool deselect_all,
1701 const bool curves_only,
1702 bool wait_to_deselect_others)
1703{
1704 SpaceGraph *sipo = (SpaceGraph *)ac->sl;
1705 tNearestVertInfo *nvi;
1706 BezTriple *bezt = nullptr;
1707 bool run_modal = false;
1708
1709 /* find the beztriple that we're selecting, and the handle that was clicked on */
1710 nvi = find_nearest_fcurve_vert(ac, mval);
1711
1712 if (select_mode != SELECT_REPLACE) {
1713 /* The modal execution to delay deselecting other items is only needed for normal click
1714 * selection, i.e. for SELECT_REPLACE. */
1715 wait_to_deselect_others = false;
1716 }
1717
1720
1721 const bool already_selected =
1722 (nvi != nullptr) && (((nvi->hpoint == NEAREST_HANDLE_KEY) && (nvi->bezt->f2 & SELECT)) ||
1723 ((nvi->hpoint == NEAREST_HANDLE_LEFT) && (nvi->bezt->f1 & SELECT)) ||
1724 ((nvi->hpoint == NEAREST_HANDLE_RIGHT) && (nvi->bezt->f3 & SELECT)));
1725
1726 if (wait_to_deselect_others && nvi && already_selected) {
1727 run_modal = true;
1728 }
1729 /* For replacing selection, if we have something to select, we have to clear existing selection.
1730 * The same goes if we found nothing to select, and deselect_all is true
1731 * (deselect on nothing behavior). */
1732 else if ((nvi != nullptr && select_mode == SELECT_REPLACE) || (nvi == nullptr && deselect_all)) {
1733 /* reset selection mode */
1734 select_mode = SELECT_ADD;
1735
1736 /* deselect all other keyframes (+ F-Curves too) */
1737 deselect_graph_keys(ac, false, SELECT_SUBTRACT, true);
1738
1739 /* Deselect other channels too, but only do this if selection of channel
1740 * when the visibility of keyframes doesn't depend on this. */
1741 if ((U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) == 0) {
1743 }
1744 }
1745
1746 if (nvi == nullptr) {
1747 return deselect_all ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1748 }
1749
1750 /* if points can be selected on this F-Curve */
1751 /* TODO: what about those with no keyframes? */
1752 bool something_was_selected = false;
1753 if (!curves_only && ((nvi->fcu->flag & FCURVE_PROTECTED) == 0)) {
1754 /* only if there's keyframe */
1755 if (nvi->bezt) {
1756 bezt = nvi->bezt; /* Used to check `bezt` selection is set. */
1757 if (select_mode == SELECT_INVERT) {
1758 if (nvi->hpoint == NEAREST_HANDLE_KEY) {
1759 bezt->f2 ^= SELECT;
1760 something_was_selected = (bezt->f2 & SELECT);
1761 }
1762 else if (nvi->hpoint == NEAREST_HANDLE_LEFT) {
1763 /* toggle selection */
1764 bezt->f1 ^= SELECT;
1765 something_was_selected = (bezt->f1 & SELECT);
1766 }
1767 else {
1768 /* toggle selection */
1769 bezt->f3 ^= SELECT;
1770 something_was_selected = (bezt->f3 & SELECT);
1771 }
1772 }
1773 else {
1774 if (nvi->hpoint == NEAREST_HANDLE_KEY) {
1775 bezt->f2 |= SELECT;
1776 }
1777 else if (nvi->hpoint == NEAREST_HANDLE_LEFT) {
1778 bezt->f1 |= SELECT;
1779 }
1780 else {
1781 bezt->f3 |= SELECT;
1782 }
1783 something_was_selected = true;
1784 }
1785
1786 if (!run_modal && BEZT_ISSEL_ANY(bezt)) {
1787 const bool may_activate = !already_selected ||
1790 if (may_activate) {
1792 }
1793 }
1794 }
1795 else if (nvi->fpt) {
1796 /* TODO: need to handle sample points */
1797 }
1798 }
1799 else {
1800 KeyframeEditFunc select_cb;
1801 KeyframeEditData ked;
1802
1803 /* initialize keyframe editing data */
1804 memset(&ked, 0, sizeof(KeyframeEditData));
1805
1806 /* set up BezTriple edit callbacks */
1807 select_cb = ANIM_editkeyframes_select(select_mode);
1808
1809 /* select all keyframes */
1810 ANIM_fcurve_keyframes_loop(&ked, nvi->fcu, nullptr, select_cb, nullptr);
1811 }
1812
1813 /* only change selection of channel when the visibility of keyframes doesn't depend on this */
1814 if ((U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) == 0) {
1815 /* select or deselect curve? */
1816 if (bezt) {
1817 /* take selection status from item that got hit, to prevent flip/flop on channel
1818 * selection status when shift-selecting (i.e. "SELECT_INVERT") points
1819 */
1820 if (BEZT_ISSEL_ANY(bezt)) {
1821 nvi->fcu->flag |= FCURVE_SELECTED;
1822 }
1823 else {
1824 nvi->fcu->flag &= ~FCURVE_SELECTED;
1825 }
1826 }
1827 else {
1828 /* Didn't hit any channel,
1829 * so just apply that selection mode to the curve's selection status. */
1830 if (select_mode == SELECT_INVERT) {
1831 nvi->fcu->flag ^= FCURVE_SELECTED;
1832 }
1833 else if (select_mode == SELECT_ADD) {
1834 nvi->fcu->flag |= FCURVE_SELECTED;
1835 }
1836 }
1837 }
1838
1839 /* Set active F-Curve when something was actually selected (so not on a deselect), except when
1840 * dragging the selected keys. Needs to be called with (sipo->flag & SIPO_SELCUVERTSONLY),
1841 * otherwise the active flag won't be set #26452. */
1842 if (!run_modal && (nvi->fcu->flag & FCURVE_SELECTED) && something_was_selected) {
1843 /* NOTE: Sync the filter flags with findnearest_fcurve_vert. */
1847 ac->data,
1850 nvi->fcu,
1851 nvi->ctype);
1852 }
1853
1854 if (nvi->hpoint == NEAREST_HANDLE_LEFT) {
1856 }
1857 else if (nvi->hpoint == NEAREST_HANDLE_RIGHT) {
1859 }
1860
1861 /* free temp sample data for filtering */
1862 MEM_freeN(nvi);
1863
1864 return run_modal ? OPERATOR_RUNNING_MODAL : OPERATOR_FINISHED;
1865}
1866
1867/* Option 2) Selects all the keyframes on either side of the current frame
1868 * (depends on which side the mouse is on) */
1869/* (see graphkeys_select_leftright) */
1870
1871/* Option 3) Selects all visible keyframes in the same frame as the mouse click */
1873 const int mval[2],
1874 eEditKeyframes_Select select_mode,
1875 bool wait_to_deselect_others)
1876{
1877 ListBase anim_data = {nullptr, nullptr};
1878 int filter;
1879 bool run_modal = false;
1880
1881 KeyframeEditFunc select_cb, ok_cb;
1882 KeyframeEditData ked;
1883 tNearestVertInfo *nvi;
1884
1885 /* find the beztriple that we're selecting, and the handle that was clicked on */
1886 nvi = find_nearest_fcurve_vert(ac, mval);
1887
1888 /* check if anything to select */
1889 if (nvi == nullptr) {
1890 return OPERATOR_CANCELLED;
1891 }
1892
1893 /* get frame number on which elements should be selected */
1894 /* TODO: should we restrict to integer frames only? */
1895 const float selx = nvi->frame;
1896
1897 if (select_mode != SELECT_REPLACE) {
1898 /* Doesn't need to deselect anything -> Pass. */
1899 }
1900 else if (wait_to_deselect_others && (nvi->bezt->f2 & SELECT)) {
1901 run_modal = true;
1902 }
1903 /* If select mode is replace (and we don't do delayed deselection on mouse release), deselect all
1904 * keyframes first. */
1905 else {
1906 /* reset selection mode to add to selection */
1907 select_mode = SELECT_ADD;
1908
1909 /* - deselect all other keyframes, so that just the newly selected remain
1910 * - channels aren't deselected, since we don't re-select any as a consequence
1911 */
1912 deselect_graph_keys(ac, false, SELECT_SUBTRACT, false);
1913 }
1914
1915 /* initialize keyframe editing data */
1916 memset(&ked, 0, sizeof(KeyframeEditData));
1917
1918 /* set up BezTriple edit callbacks */
1919 select_cb = ANIM_editkeyframes_select(select_mode);
1921
1922 /* loop through all of the keys and select additional keyframes
1923 * based on the keys found to be selected above
1924 */
1928 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
1929
1930 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1931 /* set frame for validation callback to refer to */
1933
1934 /* select elements with frame number matching cfra */
1936 &ked, static_cast<FCurve *>(ale->key_data), ok_cb, select_cb, nullptr);
1937 }
1938
1939 /* free elements */
1940 MEM_freeN(nvi);
1941 BLI_freelistN(&ked.list);
1942 ANIM_animdata_freelist(&anim_data);
1943
1944 return run_modal ? OPERATOR_RUNNING_MODAL : OPERATOR_FINISHED;
1945}
1946
1948
1949/* -------------------------------------------------------------------- */
1952
1954{
1955 bAnimContext ac;
1956
1957 /* get editor data */
1958 if (ANIM_animdata_get_context(C, &ac) == 0) {
1959 return OPERATOR_CANCELLED;
1960 }
1961
1962 /* select mode is either replace (deselect all, then add) or add/extend */
1963 const short selectmode = RNA_boolean_get(op->ptr, "extend") ? SELECT_INVERT : SELECT_REPLACE;
1964 const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
1965 /* See #WM_operator_properties_generic_select() for a detailed description of the how and why of
1966 * this. */
1967 const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
1968 int mval[2];
1969 wmOperatorStatus ret_val;
1970
1971 mval[0] = RNA_int_get(op->ptr, "mouse_x");
1972 mval[1] = RNA_int_get(op->ptr, "mouse_y");
1973
1974 /* figure out action to take */
1975 if (RNA_boolean_get(op->ptr, "column")) {
1976 /* select all keyframes in the same frame as the one that was under the mouse */
1977 ret_val = graphkeys_mselect_column(
1978 &ac, mval, eEditKeyframes_Select(selectmode), wait_to_deselect_others);
1979 }
1980 else if (RNA_boolean_get(op->ptr, "curves")) {
1981 /* select all keyframes in the same F-Curve as the one under the mouse */
1982 ret_val = mouse_graph_keys(
1983 &ac, mval, eEditKeyframes_Select(selectmode), deselect_all, true, wait_to_deselect_others);
1984 }
1985 else {
1986 /* select keyframe under mouse */
1987 ret_val = mouse_graph_keys(&ac,
1988 mval,
1989 eEditKeyframes_Select(selectmode),
1990 deselect_all,
1991 false,
1992 wait_to_deselect_others);
1993 }
1994
1995 /* set notifier that keyframe selection (and also channel selection in some cases) has
1996 * changed */
1999
2000 /* for tweak grab to work */
2001 return ret_val | OPERATOR_PASS_THROUGH;
2002}
2003
2005{
2006 PropertyRNA *prop;
2007
2008 /* identifiers */
2009 ot->name = "Select Keyframes";
2010 ot->idname = "GRAPH_OT_clickselect";
2011 ot->description = "Select keyframes by clicking on them";
2012
2013 /* callbacks */
2016 ot->invoke = WM_generic_select_invoke;
2017 ot->modal = WM_generic_select_modal;
2018
2019 /* flags */
2020 ot->flag = OPTYPE_UNDO;
2021
2022 /* properties */
2024
2025 /* Key-map: Enable with `Shift`. */
2026 prop = RNA_def_boolean(ot->srna,
2027 "extend",
2028 false,
2029 "Extend Select",
2030 "Toggle keyframe selection instead of leaving newly selected "
2031 "keyframes only");
2033
2034 prop = RNA_def_boolean(ot->srna,
2035 "deselect_all",
2036 false,
2037 "Deselect On Nothing",
2038 "Deselect all when nothing under the cursor");
2040
2041 /* Key-map: Enable with `Alt`. */
2042 prop = RNA_def_boolean(ot->srna,
2043 "column",
2044 false,
2045 "Column Select",
2046 "Select all keyframes that occur on the same frame as the one under "
2047 "the mouse");
2049
2050 /* Key-map: Enable with `Ctrl-Atl`. */
2051 prop = RNA_def_boolean(
2052 ot->srna, "curves", false, "Only Curves", "Select all the keyframes in the curve");
2054}
2055
2057
2058/* -------------------------------------------------------------------- */
2061
2062/* Defines for key/handles select tool. */
2064 {GRAPHKEYS_KEYHANDLESSEL_SELECT, "SELECT", 0, "Select", ""},
2065 {GRAPHKEYS_KEYHANDLESSEL_DESELECT, "DESELECT", 0, "Deselect", ""},
2066 {GRAPHKEYS_KEYHANDLESSEL_KEEP, "KEEP", 0, "Keep", "Leave as is"},
2067 {0, nullptr, 0, nullptr, nullptr},
2068};
2069
2081 bAnimContext *ac,
2082 const enum eGraphKey_SelectKeyHandles_Action left_handle_action,
2083 const enum eGraphKey_SelectKeyHandles_Action key_action,
2084 const enum eGraphKey_SelectKeyHandles_Action right_handle_action)
2085{
2086 ListBase anim_data = {nullptr, nullptr};
2087
2090 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
2091 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
2092 BLI_assert(ale->type & ANIMTYPE_FCURVE);
2093 FCurve *fcu = (FCurve *)ale->key_data;
2094
2095 /* Only continue if F-Curve has keyframes. */
2096 if (fcu->bezt == nullptr) {
2097 continue;
2098 }
2099
2100 for (int i = 0; i < fcu->totvert; i++) {
2101 BezTriple *bezt = &fcu->bezt[i];
2102
2103 if (!BEZT_ISSEL_ANY(bezt)) {
2104 continue;
2105 }
2106
2107 switch (left_handle_action) {
2109 BEZT_SEL_IDX(bezt, 0);
2110 break;
2112 BEZT_DESEL_IDX(bezt, 0);
2113 break;
2115 /* Do nothing. */
2116 break;
2117 }
2118
2119 switch (key_action) {
2121 BEZT_SEL_IDX(bezt, 1);
2122 break;
2124 BEZT_DESEL_IDX(bezt, 1);
2125 break;
2127 /* Do nothing. */
2128 break;
2129 }
2130
2131 switch (right_handle_action) {
2133 BEZT_SEL_IDX(bezt, 2);
2134 break;
2136 BEZT_DESEL_IDX(bezt, 2);
2137 break;
2139 /* Do nothing. */
2140 break;
2141 }
2142 }
2143 }
2144
2145 /* Cleanup */
2146 ANIM_animdata_freelist(&anim_data);
2147}
2148
2150{
2151 bAnimContext ac;
2152
2153 /* Get editor data. */
2154 if (ANIM_animdata_get_context(C, &ac) == 0) {
2155 return OPERATOR_CANCELLED;
2156 }
2157
2158 const eGraphKey_SelectKeyHandles_Action left_handle_action =
2159 static_cast<eGraphKey_SelectKeyHandles_Action>(RNA_enum_get(op->ptr, "left_handle_action"));
2160 const eGraphKey_SelectKeyHandles_Action key_action =
2161 static_cast<eGraphKey_SelectKeyHandles_Action>(RNA_enum_get(op->ptr, "key_action"));
2162 const eGraphKey_SelectKeyHandles_Action right_handle_action =
2163 static_cast<eGraphKey_SelectKeyHandles_Action>(RNA_enum_get(op->ptr, "right_handle_action"));
2164
2165 graphkeys_select_key_handles(&ac, left_handle_action, key_action, right_handle_action);
2166
2168
2169 return OPERATOR_FINISHED;
2170}
2171
2173{
2174 /* identifiers */
2175 ot->name = "Select Key / Handles";
2176 ot->idname = "GRAPH_OT_select_key_handles";
2177 ot->description =
2178 "For selected keyframes, select/deselect any combination of the key itself and its handles";
2179
2180 /* callbacks */
2183
2184 /* flags */
2185 ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
2186
2187 RNA_def_enum(ot->srna,
2188 "left_handle_action",
2191 "Left Handle",
2192 "Effect on the left handle");
2193 RNA_def_enum(ot->srna,
2194 "right_handle_action",
2197 "Right Handle",
2198 "Effect on the right handle");
2199 RNA_def_enum(ot->srna,
2200 "key_action",
2203 "Key",
2204 "Effect on the key itself");
2205}
2206
int BKE_fcurve_active_keyframe_index(const FCurve *fcu)
float evaluate_fcurve_only_curve(const FCurve *fcu, float evaltime)
void BKE_fcurve_active_keyframe_set(FCurve *fcu, const BezTriple *active_bezt)
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:549
#define BLI_assert(a)
Definition BLI_assert.h:46
void BLI_lasso_boundbox(rcti *rect, blender::Span< blender::int2 > mcoords)
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void void BLI_listbase_rotate_last(ListBase *lb, void *vlink) ATTR_NONNULL(1
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:252
void void BLI_INLINE bool BLI_listbase_is_single(const ListBase *lb)
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:198
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
void BLI_rctf_rcti_copy(struct rctf *dst, const struct rcti *src)
#define FCURVE_ACTIVE_KEYFRAME_NONE
@ FCURVE_ACTIVE
@ FCURVE_SELECTED
@ FCURVE_PROTECTED
@ BEZT_IPO_BEZ
#define BEZT_DESEL_IDX(bezt, i)
#define BEZT_ISSEL_IDX(bezt, i)
#define BEZT_ISSEL_ANY(bezt)
#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_CANCELLED
@ OPERATOR_FINISHED
@ 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
@ KEYFRAME_ITER_HANDLES_INVISIBLE
short(*)(KeyframeEditData *ked, BezTriple *bezt) KeyframeEditFunc
@ SELMAP_MORE
@ SELMAP_LESS
eEditKeyframes_Select
@ SELECT_INVERT
@ SELECT_SUBTRACT
@ SELECT_REPLACE
@ SELECT_ADD
eSelectOp
@ SEL_OP_SUB
eSelectOp ED_select_op_modal(eSelectOp sel_op, bool is_first)
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
#define SEL_OP_USE_PRE_DESELECT(sel_op)
std::string ED_select_circle_get_name(wmOperatorType *ot, PointerRNA *ptr)
Read Guarded memory(de)allocation.
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
#define C
Definition RandGen.cpp:29
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:1702
float UI_view2d_region_to_view_x(const View2D *v2d, float x)
Definition view2d.cc:1657
void UI_view2d_region_to_view_rctf(const View2D *v2d, const rctf *rect_src, rctf *rect_dst) ATTR_NONNULL()
Definition view2d.cc:1675
#define NC_ANIMATION
Definition WM_types.hh:388
@ OPTYPE_DEPENDS_ON_CURSOR
Definition WM_types.hh:218
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define ND_KEYFRAME
Definition WM_types.hh:494
#define ND_ANIMCHAN
Definition WM_types.hh:496
#define NA_SELECTED
Definition WM_types.hh:589
static const EnumPropertyItem prop_column_select_types[]
void ANIM_anim_channels_select_set(bAnimContext *ac, eAnimChannels_SetFlag sel)
void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datatype, eAnimFilter_Flags filter, void *channel_data, eAnim_ChannelType channel_type)
void ANIM_animdata_freelist(ListBase *anim_data)
Definition anim_deps.cc:463
short ANIM_get_normalization_flags(SpaceLink *space_link)
Definition anim_draw.cc:415
void ANIM_nla_mapping_apply_if_needed_fcurve(bAnimListElem *ale, FCurve *fcu, const bool restore, const bool only_keys)
Definition anim_draw.cc:401
float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag, float *r_offset)
Definition anim_draw.cc:624
float ANIM_nla_tweakedit_remap(bAnimListElem *ale, const float cframe, const eNlaTime_ConvertModes mode)
Definition anim_draw.cc:324
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)
#define U
BMesh const char void * data
nullptr float
#define SELECT
#define filter
@ 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 wmOperatorStatus graphkeys_box_select_exec(bContext *C, wmOperator *op)
static wmOperatorStatus graphkeys_deselectall_exec(bContext *C, wmOperator *op)
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)
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)
#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 const EnumPropertyItem prop_graphkeys_leftright_select_types[]
static short ok_bezier_always_ok(KeyframeEditData *, BezTriple *)
void GRAPH_OT_select_lasso(wmOperatorType *ot)
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)
static wmOperatorStatus graphkeys_select_linked_exec(bContext *C, wmOperator *)
#define ABOVE
static wmOperatorStatus graphkeys_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus graphkeys_columnselect_exec(bContext *C, wmOperator *op)
void GRAPH_OT_select_circle(wmOperatorType *ot)
void GRAPH_OT_clickselect(wmOperatorType *ot)
void GRAPH_OT_select_more(wmOperatorType *ot)
static void graphkeys_select_leftright(bAnimContext *ac, short leftright, eEditKeyframes_Select select_mode)
#define GVERTSEL_TOL
static wmOperatorStatus graphkeys_clickselect_exec(bContext *C, wmOperator *op)
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)
static wmOperatorStatus graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
void GRAPH_OT_select_key_handles(wmOperatorType *ot)
static int initialize_animdata_selection_filter()
static wmOperatorStatus graphkeys_select_key_handles_exec(bContext *C, wmOperator *op)
void GRAPH_OT_select_leftright(wmOperatorType *ot)
static wmOperatorStatus 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)
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 wmOperatorStatus graphkeys_select_less_exec(bContext *C, wmOperator *)
static wmOperatorStatus graph_circle_select_exec(bContext *C, wmOperator *op)
static wmOperatorStatus graphkeys_mselect_column(bAnimContext *ac, const int mval[2], eEditKeyframes_Select select_mode, bool wait_to_deselect_others)
static wmOperatorStatus graphkeys_select_more_exec(bContext *C, wmOperator *)
static void select_moreless_graph_keys(bAnimContext *ac, short mode)
static wmOperatorStatus graphkeys_select_leftright_exec(bContext *C, wmOperator *op)
static bool rectf_curve_intersection(const float offset, const float unit_scale, const rctf *rectf, bAnimListElem *ale, const FCurve *fcu)
void GRAPH_OT_select_all(wmOperatorType *ot)
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 wmOperatorStatus graphkeys_select_leftright_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void GRAPH_OT_select_less(wmOperatorType *ot)
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_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
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.cc:36
float vec[3][3]
FPoint * fpt
BezTriple * bezt
unsigned int totvert
eKeyframeIterFlags iterflags
blender::Array< blender::int2 > mcoords
void * last
struct RenderData r
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:763
struct PointerRNA * ptr
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
void WM_event_drag_start_mval(const wmEvent *event, const ARegion *region, int r_mval[2])
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4237
bool WM_gesture_is_modal_first(const wmGesture *gesture)
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
wmOperatorStatus WM_gesture_circle_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Array< int2 > WM_gesture_lasso_path_to_array(bContext *, wmOperator *op)
wmOperatorStatus WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void WM_gesture_circle_cancel(bContext *C, wmOperator *op)
void WM_gesture_lasso_cancel(bContext *C, wmOperator *op)
wmOperatorStatus WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void WM_operator_properties_border_to_rcti(wmOperator *op, rcti *r_rect)
void WM_operator_properties_gesture_box(wmOperatorType *ot)
void WM_operator_properties_select_operation_simple(wmOperatorType *ot)
void WM_operator_properties_generic_select(wmOperatorType *ot)
void WM_operator_properties_gesture_lasso(wmOperatorType *ot)
void WM_operator_properties_gesture_circle(wmOperatorType *ot)
void WM_operator_properties_select_all(wmOperatorType *ot)
wmOperatorStatus WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_generic_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)