ccf2e552644e3276aef22d96a34ed2892e1e5cfd
[blender.git] / source / blender / editors / space_nla / space_nla.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 spnla
22  */
23
24 #include <string.h>
25 #include <stdio.h>
26
27 #include "DNA_anim_types.h"
28 #include "DNA_collection_types.h"
29 #include "DNA_scene_types.h"
30
31 #include "MEM_guardedalloc.h"
32
33 #include "BLI_blenlib.h"
34 #include "BLI_utildefines.h"
35
36 #include "BKE_context.h"
37 #include "BKE_screen.h"
38
39 #include "ED_space_api.h"
40 #include "ED_anim_api.h"
41 #include "ED_markers.h"
42 #include "ED_screen.h"
43
44 #include "WM_api.h"
45 #include "WM_types.h"
46 #include "WM_message.h"
47
48 #include "RNA_access.h"
49
50 #include "UI_resources.h"
51 #include "UI_view2d.h"
52
53 #include "nla_intern.h" /* own include */
54 #include "GPU_framebuffer.h"
55
56 /* ******************** manage regions ********************* */
57
58 ARegion *nla_has_buttons_region(ScrArea *sa)
59 {
60   ARegion *ar, *arnew;
61
62   ar = BKE_area_find_region_type(sa, RGN_TYPE_UI);
63   if (ar)
64     return ar;
65
66   /* add subdiv level; after main */
67   ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
68
69   /* is error! */
70   if (ar == NULL)
71     return NULL;
72
73   arnew = MEM_callocN(sizeof(ARegion), "buttons for nla");
74
75   BLI_insertlinkafter(&sa->regionbase, ar, arnew);
76   arnew->regiontype = RGN_TYPE_UI;
77   arnew->alignment = RGN_ALIGN_RIGHT;
78
79   arnew->flag = RGN_FLAG_HIDDEN;
80
81   return arnew;
82 }
83
84 /* ******************** default callbacks for nla space ***************** */
85
86 static SpaceLink *nla_new(const ScrArea *sa, const Scene *scene)
87 {
88   ARegion *ar;
89   SpaceNla *snla;
90
91   snla = MEM_callocN(sizeof(SpaceNla), "initnla");
92   snla->spacetype = SPACE_NLA;
93
94   /* allocate DopeSheet data for NLA Editor */
95   snla->ads = MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet");
96   snla->ads->source = (ID *)scene;
97
98   /* set auto-snapping settings */
99   snla->autosnap = SACTSNAP_FRAME;
100
101   /* header */
102   ar = MEM_callocN(sizeof(ARegion), "header for nla");
103
104   BLI_addtail(&snla->regionbase, ar);
105   ar->regiontype = RGN_TYPE_HEADER;
106   ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
107
108   /* channel list region */
109   ar = MEM_callocN(sizeof(ARegion), "channel list for nla");
110   BLI_addtail(&snla->regionbase, ar);
111   ar->regiontype = RGN_TYPE_CHANNELS;
112   ar->alignment = RGN_ALIGN_LEFT;
113
114   /* only need to set these settings since this will use the 'stack' configuration */
115   ar->v2d.scroll = V2D_SCROLL_BOTTOM;
116   ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL;
117
118   /* ui buttons */
119   ar = MEM_callocN(sizeof(ARegion), "buttons region for nla");
120
121   BLI_addtail(&snla->regionbase, ar);
122   ar->regiontype = RGN_TYPE_UI;
123   ar->alignment = RGN_ALIGN_RIGHT;
124   ar->flag = RGN_FLAG_HIDDEN;
125
126   /* main region */
127   ar = MEM_callocN(sizeof(ARegion), "main region for nla");
128
129   BLI_addtail(&snla->regionbase, ar);
130   ar->regiontype = RGN_TYPE_WINDOW;
131
132   ar->v2d.tot.xmin = (float)(SFRA - 10);
133   ar->v2d.tot.ymin = (float)(-sa->winy) / 3.0f;
134   ar->v2d.tot.xmax = (float)(EFRA + 10);
135   ar->v2d.tot.ymax = 0.0f;
136
137   ar->v2d.cur = ar->v2d.tot;
138
139   ar->v2d.min[0] = 0.0f;
140   ar->v2d.min[1] = 0.0f;
141
142   ar->v2d.max[0] = MAXFRAMEF;
143   ar->v2d.max[1] = 10000.0f;
144
145   ar->v2d.minzoom = 0.01f;
146   ar->v2d.maxzoom = 50;
147   ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL);
148   ar->v2d.scroll |= (V2D_SCROLL_RIGHT);
149   ar->v2d.keepzoom = V2D_LOCKZOOM_Y;
150   ar->v2d.keepofs = V2D_KEEPOFS_Y;
151   ar->v2d.align = V2D_ALIGN_NO_POS_Y;
152   ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL;
153
154   return (SpaceLink *)snla;
155 }
156
157 /* not spacelink itself */
158 static void nla_free(SpaceLink *sl)
159 {
160   SpaceNla *snla = (SpaceNla *)sl;
161
162   if (snla->ads) {
163     BLI_freelistN(&snla->ads->chanbase);
164     MEM_freeN(snla->ads);
165   }
166 }
167
168 /* spacetype; init callback */
169 static void nla_init(struct wmWindowManager *wm, ScrArea *sa)
170 {
171   SpaceNla *snla = (SpaceNla *)sa->spacedata.first;
172
173   /* init dopesheet data if non-existent (i.e. for old files) */
174   if (snla->ads == NULL) {
175     snla->ads = MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet");
176     snla->ads->source = (ID *)WM_window_get_active_scene(wm->winactive);
177   }
178
179   ED_area_tag_refresh(sa);
180 }
181
182 static SpaceLink *nla_duplicate(SpaceLink *sl)
183 {
184   SpaceNla *snlan = MEM_dupallocN(sl);
185
186   /* clear or remove stuff from old */
187   snlan->ads = MEM_dupallocN(snlan->ads);
188
189   return (SpaceLink *)snlan;
190 }
191
192 /* add handlers, stuff you only do once or on area/region changes */
193 static void nla_channel_region_init(wmWindowManager *wm, ARegion *ar)
194 {
195   wmKeyMap *keymap;
196
197   /* ensure the 2d view sync works - main region has bottom scroller */
198   ar->v2d.scroll = V2D_SCROLL_BOTTOM;
199
200   UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy);
201
202   /* own keymap */
203   /* own channels map first to override some channel keymaps */
204   keymap = WM_keymap_ensure(wm->defaultconf, "NLA Channels", SPACE_NLA, 0);
205   WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
206   /* now generic channels map for everything else that can apply */
207   keymap = WM_keymap_ensure(wm->defaultconf, "Animation Channels", 0, 0);
208   WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
209
210   keymap = WM_keymap_ensure(wm->defaultconf, "NLA Generic", SPACE_NLA, 0);
211   WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
212 }
213
214 /* draw entirely, view changes should be handled here */
215 static void nla_channel_region_draw(const bContext *C, ARegion *ar)
216 {
217   bAnimContext ac;
218   View2D *v2d = &ar->v2d;
219   View2DScrollers *scrollers;
220
221   /* clear and setup matrix */
222   UI_ThemeClearColor(TH_BACK);
223   GPU_clear(GPU_COLOR_BIT);
224
225   UI_view2d_view_ortho(v2d);
226
227   /* data */
228   if (ANIM_animdata_get_context(C, &ac)) {
229     draw_nla_channel_list(C, &ac, ar);
230   }
231
232   /* reset view matrix */
233   UI_view2d_view_restore(C);
234
235   /* scrollers */
236   scrollers = UI_view2d_scrollers_calc(
237       C, v2d, NULL, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
238   UI_view2d_scrollers_draw(C, v2d, scrollers);
239   UI_view2d_scrollers_free(scrollers);
240 }
241
242 /* add handlers, stuff you only do once or on area/region changes */
243 static void nla_main_region_init(wmWindowManager *wm, ARegion *ar)
244 {
245   wmKeyMap *keymap;
246
247   UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
248
249   /* own keymap */
250   keymap = WM_keymap_ensure(wm->defaultconf, "NLA Editor", SPACE_NLA, 0);
251   WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
252   keymap = WM_keymap_ensure(wm->defaultconf, "NLA Generic", SPACE_NLA, 0);
253   WM_event_add_keymap_handler(&ar->handlers, keymap);
254 }
255
256 static void nla_main_region_draw(const bContext *C, ARegion *ar)
257 {
258   /* draw entirely, view changes should be handled here */
259   SpaceNla *snla = CTX_wm_space_nla(C);
260   Scene *scene = CTX_data_scene(C);
261   bAnimContext ac;
262   View2D *v2d = &ar->v2d;
263   View2DGrid *grid;
264   View2DScrollers *scrollers;
265   short unit = 0, cfra_flag = 0;
266
267   /* clear and setup matrix */
268   UI_ThemeClearColor(TH_BACK);
269   GPU_clear(GPU_COLOR_BIT);
270
271   UI_view2d_view_ortho(v2d);
272
273   /* time grid */
274   unit = (snla->flag & SNLA_DRAWTIME) ? V2D_UNIT_SECONDS : V2D_UNIT_FRAMES;
275   grid = UI_view2d_grid_calc(CTX_data_scene(C),
276                              v2d,
277                              unit,
278                              V2D_GRID_CLAMP,
279                              V2D_ARG_DUMMY,
280                              V2D_ARG_DUMMY,
281                              ar->winx,
282                              ar->winy);
283   UI_view2d_grid_draw(v2d, grid, V2D_GRIDLINES_ALL);
284   UI_view2d_grid_free(grid);
285
286   ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
287
288   /* start and end frame */
289   ANIM_draw_framerange(scene, v2d);
290
291   /* data */
292   if (ANIM_animdata_get_context(C, &ac)) {
293     /* strips and backdrops */
294     draw_nla_main_data(&ac, snla, ar);
295
296     /* text draw cached, in pixelspace now */
297     UI_view2d_text_cache_draw(ar);
298   }
299
300   UI_view2d_view_ortho(v2d);
301
302   /* current frame */
303   if (snla->flag & SNLA_DRAWTIME)
304     cfra_flag |= DRAWCFRA_UNIT_SECONDS;
305   ANIM_draw_cfra(C, v2d, cfra_flag);
306
307   /* markers */
308   UI_view2d_view_orthoSpecial(ar, v2d, 1);
309   int marker_draw_flag = DRAW_MARKERS_MARGIN;
310   if (snla->flag & SNLA_SHOW_MARKER_LINES)
311     marker_draw_flag |= DRAW_MARKERS_LINES;
312   ED_markers_draw(C, marker_draw_flag);
313
314   /* preview range */
315   UI_view2d_view_ortho(v2d);
316   ANIM_draw_previewrange(C, v2d, 0);
317
318   /* callback */
319   UI_view2d_view_ortho(v2d);
320   ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
321
322   /* reset view matrix */
323   UI_view2d_view_restore(C);
324
325   /* scrollers */
326   scrollers = UI_view2d_scrollers_calc(
327       C, v2d, NULL, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
328   UI_view2d_scrollers_draw(C, v2d, scrollers);
329   UI_view2d_scrollers_free(scrollers);
330
331   /* draw current frame number-indicator on top of scrollers */
332   if ((snla->flag & SNLA_NODRAWCFRANUM) == 0) {
333     UI_view2d_view_orthoSpecial(ar, v2d, 1);
334     ANIM_draw_cfra_number(C, v2d, cfra_flag);
335   }
336 }
337
338 /* add handlers, stuff you only do once or on area/region changes */
339 static void nla_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
340 {
341   ED_region_header_init(ar);
342 }
343
344 static void nla_header_region_draw(const bContext *C, ARegion *ar)
345 {
346   ED_region_header(C, ar);
347 }
348
349 /* add handlers, stuff you only do once or on area/region changes */
350 static void nla_buttons_region_init(wmWindowManager *wm, ARegion *ar)
351 {
352   wmKeyMap *keymap;
353
354   ED_region_panels_init(wm, ar);
355
356   keymap = WM_keymap_ensure(wm->defaultconf, "NLA Generic", SPACE_NLA, 0);
357   WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
358 }
359
360 static void nla_buttons_region_draw(const bContext *C, ARegion *ar)
361 {
362   ED_region_panels(C, ar);
363 }
364
365 static void nla_region_listener(wmWindow *UNUSED(win),
366                                 ScrArea *UNUSED(sa),
367                                 ARegion *ar,
368                                 wmNotifier *wmn,
369                                 const Scene *UNUSED(scene))
370 {
371   /* context changes */
372   switch (wmn->category) {
373     case NC_ANIMATION:
374       ED_region_tag_redraw(ar);
375       break;
376     case NC_SCENE:
377       switch (wmn->data) {
378         case ND_OB_ACTIVE:
379         case ND_FRAME:
380         case ND_MARKERS:
381           ED_region_tag_redraw(ar);
382           break;
383       }
384       break;
385     case NC_OBJECT:
386       switch (wmn->data) {
387         case ND_BONE_ACTIVE:
388         case ND_BONE_SELECT:
389         case ND_KEYS:
390           ED_region_tag_redraw(ar);
391           break;
392       }
393       break;
394     default:
395       if (wmn->data == ND_KEYS)
396         ED_region_tag_redraw(ar);
397       break;
398   }
399 }
400
401 static void nla_main_region_listener(wmWindow *UNUSED(win),
402                                      ScrArea *UNUSED(sa),
403                                      ARegion *ar,
404                                      wmNotifier *wmn,
405                                      const Scene *UNUSED(scene))
406 {
407   /* context changes */
408   switch (wmn->category) {
409     case NC_ANIMATION:
410       ED_region_tag_redraw(ar);
411       break;
412     case NC_SCENE:
413       switch (wmn->data) {
414         case ND_RENDER_OPTIONS:
415         case ND_OB_ACTIVE:
416         case ND_FRAME:
417         case ND_FRAME_RANGE:
418         case ND_MARKERS:
419           ED_region_tag_redraw(ar);
420           break;
421       }
422       break;
423     case NC_OBJECT:
424       switch (wmn->data) {
425         case ND_BONE_ACTIVE:
426         case ND_BONE_SELECT:
427         case ND_KEYS:
428         case ND_TRANSFORM:
429           ED_region_tag_redraw(ar);
430           break;
431       }
432       break;
433     case NC_NODE:
434       switch (wmn->action) {
435         case NA_EDITED:
436           ED_region_tag_redraw(ar);
437           break;
438       }
439       break;
440     case NC_ID:
441       if (wmn->action == NA_RENAME)
442         ED_region_tag_redraw(ar);
443       break;
444     case NC_SCREEN:
445       if (ELEM(wmn->data, ND_LAYER)) {
446         ED_region_tag_redraw(ar);
447       }
448       break;
449     default:
450       if (wmn->data == ND_KEYS)
451         ED_region_tag_redraw(ar);
452       break;
453   }
454 }
455
456 static void nla_main_region_message_subscribe(const struct bContext *UNUSED(C),
457                                               struct WorkSpace *UNUSED(workspace),
458                                               struct Scene *scene,
459                                               struct bScreen *screen,
460                                               struct ScrArea *sa,
461                                               struct ARegion *ar,
462                                               struct wmMsgBus *mbus)
463 {
464   PointerRNA ptr;
465   RNA_pointer_create(&screen->id, &RNA_SpaceNLA, sa->spacedata.first, &ptr);
466
467   wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
468       .owner = ar,
469       .user_data = ar,
470       .notify = ED_region_do_msg_notify_tag_redraw,
471   };
472
473   /* Timeline depends on scene properties. */
474   {
475     bool use_preview = (scene->r.flag & SCER_PRV_RANGE);
476     extern PropertyRNA rna_Scene_frame_start;
477     extern PropertyRNA rna_Scene_frame_end;
478     extern PropertyRNA rna_Scene_frame_preview_start;
479     extern PropertyRNA rna_Scene_frame_preview_end;
480     extern PropertyRNA rna_Scene_use_preview_range;
481     extern PropertyRNA rna_Scene_frame_current;
482     const PropertyRNA *props[] = {
483         use_preview ? &rna_Scene_frame_preview_start : &rna_Scene_frame_start,
484         use_preview ? &rna_Scene_frame_preview_end : &rna_Scene_frame_end,
485         &rna_Scene_use_preview_range,
486         &rna_Scene_frame_current,
487     };
488
489     PointerRNA idptr;
490     RNA_id_pointer_create(&scene->id, &idptr);
491
492     for (int i = 0; i < ARRAY_SIZE(props); i++) {
493       WM_msg_subscribe_rna(mbus, &idptr, props[i], &msg_sub_value_region_tag_redraw, __func__);
494     }
495   }
496 }
497
498 static void nla_channel_region_listener(wmWindow *UNUSED(win),
499                                         ScrArea *UNUSED(sa),
500                                         ARegion *ar,
501                                         wmNotifier *wmn,
502                                         const Scene *UNUSED(scene))
503 {
504   /* context changes */
505   switch (wmn->category) {
506     case NC_ANIMATION:
507       ED_region_tag_redraw(ar);
508       break;
509     case NC_SCENE:
510       switch (wmn->data) {
511         case ND_OB_ACTIVE:
512           ED_region_tag_redraw(ar);
513           break;
514       }
515       break;
516     case NC_OBJECT:
517       switch (wmn->data) {
518         case ND_BONE_ACTIVE:
519         case ND_BONE_SELECT:
520         case ND_KEYS:
521           ED_region_tag_redraw(ar);
522           break;
523       }
524       break;
525     case NC_ID:
526       if (wmn->action == NA_RENAME)
527         ED_region_tag_redraw(ar);
528       break;
529     default:
530       if (wmn->data == ND_KEYS)
531         ED_region_tag_redraw(ar);
532       break;
533   }
534 }
535
536 static void nla_channel_region_message_subscribe(const struct bContext *UNUSED(C),
537                                                  struct WorkSpace *UNUSED(workspace),
538                                                  struct Scene *UNUSED(scene),
539                                                  struct bScreen *screen,
540                                                  struct ScrArea *sa,
541                                                  struct ARegion *ar,
542                                                  struct wmMsgBus *mbus)
543 {
544   PointerRNA ptr;
545   RNA_pointer_create(&screen->id, &RNA_SpaceNLA, sa->spacedata.first, &ptr);
546
547   wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
548       .owner = ar,
549       .user_data = ar,
550       .notify = ED_region_do_msg_notify_tag_redraw,
551   };
552
553   /* All dopesheet filter settings, etc. affect the drawing of this editor,
554    * so just whitelist the entire struct for updates
555    */
556   {
557     wmMsgParams_RNA msg_key_params = {{{0}}};
558     StructRNA *type_array[] = {
559         &RNA_DopeSheet,
560     };
561
562     for (int i = 0; i < ARRAY_SIZE(type_array); i++) {
563       msg_key_params.ptr.type = type_array[i];
564       WM_msg_subscribe_rna_params(
565           mbus, &msg_key_params, &msg_sub_value_region_tag_redraw, __func__);
566     }
567   }
568 }
569
570 /* editor level listener */
571 static void nla_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene))
572 {
573   /* context changes */
574   switch (wmn->category) {
575     case NC_ANIMATION:
576       // TODO: filter specific types of changes?
577       ED_area_tag_refresh(sa);
578       break;
579     case NC_SCENE:
580 #if 0
581       switch (wmn->data) {
582         case ND_OB_ACTIVE:
583         case ND_OB_SELECT:
584           ED_area_tag_refresh(sa);
585           break;
586       }
587 #endif
588       ED_area_tag_refresh(sa);
589       break;
590     case NC_OBJECT:
591       switch (wmn->data) {
592         case ND_TRANSFORM:
593           /* do nothing */
594           break;
595         default:
596           ED_area_tag_refresh(sa);
597           break;
598       }
599       break;
600     case NC_SPACE:
601       if (wmn->data == ND_SPACE_NLA)
602         ED_area_tag_redraw(sa);
603       break;
604   }
605 }
606
607 static void nla_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
608 {
609   SpaceNla *snla = (SpaceNla *)slink;
610
611   if (snla->ads) {
612     if ((ID *)snla->ads->filter_grp == old_id) {
613       snla->ads->filter_grp = (Collection *)new_id;
614     }
615     if ((ID *)snla->ads->source == old_id) {
616       snla->ads->source = new_id;
617     }
618   }
619 }
620
621 /* only called once, from space/spacetypes.c */
622 void ED_spacetype_nla(void)
623 {
624   SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype nla");
625   ARegionType *art;
626
627   st->spaceid = SPACE_NLA;
628   strncpy(st->name, "NLA", BKE_ST_MAXNAME);
629
630   st->new = nla_new;
631   st->free = nla_free;
632   st->init = nla_init;
633   st->duplicate = nla_duplicate;
634   st->operatortypes = nla_operatortypes;
635   st->listener = nla_listener;
636   st->keymap = nla_keymap;
637   st->id_remap = nla_id_remap;
638
639   /* regions: main window */
640   art = MEM_callocN(sizeof(ARegionType), "spacetype nla region");
641   art->regionid = RGN_TYPE_WINDOW;
642   art->init = nla_main_region_init;
643   art->draw = nla_main_region_draw;
644   art->listener = nla_main_region_listener;
645   art->message_subscribe = nla_main_region_message_subscribe;
646   art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES;
647
648   BLI_addhead(&st->regiontypes, art);
649
650   /* regions: header */
651   art = MEM_callocN(sizeof(ARegionType), "spacetype nla region");
652   art->regionid = RGN_TYPE_HEADER;
653   art->prefsizey = HEADERY;
654   art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
655
656   art->init = nla_header_region_init;
657   art->draw = nla_header_region_draw;
658
659   BLI_addhead(&st->regiontypes, art);
660
661   /* regions: channels */
662   art = MEM_callocN(sizeof(ARegionType), "spacetype nla region");
663   art->regionid = RGN_TYPE_CHANNELS;
664   art->prefsizex = 200;
665   art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES;
666
667   art->init = nla_channel_region_init;
668   art->draw = nla_channel_region_draw;
669   art->listener = nla_channel_region_listener;
670   art->message_subscribe = nla_channel_region_message_subscribe;
671
672   BLI_addhead(&st->regiontypes, art);
673
674   /* regions: UI buttons */
675   art = MEM_callocN(sizeof(ARegionType), "spacetype nla region");
676   art->regionid = RGN_TYPE_UI;
677   art->prefsizex = 200;
678   art->keymapflag = ED_KEYMAP_UI;
679   art->listener = nla_region_listener;
680   art->init = nla_buttons_region_init;
681   art->draw = nla_buttons_region_draw;
682
683   BLI_addhead(&st->regiontypes, art);
684
685   nla_buttons_register(art);
686
687   BKE_spacetype_register(st);
688 }