Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / animation / anim_draw.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Joshua Leung
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/animation/anim_draw.c
28  *  \ingroup edanimation
29  */
30
31 #include "BLI_sys_types.h"
32
33 #include "DNA_anim_types.h"
34 #include "DNA_scene_types.h"
35 #include "DNA_space_types.h"
36 #include "DNA_userdef_types.h"
37 #include "DNA_screen_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_gpencil_types.h"
40 #include "DNA_mask_types.h"
41
42 #include "BLI_math.h"
43 #include "BLI_timecode.h"
44 #include "BLI_utildefines.h"
45 #include "BLI_rect.h"
46 #include "BLI_dlrbTree.h"
47
48 #include "BKE_context.h"
49 #include "BKE_curve.h"
50 #include "BKE_fcurve.h"
51 #include "BKE_global.h"
52 #include "BKE_nla.h"
53 #include "BKE_mask.h"
54
55 #include "ED_anim_api.h"
56 #include "ED_keyframes_edit.h"
57 #include "ED_keyframes_draw.h"
58
59 #include "RNA_access.h"
60
61 #include "UI_interface.h"
62 #include "UI_resources.h"
63 #include "UI_view2d.h"
64
65 #include "GPU_immediate.h"
66 #include "GPU_matrix.h"
67
68 /* *************************************************** */
69 /* CURRENT FRAME DRAWING */
70
71 /* Draw current frame number in a little green box beside the current frame indicator */
72 void ANIM_draw_cfra_number(const bContext *C, View2D *v2d, short flag)
73 {
74         Scene *scene = CTX_data_scene(C);
75         const float time = scene->r.cfra + scene->r.subframe;
76         const float cfra = (float)(time * scene->r.framelen);
77         const bool show_time = (flag & DRAWCFRA_UNIT_SECONDS) != 0;
78
79         const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
80         unsigned char col[4];
81         float color[4];
82         float xscale, x, y;
83         char numstr[32] = "  t  ";  /* t is the character to start replacing from */
84         float hlen;
85         int slen;
86
87         /* because the frame number text is subject to the same scaling as the contents of the view */
88         UI_view2d_scale_get(v2d, &xscale, NULL);
89         gpuPushMatrix();
90         gpuScale2f(1.0f / xscale, 1.0f);
91
92         /* get timecode string
93          *      - padding on str-buf passed so that it doesn't sit on the frame indicator
94          */
95         if (show_time) {
96                 BLI_timecode_string_from_time(&numstr[2], sizeof(numstr) - 2, 0, FRA2TIME(cfra), FPS, U.timecode_style);
97         }
98         else {
99                 BLI_timecode_string_from_time_seconds(&numstr[2], sizeof(numstr) - 2, 1, cfra);
100         }
101
102         slen = UI_fontstyle_string_width(fstyle, numstr) - 1;
103         hlen = slen * 0.5f;
104
105         /* get starting coordinates for drawing */
106         x = cfra * xscale;
107         y = -0.1f * U.widget_unit;
108
109         /* draw green box around/behind text */
110         UI_GetThemeColor4fv(TH_CFRAME, color);
111         color[3] = 3.0f;
112
113         UI_draw_roundbox_corner_set(UI_CNR_ALL);
114         UI_draw_roundbox_aa(true,
115                             x - hlen - 0.1f * U.widget_unit,
116                             y + 3.0f,
117                             x + hlen + 0.1f * U.widget_unit,
118                             y -3.0f + U.widget_unit,
119                             0.1f * U.widget_unit,
120                             color);
121
122         /* draw current frame number */
123         UI_GetThemeColor4ubv(TH_TEXT_HI, col);
124         UI_fontstyle_draw_simple(fstyle,
125                                  x - hlen - 0.15f * U.widget_unit,
126                                  y        + 0.28f * U.widget_unit,
127                                  numstr, col);
128
129         /* restore view transform */
130         gpuPopMatrix();
131 }
132
133 /* General call for drawing current frame indicator in animation editor */
134 void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag)
135 {
136         Scene *scene = CTX_data_scene(C);
137
138         const float time = scene->r.cfra + scene->r.subframe;
139         const float x = (float)(time * scene->r.framelen);
140
141         glLineWidth((flag & DRAWCFRA_WIDE) ? 3.0 : 2.0);
142
143         Gwn_VertFormat *format = immVertexFormat();
144         unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
145
146         immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
147
148         /* Draw a light green line to indicate current frame */
149         immUniformThemeColor(TH_CFRAME);
150
151         immBegin(GWN_PRIM_LINES, 2);
152         immVertex2f(pos, x, v2d->cur.ymin - 500.0f); /* XXX arbitrary... want it go to bottom */
153         immVertex2f(pos, x, v2d->cur.ymax);
154         immEnd();
155         immUnbindProgram();
156 }
157
158 /* *************************************************** */
159 /* PREVIEW RANGE 'CURTAINS' */
160 /* Note: 'Preview Range' tools are defined in anim_ops.c */
161
162 /* Draw preview range 'curtains' for highlighting where the animation data is */
163 void ANIM_draw_previewrange(const bContext *C, View2D *v2d, int end_frame_width)
164 {
165         Scene *scene = CTX_data_scene(C);
166
167         /* only draw this if preview range is set */
168         if (PRVRANGEON) {
169                 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
170                 glEnable(GL_BLEND);
171
172                 Gwn_VertFormat *format = immVertexFormat();
173                 unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
174
175                 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
176                 immUniformThemeColorShadeAlpha(TH_ANIM_ACTIVE, -25, -30);
177                 //immUniformColor4f(0.8f, 0.44f, 0.1f, 0.2f); /* XXX: Fix this hardcoded color (anim_active) */
178
179                 /* only draw two separate 'curtains' if there's no overlap between them */
180                 if (PSFRA < PEFRA + end_frame_width) {
181                         immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
182                         immRectf(pos, (float)(PEFRA + end_frame_width), v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
183                 }
184                 else {
185                         immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
186                 }
187
188                 immUnbindProgram();
189
190                 glDisable(GL_BLEND);
191         }
192 }
193
194 /* *************************************************** */
195 /* SCENE FRAME RANGE */
196
197 /* Draw frame range guides (for scene frame range) in background */
198 // TODO: Should we still show these when preview range is enabled?
199 void ANIM_draw_framerange(Scene *scene, View2D *v2d)
200 {
201         /* draw darkened area outside of active timeline frame range */
202         glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
203         glEnable(GL_BLEND);
204
205         Gwn_VertFormat *format = immVertexFormat();
206         unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
207
208         immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
209         immUniformThemeColorShadeAlpha(TH_BACK, -25, -100);
210
211         if (SFRA < EFRA) {
212                 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)SFRA, v2d->cur.ymax);
213                 immRectf(pos, (float)EFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
214         }
215         else {
216                 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
217         }
218
219         glDisable(GL_BLEND);
220
221         /* thin lines where the actual frames are */
222         immUniformThemeColorShade(TH_BACK, -60);
223
224         immBegin(GWN_PRIM_LINES, 4);
225
226         immVertex2f(pos, (float)SFRA, v2d->cur.ymin);
227         immVertex2f(pos, (float)SFRA, v2d->cur.ymax);
228
229         immVertex2f(pos, (float)EFRA, v2d->cur.ymin);
230         immVertex2f(pos, (float)EFRA, v2d->cur.ymax);
231
232         immEnd();
233         immUnbindProgram();
234 }
235
236 /* *************************************************** */
237 /* NLA-MAPPING UTILITIES (required for drawing and also editing keyframes)  */
238
239 /* Obtain the AnimData block providing NLA-mapping for the given channel (if applicable) */
240 // TODO: do not supply return this if the animdata tells us that there is no mapping to perform
241 AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
242 {
243         /* sanity checks */
244         if (ac == NULL)
245                 return NULL;
246
247         /* abort if rendering - we may get some race condition issues... */
248         if (G.is_rendering) return NULL;
249
250         /* apart from strictly keyframe-related contexts, this shouldn't even happen */
251         // XXX: nla and channel here may not be necessary...
252         if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_SHAPEKEY, ANIMCONT_DOPESHEET,
253                                ANIMCONT_FCURVES, ANIMCONT_NLA, ANIMCONT_CHANNEL))
254         {
255                 /* handling depends on the type of animation-context we've got */
256                 if (ale) {
257                         /* NLA Control Curves occur on NLA strips, and shouldn't be subjected to this kind of mapping */
258                         if (ale->type != ANIMTYPE_NLACURVE)
259                                 return ale->adt;
260                 }
261         }
262
263         /* cannot handle... */
264         return NULL;
265 }
266
267 /* ------------------- */
268
269 /* helper function for ANIM_nla_mapping_apply_fcurve() -> "restore", i.e. mapping points back to action-time */
270 static short bezt_nlamapping_restore(KeyframeEditData *ked, BezTriple *bezt)
271 {
272         /* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */
273         AnimData *adt = (AnimData *)ked->data;
274         short only_keys = (short)ked->i1;
275
276         /* adjust BezTriple handles only if allowed to */
277         if (only_keys == 0) {
278                 bezt->vec[0][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_UNMAP);
279                 bezt->vec[2][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_UNMAP);
280         }
281
282         bezt->vec[1][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_UNMAP);
283
284         return 0;
285 }
286
287 /* helper function for ANIM_nla_mapping_apply_fcurve() -> "apply", i.e. mapping points to NLA-mapped global time */
288 static short bezt_nlamapping_apply(KeyframeEditData *ked, BezTriple *bezt)
289 {
290         /* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */
291         AnimData *adt = (AnimData *)ked->data;
292         short only_keys = (short)ked->i1;
293
294         /* adjust BezTriple handles only if allowed to */
295         if (only_keys == 0) {
296                 bezt->vec[0][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_MAP);
297                 bezt->vec[2][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_MAP);
298         }
299
300         bezt->vec[1][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_MAP);
301
302         return 0;
303 }
304
305
306 /* Apply/Unapply NLA mapping to all keyframes in the nominated F-Curve
307  *      - restore = whether to map points back to non-mapped time
308  *  - only_keys = whether to only adjust the location of the center point of beztriples
309  */
310 void ANIM_nla_mapping_apply_fcurve(AnimData *adt, FCurve *fcu, bool restore, bool only_keys)
311 {
312         KeyframeEditData ked = {{NULL}};
313         KeyframeEditFunc map_cb;
314
315         /* init edit data
316          *      - AnimData is stored in 'data'
317          *      - only_keys is stored in 'i1'
318          */
319         ked.data = (void *)adt;
320         ked.i1 = (int)only_keys;
321
322         /* get editing callback */
323         if (restore)
324                 map_cb = bezt_nlamapping_restore;
325         else
326                 map_cb = bezt_nlamapping_apply;
327
328         /* apply to F-Curve */
329         ANIM_fcurve_keyframes_loop(&ked, fcu, NULL, map_cb, NULL);
330 }
331
332 /* *************************************************** */
333 /* UNITS CONVERSION MAPPING (required for drawing and editing keyframes) */
334
335 /* Get flags used for normalization in ANIM_unit_mapping_get_factor. */
336 short ANIM_get_normalization_flags(bAnimContext *ac)
337 {
338         if (ac->sl->spacetype == SPACE_IPO) {
339                 SpaceIpo *sipo = (SpaceIpo *) ac->sl;
340                 bool use_normalization = (sipo->flag & SIPO_NORMALIZE) != 0;
341                 bool freeze_normalization = (sipo->flag & SIPO_NORMALIZE_FREEZE) != 0;
342                 return use_normalization
343                     ? (ANIM_UNITCONV_NORMALIZE |  (freeze_normalization ? ANIM_UNITCONV_NORMALIZE_FREEZE : 0))
344                     : 0;
345         }
346
347         return 0;
348 }
349
350 static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, float *r_offset)
351 {
352         float factor = 1.0f, offset = 0.0f;
353
354         if (flag & ANIM_UNITCONV_RESTORE) {
355                 if (r_offset)
356                         *r_offset = fcu->prev_offset;
357
358                 return 1.0f / fcu->prev_norm_factor;
359         }
360
361         if (flag & ANIM_UNITCONV_NORMALIZE_FREEZE) {
362                 if (r_offset)
363                         *r_offset = fcu->prev_offset;
364                 if (fcu->prev_norm_factor == 0.0f) {
365                         /* Happens when Auto Normalize was disabled before
366                          * any curves were displayed.
367                          */
368                         return 1.0f;
369                 }
370                 return fcu->prev_norm_factor;
371         }
372
373         if (G.moving & G_TRANSFORM_FCURVES) {
374                 if (r_offset)
375                         *r_offset = fcu->prev_offset;
376                 if (fcu->prev_norm_factor == 0.0f) {
377                         /* Same as above. */
378                         return 1.0f;
379                 }
380                 return fcu->prev_norm_factor;
381         }
382
383         fcu->prev_norm_factor = 1.0f;
384         if (fcu->bezt) {
385                 const bool use_preview_only = PRVRANGEON;
386                 const BezTriple *bezt;
387                 int i;
388                 float max_coord = -FLT_MAX;
389                 float min_coord = FLT_MAX;
390                 float range;
391
392                 if (fcu->totvert < 1) {
393                         return 1.0f;
394                 }
395
396                 for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
397                         if (use_preview_only && !IN_RANGE_INCL(bezt->vec[1][0],
398                                                                scene->r.psfra,
399                                                                scene->r.pefra))
400                         {
401                                 continue;
402                         }
403
404                         if (i == 0) {
405                                 /* We ignore extrapolation flags and handle here, and use the
406                                  * control point position only. so we normalize "interesting"
407                                  * part of the curve.
408                                  *
409                                  * Here we handle left extrapolation.
410                                  */
411                                 max_coord = max_ff(max_coord, bezt->vec[1][1]);
412
413                                 min_coord = min_ff(min_coord, bezt->vec[1][1]);
414                         }
415                         else {
416                                 const BezTriple *prev_bezt = bezt - 1;
417                                 if (prev_bezt->ipo == BEZT_IPO_CONST) {
418                                         /* Constant interpolation: previous CV value is used up
419                                          * to the current keyframe.
420                                          */
421                                         max_coord = max_ff(max_coord, bezt->vec[1][1]);
422                                         min_coord = min_ff(min_coord, bezt->vec[1][1]);
423                                 }
424                                 else if (prev_bezt->ipo == BEZT_IPO_LIN) {
425                                         /* Linear interpolation: min/max using both previous and
426                                          * and current CV.
427                                          */
428                                         max_coord = max_ff(max_coord, bezt->vec[1][1]);
429                                         min_coord = min_ff(min_coord, bezt->vec[1][1]);
430                                         max_coord = max_ff(max_coord, prev_bezt->vec[1][1]);
431                                         min_coord = min_ff(min_coord, prev_bezt->vec[1][1]);
432                                 }
433                                 else if (prev_bezt->ipo == BEZT_IPO_BEZ) {
434                                         const int resol = fcu->driver
435                                                 ? 32
436                                                 : min_ii((int)(5.0f * len_v2v2(bezt->vec[1], prev_bezt->vec[1])), 32);
437                                         if (resol < 2) {
438                                                 max_coord = max_ff(max_coord, prev_bezt->vec[1][1]);
439                                                 min_coord = min_ff(min_coord, prev_bezt->vec[1][1]);
440                                         }
441                                         else {
442                                                 float data[120];
443                                                 float v1[2], v2[2], v3[2], v4[2];
444
445                                                 v1[0] = prev_bezt->vec[1][0];
446                                                 v1[1] = prev_bezt->vec[1][1];
447                                                 v2[0] = prev_bezt->vec[2][0];
448                                                 v2[1] = prev_bezt->vec[2][1];
449
450                                                 v3[0] = bezt->vec[0][0];
451                                                 v3[1] = bezt->vec[0][1];
452                                                 v4[0] = bezt->vec[1][0];
453                                                 v4[1] = bezt->vec[1][1];
454
455                                                 correct_bezpart(v1, v2, v3, v4);
456
457                                                 BKE_curve_forward_diff_bezier(v1[0], v2[0], v3[0], v4[0], data, resol, sizeof(float) * 3);
458                                                 BKE_curve_forward_diff_bezier(v1[1], v2[1], v3[1], v4[1], data + 1, resol, sizeof(float) * 3);
459
460                                                 for (int j = 0; j <= resol; ++j) {
461                                                         const float *fp = &data[j * 3];
462                                                         max_coord = max_ff(max_coord, fp[1]);
463                                                         min_coord = min_ff(min_coord, fp[1]);
464                                                 }
465                                         }
466                                 }
467                         }
468                 }
469
470                 if (max_coord > min_coord) {
471                         range = max_coord - min_coord;
472                         if (range > FLT_EPSILON) {
473                                 factor = 2.0f / range;
474                         }
475                         offset = -min_coord - range / 2.0f;
476                 }
477                 else if (max_coord == min_coord) {
478                         factor = 1.0f;
479                         offset = -min_coord;
480                 }
481         }
482         BLI_assert(factor != 0.0f);
483         if (r_offset) {
484                 *r_offset = offset;
485         }
486
487         fcu->prev_norm_factor = factor;
488         fcu->prev_offset = offset;
489         return factor;
490 }
491
492 /* Get unit conversion factor for given ID + F-Curve */
493 float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag, float *r_offset)
494 {
495         if (flag & ANIM_UNITCONV_NORMALIZE) {
496                 return normalization_factor_get(scene, fcu, flag, r_offset);
497         }
498
499         if (r_offset)
500                 *r_offset = 0.0f;
501
502         /* sanity checks */
503         if (id && fcu && fcu->rna_path) {
504                 PointerRNA ptr, id_ptr;
505                 PropertyRNA *prop;
506
507                 /* get RNA property that F-Curve affects */
508                 RNA_id_pointer_create(id, &id_ptr);
509                 if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
510                         /* rotations: radians <-> degrees? */
511                         if (RNA_SUBTYPE_UNIT(RNA_property_subtype(prop)) == PROP_UNIT_ROTATION) {
512                                 /* if the radians flag is not set, default to using degrees which need conversions */
513                                 if ((scene) && (scene->unit.system_rotation == USER_UNIT_ROT_RADIANS) == 0) {
514                                         if (flag & ANIM_UNITCONV_RESTORE)
515                                                 return DEG2RADF(1.0f);  /* degrees to radians */
516                                         else
517                                                 return RAD2DEGF(1.0f);  /* radians to degrees */
518                                 }
519                         }
520
521                         /* TODO: other rotation types here as necessary */
522                 }
523         }
524
525         /* no mapping needs to occur... */
526         return 1.0f;
527 }
528
529 static bool find_prev_next_keyframes(struct bContext *C, int *nextfra, int *prevfra)
530 {
531         Scene *scene = CTX_data_scene(C);
532         Object *ob = CTX_data_active_object(C);
533         Mask *mask = CTX_data_edit_mask(C);
534         bDopeSheet ads = {NULL};
535         DLRBT_Tree keys;
536         ActKeyColumn *aknext, *akprev;
537         float cfranext, cfraprev;
538         bool donenext = false, doneprev = false;
539         int nextcount = 0, prevcount = 0;
540
541         cfranext = cfraprev = (float)(CFRA);
542
543         /* init binarytree-list for getting keyframes */
544         BLI_dlrbTree_init(&keys);
545
546         /* seed up dummy dopesheet context with flags to perform necessary filtering */
547         if ((scene->flag & SCE_KEYS_NO_SELONLY) == 0) {
548                 /* only selected channels are included */
549                 ads.filterflag |= ADS_FILTER_ONLYSEL;
550         }
551
552         /* populate tree with keyframe nodes */
553         scene_to_keylist(&ads, scene, &keys, NULL);
554         gpencil_to_keylist(&ads, scene->gpd, &keys);
555
556         if (ob) {
557                 ob_to_keylist(&ads, ob, &keys, NULL);
558                 gpencil_to_keylist(&ads, ob->gpd, &keys);
559         }
560
561         if (mask) {
562                 MaskLayer *masklay = BKE_mask_layer_active(mask);
563                 mask_to_keylist(&ads, masklay, &keys);
564         }
565
566         /* build linked-list for searching */
567         BLI_dlrbTree_linkedlist_sync(&keys);
568
569         /* find matching keyframe in the right direction */
570         do {
571                 aknext = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfranext);
572
573                 if (aknext) {
574                         if (CFRA == (int)aknext->cfra) {
575                                 /* make this the new starting point for the search and ignore */
576                                 cfranext = aknext->cfra;
577                         }
578                         else {
579                                 /* this changes the frame, so set the frame and we're done */
580                                 if (++nextcount == U.view_frame_keyframes)
581                                         donenext = true;
582                         }
583                         cfranext = aknext->cfra;
584                 }
585         } while ((aknext != NULL) && (donenext == false));
586
587         do {
588                 akprev = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &cfraprev);
589
590                 if (akprev) {
591                         if (CFRA == (int)akprev->cfra) {
592                                 /* make this the new starting point for the search */
593                         }
594                         else {
595                                 /* this changes the frame, so set the frame and we're done */
596                                 if (++prevcount == U.view_frame_keyframes)
597                                         doneprev = true;
598                         }
599                         cfraprev = akprev->cfra;
600                 }
601         } while ((akprev != NULL) && (doneprev == false));
602
603         /* free temp stuff */
604         BLI_dlrbTree_free(&keys);
605
606         /* any success? */
607         if (doneprev || donenext) {
608                 if (doneprev)
609                         *prevfra = cfraprev;
610                 else
611                         *prevfra = CFRA - (cfranext - CFRA);
612
613                 if (donenext)
614                         *nextfra = cfranext;
615                 else
616                         *nextfra = CFRA + (CFRA - cfraprev);
617
618                 return true;
619         }
620
621         return false;
622 }
623
624 void ANIM_center_frame(struct bContext *C, int smooth_viewtx)
625 {
626         ARegion *ar = CTX_wm_region(C);
627         Scene *scene = CTX_data_scene(C);
628         float w = BLI_rctf_size_x(&ar->v2d.cur);
629         rctf newrct;
630         int nextfra, prevfra;
631
632         switch (U.view_frame_type) {
633                 case ZOOM_FRAME_MODE_SECONDS:
634                 {
635                         const float fps = FPS;
636                         newrct.xmax = scene->r.cfra + U.view_frame_seconds * fps + 1;
637                         newrct.xmin = scene->r.cfra - U.view_frame_seconds * fps - 1;
638                         newrct.ymax = ar->v2d.cur.ymax;
639                         newrct.ymin = ar->v2d.cur.ymin;
640                         break;
641                 }
642
643                 /* hardest case of all, look for all keyframes around frame and display those */
644                 case ZOOM_FRAME_MODE_KEYFRAMES:
645                         if (find_prev_next_keyframes(C, &nextfra, &prevfra)) {
646                                 newrct.xmax = nextfra;
647                                 newrct.xmin = prevfra;
648                                 newrct.ymax = ar->v2d.cur.ymax;
649                                 newrct.ymin = ar->v2d.cur.ymin;
650                                 break;
651                         }
652                         /* else drop through, keep range instead */
653                         ATTR_FALLTHROUGH;
654
655                 case ZOOM_FRAME_MODE_KEEP_RANGE:
656                 default:
657                         newrct.xmax = scene->r.cfra + (w / 2);
658                         newrct.xmin = scene->r.cfra - (w / 2);
659                         newrct.ymax = ar->v2d.cur.ymax;
660                         newrct.ymin = ar->v2d.cur.ymin;
661                         break;
662         }
663
664         UI_view2d_smooth_view(C, ar, &newrct, smooth_viewtx);
665 }
666 /* *************************************************** */