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