Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / space_time / space_time.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): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_time/space_time.c
28  *  \ingroup sptime
29  */
30
31
32 #include <string.h>
33 #include <stdio.h>
34
35 #include "DNA_cachefile_types.h"
36 #include "DNA_constraint_types.h"
37 #include "DNA_gpencil_types.h"
38 #include "DNA_modifier_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_scene_types.h"
41
42 #include "MEM_guardedalloc.h"
43
44 #include "BLI_blenlib.h"
45 #include "BLI_dlrbTree.h"
46 #include "BLI_utildefines.h"
47
48 #include "BKE_constraint.h"
49 #include "BKE_context.h"
50 #include "BKE_main.h"
51 #include "BKE_modifier.h"
52 #include "BKE_screen.h"
53 #include "BKE_pointcache.h"
54
55 #include "ED_anim_api.h"
56 #include "ED_keyframes_draw.h"
57 #include "ED_screen.h"
58
59 #include "WM_api.h"
60 #include "WM_types.h"
61
62 #include "BIF_gl.h"
63
64 #include "UI_resources.h"
65 #include "UI_view2d.h"
66 #include "UI_interface.h"
67
68 #include "ED_space_api.h"
69 #include "ED_markers.h"
70
71 #include "GPU_immediate.h"
72 #include "GPU_matrix.h"
73
74 #include "time_intern.h"
75
76 /* ************************ main time area region *********************** */
77
78 static void time_draw_sfra_efra(Scene *scene, View2D *v2d)
79 {       
80         /* draw darkened area outside of active timeline 
81          * frame range used is preview range or scene range 
82          */
83         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
84         glEnable(GL_BLEND);
85
86         Gwn_VertFormat *format = immVertexFormat();
87         unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
88
89         immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
90         immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
91
92         if (PSFRA < PEFRA) {
93                 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
94                 immRectf(pos, (float)PEFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
95         }
96         else {
97                 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
98         }
99
100         glDisable(GL_BLEND);
101
102         /* thin lines where the actual frames are */
103         immUniformThemeColorShade(TH_BACK, -60);
104
105         immBegin(GWN_PRIM_LINES, 4);
106
107         immVertex2f(pos, (float)PSFRA, v2d->cur.ymin);
108         immVertex2f(pos, (float)PSFRA, v2d->cur.ymax);
109
110         immVertex2f(pos, (float)PEFRA, v2d->cur.ymin);
111         immVertex2f(pos, (float)PEFRA, v2d->cur.ymax);
112
113         immEnd();
114         immUnbindProgram();
115 }
116
117 static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene)
118 {
119         PTCacheID *pid;
120         ListBase pidlist;
121         const float cache_draw_height = (4.0f * UI_DPI_FAC * U.pixelsize);
122         float yoffs = 0.f;
123         
124         if (!(stime->cache_display & TIME_CACHE_DISPLAY) || (!ob))
125                 return;
126
127         BKE_ptcache_ids_from_object(&pidlist, ob, scene, 0);
128
129         unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
130         immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
131
132         /* iterate over pointcaches on the active object, 
133          * add spacetimecache and vertex array for each */
134         for (pid = pidlist.first; pid; pid = pid->next) {
135                 float col[4];
136
137                 switch (pid->type) {
138                         case PTCACHE_TYPE_SOFTBODY:
139                                 if (!(stime->cache_display & TIME_CACHE_SOFTBODY)) continue;
140                                 break;
141                         case PTCACHE_TYPE_PARTICLES:
142                                 if (!(stime->cache_display & TIME_CACHE_PARTICLES)) continue;
143                                 break;
144                         case PTCACHE_TYPE_CLOTH:
145                                 if (!(stime->cache_display & TIME_CACHE_CLOTH)) continue;
146                                 break;
147                         case PTCACHE_TYPE_SMOKE_DOMAIN:
148                         case PTCACHE_TYPE_SMOKE_HIGHRES:
149                                 if (!(stime->cache_display & TIME_CACHE_SMOKE)) continue;
150                                 break;
151                         case PTCACHE_TYPE_DYNAMICPAINT:
152                                 if (!(stime->cache_display & TIME_CACHE_DYNAMICPAINT)) continue;
153                                 break;
154                         case PTCACHE_TYPE_RIGIDBODY:
155                                 if (!(stime->cache_display & TIME_CACHE_RIGIDBODY)) continue;
156                                 break;
157                 }
158
159                 if (pid->cache->cached_frames == NULL)
160                         continue;
161
162                 gpuPushMatrix();
163                 gpuTranslate2f(0.0, (float)V2D_SCROLL_HEIGHT + yoffs);
164                 gpuScale2f(1.0, cache_draw_height);
165                 
166                 switch (pid->type) {
167                         case PTCACHE_TYPE_SOFTBODY:
168                                 col[0] = 1.0;   col[1] = 0.4;   col[2] = 0.02;
169                                 col[3] = 0.1;
170                                 break;
171                         case PTCACHE_TYPE_PARTICLES:
172                                 col[0] = 1.0;   col[1] = 0.1;   col[2] = 0.02;
173                                 col[3] = 0.1;
174                                 break;
175                         case PTCACHE_TYPE_CLOTH:
176                                 col[0] = 0.1;   col[1] = 0.1;   col[2] = 0.75;
177                                 col[3] = 0.1;
178                                 break;
179                         case PTCACHE_TYPE_SMOKE_DOMAIN:
180                         case PTCACHE_TYPE_SMOKE_HIGHRES:
181                                 col[0] = 0.2;   col[1] = 0.2;   col[2] = 0.2;
182                                 col[3] = 0.1;
183                                 break;
184                         case PTCACHE_TYPE_DYNAMICPAINT:
185                                 col[0] = 1.0;   col[1] = 0.1;   col[2] = 0.75;
186                                 col[3] = 0.1;
187                                 break;
188                         case PTCACHE_TYPE_RIGIDBODY:
189                                 col[0] = 1.0;   col[1] = 0.6;   col[2] = 0.0;
190                                 col[3] = 0.1;
191                                 break;
192                         default:
193                                 col[0] = 1.0;   col[1] = 0.0;   col[2] = 1.0;
194                                 col[3] = 0.1;
195                                 BLI_assert(0);
196                                 break;
197                 }
198
199                 const int sta = pid->cache->startframe, end = pid->cache->endframe;
200                 const int len = (end - sta + 1) * 6;
201
202                 glEnable(GL_BLEND);
203
204                 immUniformColor4fv(col);
205                 immRectf(pos, (float)sta, 0.0, (float)end, 1.0);
206
207                 col[3] = 0.4f;
208                 if (pid->cache->flag & PTCACHE_BAKED) {
209                         col[0] -= 0.4f; col[1] -= 0.4f; col[2] -= 0.4f;
210                 }
211                 else if (pid->cache->flag & PTCACHE_OUTDATED) {
212                         col[0] += 0.4f; col[1] += 0.4f; col[2] += 0.4f;
213                 }
214
215                 immUniformColor4fv(col);
216
217                 if (len > 0) {
218                         immBeginAtMost(GWN_PRIM_TRIS, len);
219
220                         /* draw a quad for each cached frame */
221                         for (int i = sta; i <= end; i++) {
222                                 if (pid->cache->cached_frames[i - sta]) {
223                                         immVertex2f(pos, (float)i - 0.5f, 0.0f);
224                                         immVertex2f(pos, (float)i - 0.5f, 1.0f);
225                                         immVertex2f(pos, (float)i + 0.5f, 1.0f);
226
227                                         immVertex2f(pos, (float)i - 0.5f, 0.0f);
228                                         immVertex2f(pos, (float)i + 0.5f, 1.0f);
229                                         immVertex2f(pos, (float)i + 0.5f, 0.0f);
230                                 }
231                         }
232
233                         immEnd();
234                 }
235
236                 glDisable(GL_BLEND);
237
238                 gpuPopMatrix();
239
240                 yoffs += cache_draw_height;
241         }
242
243         immUnbindProgram();
244
245         BLI_freelistN(&pidlist);
246 }
247
248 /* helper function - find actkeycolumn that occurs on cframe, or the nearest one if not found */
249 static ActKeyColumn *time_cfra_find_ak(ActKeyColumn *ak, float cframe)
250 {
251         ActKeyColumn *akn = NULL;
252         
253         /* sanity checks */
254         if (ak == NULL)
255                 return NULL;
256         
257         /* check if this is a match, or whether it is in some subtree */
258         if (cframe < ak->cfra)
259                 akn = time_cfra_find_ak(ak->left, cframe);
260         else if (cframe > ak->cfra)
261                 akn = time_cfra_find_ak(ak->right, cframe);
262                 
263         /* if no match found (or found match), just use the current one */
264         if (akn == NULL)
265                 return ak;
266         else
267                 return akn;
268 }
269
270 /* helper for time_draw_keyframes() */
271 static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel, const unsigned char color[3])
272 {
273         bDopeSheet ads = {NULL};
274         DLRBT_Tree keys;
275         ActKeyColumn *ak;
276         
277         float fac1 = (GS(id->name) == ID_GD) ? 0.8f : 0.6f; /* draw GPencil keys taller, to help distinguish them */
278         float fac2 = 1.0f - fac1;
279         
280         float ymin = v2d->tot.ymin;
281         float ymax = v2d->tot.ymax * fac1 + ymin * fac2;
282         
283         /* init binarytree-list for getting keyframes */
284         BLI_dlrbTree_init(&keys);
285         
286         /* init dopesheet settings */
287         if (onlysel)
288                 ads.filterflag |= ADS_FILTER_ONLYSEL;
289
290         /* populate tree with keyframe nodes */
291         switch (GS(id->name)) {
292                 case ID_SCE:
293                         scene_to_keylist(&ads, (Scene *)id, &keys, NULL);
294                         break;
295                 case ID_OB:
296                         ob_to_keylist(&ads, (Object *)id, &keys, NULL);
297                         break;
298                 case ID_GD:
299                         gpencil_to_keylist(&ads, (bGPdata *)id, &keys);
300                         break;
301                 case ID_CF:
302                         cachefile_to_keylist(&ads, (CacheFile *)id, &keys, NULL);
303                         break;
304                 default:
305                         break;
306         }
307                 
308         /* build linked-list for searching */
309         BLI_dlrbTree_linkedlist_sync(&keys);
310         
311         /* start drawing keyframes 
312          *      - we use the binary-search capabilities of the tree to only start from 
313          *        the first visible keyframe (last one can then be easily checked)
314          *      - draw within a single GL block to be faster
315          */
316
317         ActKeyColumn *link;
318         int max_len = 0;
319
320         ak = time_cfra_find_ak(keys.root, v2d->cur.xmin);
321
322         for (link = ak; link; link = link->next) {
323                 max_len++;
324         }
325
326         if (max_len > 0) {
327
328                 Gwn_VertFormat *format = immVertexFormat();
329                 unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
330
331                 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
332                 immUniformColor3ubv(color);
333
334                 immBeginAtMost(GWN_PRIM_LINES, max_len * 2);
335
336                 for (; (ak) && (ak->cfra <= v2d->cur.xmax);
337                         ak = ak->next)
338                 {
339                         immVertex2f(pos, ak->cfra, ymin);
340                         immVertex2f(pos, ak->cfra, ymax);
341                 }
342
343                 immEnd();
344                 immUnbindProgram();
345         }
346
347         /* free temp stuff */
348         BLI_dlrbTree_free(&keys);
349 }
350
351 static void time_draw_caches_keyframes(Main *bmain, SceneLayer *sl, View2D *v2d, bool onlysel, const unsigned char color[3])
352 {
353         CacheFile *cache_file;
354
355         for (cache_file = bmain->cachefiles.first;
356              cache_file;
357              cache_file = cache_file->id.next)
358         {
359                 cache_file->draw_flag &= ~CACHEFILE_KEYFRAME_DRAWN;
360         }
361
362         for (Base *base = sl->object_bases.first; base; base = base->next) {
363                 Object *ob = base->object;
364
365                 ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
366
367                 if (md) {
368                         MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
369
370                         cache_file = mcmd->cache_file;
371
372                         if (!cache_file || (cache_file->draw_flag & CACHEFILE_KEYFRAME_DRAWN) != 0) {
373                                 continue;
374                         }
375
376                         cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN;
377
378                         time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel, color);
379                 }
380
381                 for (bConstraint *con = ob->constraints.first; con; con = con->next) {
382                         if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
383                                 continue;
384                         }
385
386                         bTransformCacheConstraint *data = con->data;
387
388                         cache_file = data->cache_file;
389
390                         if (!cache_file || (cache_file->draw_flag & CACHEFILE_KEYFRAME_DRAWN) != 0) {
391                                 continue;
392                         }
393
394                         cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN;
395
396                         time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel, color);
397                 }
398         }
399 }
400
401 /* draw keyframe lines for timeline */
402 static void time_draw_keyframes(const bContext *C, ARegion *ar)
403 {
404         Scene *scene = CTX_data_scene(C);
405         SceneLayer *sl = CTX_data_scene_layer(C);
406         Object *ob = CTX_data_active_object(C);
407         View2D *v2d = &ar->v2d;
408         bool onlysel = ((scene->flag & SCE_KEYS_NO_SELONLY) == 0);
409         unsigned char color[3];
410         
411         /* set this for all keyframe lines once and for all */
412         glLineWidth(1.0);
413
414         /* draw cache files keyframes (if available) */
415         UI_GetThemeColor3ubv(TH_TIME_KEYFRAME, color);
416         time_draw_caches_keyframes(CTX_data_main(C), sl, v2d, onlysel, color);
417
418         /* draw grease pencil keyframes (if available) */       
419         UI_GetThemeColor3ubv(TH_TIME_GP_KEYFRAME, color);
420
421         if (scene->gpd) {
422                 time_draw_idblock_keyframes(v2d, (ID *)scene->gpd, onlysel, color);
423         }
424         if (ob && ob->gpd) {
425                 time_draw_idblock_keyframes(v2d, (ID *)ob->gpd, onlysel, color);
426         }
427         
428         /* draw scene keyframes first 
429          *      - don't try to do this when only drawing active/selected data keyframes,
430          *        since this can become quite slow
431          */
432         if (onlysel == 0) {
433                 /* set draw color */
434                 UI_GetThemeColorShade3ubv(TH_TIME_KEYFRAME, -50, color);
435                 time_draw_idblock_keyframes(v2d, (ID *)scene, onlysel, color);
436         }
437         
438         /* draw keyframes from selected objects 
439          *  - only do the active object if in posemode (i.e. showing only keyframes for the bones)
440          *    OR the onlysel flag was set, which means that only active object's keyframes should
441          *    be considered
442          */
443         UI_GetThemeColor3ubv(TH_TIME_KEYFRAME, color);
444
445         if (ob && ((ob->mode == OB_MODE_POSE) || onlysel)) {
446                 /* draw keyframes for active object only */
447                 time_draw_idblock_keyframes(v2d, (ID *)ob, onlysel, color);
448         }
449         else {
450                 bool active_done = false;
451                 
452                 /* draw keyframes from all selected objects */
453                 CTX_DATA_BEGIN (C, Object *, obsel, selected_objects)
454                 {
455                         /* last arg is 0, since onlysel doesn't apply here... */
456                         time_draw_idblock_keyframes(v2d, (ID *)obsel, 0, color);
457                         
458                         /* if this object is the active one, set flag so that we don't draw again */
459                         if (obsel == ob)
460                                 active_done = true;
461                 }
462                 CTX_DATA_END;
463                 
464                 /* if active object hasn't been done yet, draw it... */
465                 if (ob && (active_done == 0))
466                         time_draw_idblock_keyframes(v2d, (ID *)ob, 0, color);
467         }
468 }
469
470 /* ---------------- */
471
472 /* editor level listener */
473 static void time_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, const Scene *UNUSED(scene))
474 {
475
476         /* mainly for updating cache display */
477         switch (wmn->category) {
478                 case NC_OBJECT:
479                 {
480                         switch (wmn->data) {
481                                 case ND_BONE_SELECT:
482                                 case ND_BONE_ACTIVE:
483                                 case ND_POINTCACHE:
484                                 case ND_MODIFIER:
485                                 case ND_PARTICLE:
486                                 case ND_KEYS:
487                                         ED_area_tag_refresh(sa);
488                                         ED_area_tag_redraw(sa);
489                                         break;
490                         }
491                         break;
492                 }
493                 case NC_SCENE:
494                 {
495                         switch (wmn->data) {
496                                 case ND_RENDER_RESULT:
497                                         ED_area_tag_redraw(sa);
498                                         break;
499                                 case ND_OB_ACTIVE:
500                                 case ND_FRAME:
501                                         ED_area_tag_refresh(sa);
502                                         break;
503                                 case ND_FRAME_RANGE:
504                                 {
505                                         ARegion *ar;
506                                         Scene *scene = wmn->reference;
507
508                                         for (ar = sa->regionbase.first; ar; ar = ar->next) {
509                                                 if (ar->regiontype == RGN_TYPE_WINDOW) {
510                                                         ar->v2d.tot.xmin = (float)(SFRA - 4);
511                                                         ar->v2d.tot.xmax = (float)(EFRA + 4);
512                                                         break;
513                                                 }
514                                         }
515                                         break;
516                                 }
517                         }
518                         break;
519                 }
520                 case NC_SPACE:
521                 {
522                         switch (wmn->data) {
523                                 case ND_SPACE_CHANGED:
524                                         ED_area_tag_refresh(sa);
525                                         break;
526                         }
527                         break;
528                 }
529                 case NC_WM:
530                 {
531                         switch (wmn->data) {
532                                 case ND_FILEREAD:
533                                         ED_area_tag_refresh(sa);
534                                         break;
535                         }
536                         break;
537                 }
538         }
539 }
540
541 /* ---------------- */
542
543 /* add handlers, stuff you only do once or on area/region changes */
544 static void time_main_region_init(wmWindowManager *wm, ARegion *ar)
545 {
546         wmKeyMap *keymap;
547         
548         UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
549         
550         /* own keymap */
551         keymap = WM_keymap_find(wm->defaultconf, "Timeline", SPACE_TIME, 0);
552         WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
553 }
554
555 static void time_main_region_draw(const bContext *C, ARegion *ar)
556 {
557         /* draw entirely, view changes should be handled here */
558         Scene *scene = CTX_data_scene(C);
559         SpaceTime *stime = CTX_wm_space_time(C);
560         Object *obact = CTX_data_active_object(C);
561         View2D *v2d = &ar->v2d;
562         View2DGrid *grid;
563         View2DScrollers *scrollers;
564         int unit, flag = 0;
565         
566         /* clear and setup matrix */
567         UI_ThemeClearColor(TH_BACK);
568         glClear(GL_COLOR_BUFFER_BIT);
569         
570         UI_view2d_view_ortho(v2d);
571         
572         /* grid */
573         unit = (stime->flag & TIME_DRAWFRAMES) ? V2D_UNIT_FRAMES : V2D_UNIT_SECONDS;
574         grid = UI_view2d_grid_calc(scene, v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY, ar->winx, ar->winy);
575         UI_view2d_grid_draw(v2d, grid, (V2D_VERTICAL_LINES | V2D_VERTICAL_AXIS));
576         UI_view2d_grid_free(grid);
577         
578         ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
579
580         /* start and end frame */
581         time_draw_sfra_efra(scene, v2d);
582         
583         /* current frame */
584         flag = DRAWCFRA_WIDE; /* this is only really needed on frames where there's a keyframe, but this will do... */
585         if ((stime->flag & TIME_DRAWFRAMES) == 0)  flag |= DRAWCFRA_UNIT_SECONDS;
586         if (stime->flag & TIME_CFRA_NUM)           flag |= DRAWCFRA_SHOW_NUMBOX;
587         ANIM_draw_cfra(C, v2d, flag);
588         
589         UI_view2d_view_ortho(v2d);
590         
591         /* keyframes */
592         time_draw_keyframes(C, ar);
593         
594         /* markers */
595         UI_view2d_view_orthoSpecial(ar, v2d, 1);
596         ED_markers_draw(C, 0);
597         
598         /* caches */
599         time_draw_cache(stime, obact, scene);
600         
601         /* callback */
602         UI_view2d_view_ortho(v2d);
603         ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
604
605         /* reset view matrix */
606         UI_view2d_view_restore(C);
607         
608         /* scrollers */
609         scrollers = UI_view2d_scrollers_calc(C, v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
610         UI_view2d_scrollers_draw(C, v2d, scrollers);
611         UI_view2d_scrollers_free(scrollers);
612 }
613
614 static void time_main_region_listener(
615         bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
616         wmNotifier *wmn, const Scene *UNUSED(scene))
617 {
618         /* context changes */
619         switch (wmn->category) {
620                 case NC_SPACE:
621                         if (wmn->data == ND_SPACE_TIME)
622                                 ED_region_tag_redraw(ar);
623                         break;
624
625                 case NC_ANIMATION:
626                         ED_region_tag_redraw(ar);
627                         break;
628                 
629                 case NC_SCENE:
630                         switch (wmn->data) {
631                                 case ND_OB_SELECT:
632                                 case ND_OB_ACTIVE:
633                                 case ND_FRAME:
634                                 case ND_FRAME_RANGE:
635                                 case ND_KEYINGSET:
636                                 case ND_RENDER_OPTIONS:
637                                         ED_region_tag_redraw(ar);
638                                         break;
639                         }
640                         break;
641                 case NC_GPENCIL:
642                         if (wmn->data == ND_DATA)
643                                 ED_region_tag_redraw(ar);
644                         break;
645                 case NC_SCREEN:
646                         if (ELEM(wmn->data, ND_LAYER)) {
647                                 ED_region_tag_redraw(ar);
648                         }
649                         break;
650         }
651 }
652
653 /* ************************ header time area region *********************** */
654
655 /* add handlers, stuff you only do once or on area/region changes */
656 static void time_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
657 {
658         ED_region_header_init(ar);
659 }
660
661 static void time_header_region_draw(const bContext *C, ARegion *ar)
662 {
663         ED_region_header(C, ar);
664 }
665
666 static void time_header_region_listener(
667         bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
668         wmNotifier *wmn, const Scene *UNUSED(scene))
669 {
670         /* context changes */
671         switch (wmn->category) {
672                 case NC_SCREEN:
673                 {
674                         if (wmn->data == ND_ANIMPLAY)
675                                 ED_region_tag_redraw(ar);
676                         break;
677                 }
678                 case NC_SCENE:
679                 {
680                         switch (wmn->data) {
681                                 case ND_RENDER_RESULT:
682                                 case ND_OB_SELECT:
683                                 case ND_FRAME:
684                                 case ND_FRAME_RANGE:
685                                 case ND_KEYINGSET:
686                                 case ND_RENDER_OPTIONS:
687                                         ED_region_tag_redraw(ar);
688                                         break;
689                         }
690                         break;
691                 }
692                 case NC_SPACE:
693                 {
694                         if (wmn->data == ND_SPACE_TIME)
695                                 ED_region_tag_redraw(ar);
696                         break;
697                 }
698         }
699 }
700
701 /* ******************** default callbacks for time space ***************** */
702
703 static SpaceLink *time_new(const bContext *C)
704 {
705         Scene *scene = CTX_data_scene(C);
706         ARegion *ar;
707         SpaceTime *stime;
708
709         stime = MEM_callocN(sizeof(SpaceTime), "inittime");
710
711         stime->spacetype = SPACE_TIME;
712         stime->flag |= TIME_DRAWFRAMES;
713
714         /* header */
715         ar = MEM_callocN(sizeof(ARegion), "header for time");
716         
717         BLI_addtail(&stime->regionbase, ar);
718         ar->regiontype = RGN_TYPE_HEADER;
719         ar->alignment = RGN_ALIGN_BOTTOM;
720         
721         /* main region */
722         ar = MEM_callocN(sizeof(ARegion), "main region for time");
723         
724         BLI_addtail(&stime->regionbase, ar);
725         ar->regiontype = RGN_TYPE_WINDOW;
726         
727         ar->v2d.tot.xmin = (float)(SFRA - 4);
728         ar->v2d.tot.ymin = 0.0f;
729         ar->v2d.tot.xmax = (float)(EFRA + 4);
730         ar->v2d.tot.ymax = 50.0f;
731         
732         ar->v2d.cur = ar->v2d.tot;
733
734         ar->v2d.min[0] = 1.0f;
735         ar->v2d.min[1] = 50.0f;
736
737         ar->v2d.max[0] = MAXFRAMEF;
738         ar->v2d.max[1] = 50.0;
739
740         ar->v2d.minzoom = 0.1f;
741         ar->v2d.maxzoom = 10.0;
742
743         ar->v2d.scroll |= (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL);
744         ar->v2d.align |= V2D_ALIGN_NO_NEG_Y;
745         ar->v2d.keepofs |= V2D_LOCKOFS_Y;
746         ar->v2d.keepzoom |= V2D_LOCKZOOM_Y;
747
748
749         return (SpaceLink *)stime;
750 }
751
752 /* spacetype; init callback in ED_area_initialize() */
753 /* init is called to (re)initialize an existing editor (file read, screen changes) */
754 /* validate spacedata, add own area level handlers */
755 static void time_init(wmWindowManager *UNUSED(wm), ScrArea *sa)
756 {
757         SpaceTime *stime = (SpaceTime *)sa->spacedata.first;
758         
759         /* enable all cache display */
760         stime->cache_display |= TIME_CACHE_DISPLAY;
761         stime->cache_display |= (TIME_CACHE_SOFTBODY | TIME_CACHE_PARTICLES);
762         stime->cache_display |= (TIME_CACHE_CLOTH | TIME_CACHE_SMOKE | TIME_CACHE_DYNAMICPAINT);
763         stime->cache_display |= TIME_CACHE_RIGIDBODY;
764 }
765
766 static SpaceLink *time_duplicate(SpaceLink *sl)
767 {
768         SpaceTime *stime = (SpaceTime *)sl;
769         SpaceTime *stimen = MEM_dupallocN(stime);
770         
771         BLI_listbase_clear(&stimen->caches);
772         
773         return (SpaceLink *)stimen;
774 }
775
776 /* only called once, from space_api/spacetypes.c */
777 /* it defines all callbacks to maintain spaces */
778 void ED_spacetype_time(void)
779 {
780         SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype time");
781         ARegionType *art;
782         
783         st->spaceid = SPACE_TIME;
784         strncpy(st->name, "Timeline", BKE_ST_MAXNAME);
785         
786         st->new = time_new;
787         st->init = time_init;
788         st->duplicate = time_duplicate;
789         st->operatortypes = time_operatortypes;
790         st->keymap = NULL;
791         st->listener = time_listener;
792         
793         /* regions: main window */
794         art = MEM_callocN(sizeof(ARegionType), "spacetype time region");
795         art->regionid = RGN_TYPE_WINDOW;
796         art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES;
797         
798         art->init = time_main_region_init;
799         art->draw = time_main_region_draw;
800         art->listener = time_main_region_listener;
801         art->keymap = time_keymap;
802         art->lock = 1;   /* Due to pointcache, see T4960. */
803         BLI_addhead(&st->regiontypes, art);
804         
805         /* regions: header */
806         art = MEM_callocN(sizeof(ARegionType), "spacetype time region");
807         art->regionid = RGN_TYPE_HEADER;
808         art->prefsizey = HEADERY;
809         art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
810         
811         art->init = time_header_region_init;
812         art->draw = time_header_region_draw;
813         art->listener = time_header_region_listener;
814         BLI_addhead(&st->regiontypes, art);
815                 
816         BKE_spacetype_register(st);
817 }