35c031e8bc8c2e81751de2f2109340ba916a954e
[blender.git] / source / blender / editors / space_sequencer / space_sequencer.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 spseq
22  */
23
24 #include <string.h>
25 #include <stdio.h>
26
27 #include "DNA_gpencil_types.h"
28 #include "DNA_scene_types.h"
29 #include "DNA_mask_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_global.h"
38 #include "BKE_library.h"
39 #include "BKE_screen.h"
40 #include "BKE_sequencer.h"
41
42 #include "ED_space_api.h"
43 #include "ED_screen.h"
44 #include "ED_view3d.h" /* only for sequencer view3d drawing callback */
45
46 #include "WM_api.h"
47 #include "WM_types.h"
48 #include "WM_message.h"
49
50 #include "RNA_access.h"
51
52 #include "UI_interface.h"
53 #include "UI_resources.h"
54 #include "UI_view2d.h"
55
56 #include "IMB_imbuf.h"
57
58 #include "sequencer_intern.h"  // own include
59
60 /**************************** common state *****************************/
61
62 static void sequencer_scopes_tag_refresh(ScrArea *sa)
63 {
64   SpaceSeq *sseq = (SpaceSeq *)sa->spacedata.first;
65
66   sseq->scopes.reference_ibuf = NULL;
67 }
68
69 /* ******************** manage regions ********************* */
70
71 ARegion *sequencer_has_buttons_region(ScrArea *sa)
72 {
73   ARegion *ar, *arnew;
74
75   ar = BKE_area_find_region_type(sa, RGN_TYPE_UI);
76   if (ar) {
77     return ar;
78   }
79
80   /* add subdiv level; after header */
81   ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
82
83   /* is error! */
84   if (ar == NULL) {
85     return NULL;
86   }
87
88   arnew = MEM_callocN(sizeof(ARegion), "buttons for sequencer");
89
90   BLI_insertlinkafter(&sa->regionbase, ar, arnew);
91   arnew->regiontype = RGN_TYPE_UI;
92   arnew->alignment = RGN_ALIGN_RIGHT;
93
94   arnew->flag = RGN_FLAG_HIDDEN;
95
96   return arnew;
97 }
98
99 static ARegion *sequencer_find_region(ScrArea *sa, short type)
100 {
101   ARegion *ar = NULL;
102
103   for (ar = sa->regionbase.first; ar; ar = ar->next) {
104     if (ar->regiontype == type) {
105       return ar;
106     }
107   }
108
109   return ar;
110 }
111
112 /* ******************** default callbacks for sequencer space ***************** */
113
114 static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene)
115 {
116   ARegion *ar;
117   SpaceSeq *sseq;
118
119   sseq = MEM_callocN(sizeof(SpaceSeq), "initsequencer");
120   sseq->spacetype = SPACE_SEQ;
121   sseq->chanshown = 0;
122   sseq->view = SEQ_VIEW_SEQUENCE;
123   sseq->mainb = SEQ_DRAW_IMG_IMBUF;
124   sseq->flag = SEQ_SHOW_GPENCIL | SEQ_USE_ALPHA | SEQ_SHOW_MARKER_LINES;
125
126   /* header */
127   ar = MEM_callocN(sizeof(ARegion), "header for sequencer");
128
129   BLI_addtail(&sseq->regionbase, ar);
130   ar->regiontype = RGN_TYPE_HEADER;
131   ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
132
133   /* buttons/list view */
134   ar = MEM_callocN(sizeof(ARegion), "buttons for sequencer");
135
136   BLI_addtail(&sseq->regionbase, ar);
137   ar->regiontype = RGN_TYPE_UI;
138   ar->alignment = RGN_ALIGN_RIGHT;
139   ar->flag = RGN_FLAG_HIDDEN;
140
141   /* preview region */
142   /* NOTE: if you change values here, also change them in sequencer_init_preview_region */
143   ar = MEM_callocN(sizeof(ARegion), "preview region for sequencer");
144   BLI_addtail(&sseq->regionbase, ar);
145   ar->regiontype = RGN_TYPE_PREVIEW;
146   ar->alignment = RGN_ALIGN_TOP;
147   ar->flag |= RGN_FLAG_HIDDEN;
148   /* for now, aspect ratio should be maintained, and zoom is clamped within sane default limits */
149   ar->v2d.keepzoom = V2D_KEEPASPECT | V2D_KEEPZOOM | V2D_LIMITZOOM;
150   ar->v2d.minzoom = 0.001f;
151   ar->v2d.maxzoom = 1000.0f;
152   ar->v2d.tot.xmin = -960.0f; /* 1920 width centered */
153   ar->v2d.tot.ymin = -540.0f; /* 1080 height centered */
154   ar->v2d.tot.xmax = 960.0f;
155   ar->v2d.tot.ymax = 540.0f;
156   ar->v2d.min[0] = 0.0f;
157   ar->v2d.min[1] = 0.0f;
158   ar->v2d.max[0] = 12000.0f;
159   ar->v2d.max[1] = 12000.0f;
160   ar->v2d.cur = ar->v2d.tot;
161   ar->v2d.align = V2D_ALIGN_FREE;
162   ar->v2d.keeptot = V2D_KEEPTOT_FREE;
163
164   /* main region */
165   ar = MEM_callocN(sizeof(ARegion), "main region for sequencer");
166
167   BLI_addtail(&sseq->regionbase, ar);
168   ar->regiontype = RGN_TYPE_WINDOW;
169
170   /* seq space goes from (0,8) to (0, efra) */
171
172   ar->v2d.tot.xmin = 0.0f;
173   ar->v2d.tot.ymin = 0.0f;
174   ar->v2d.tot.xmax = scene->r.efra;
175   ar->v2d.tot.ymax = 8.0f;
176
177   ar->v2d.cur = ar->v2d.tot;
178
179   ar->v2d.min[0] = 10.0f;
180   ar->v2d.min[1] = 0.5f;
181
182   ar->v2d.max[0] = MAXFRAMEF;
183   ar->v2d.max[1] = MAXSEQ;
184
185   ar->v2d.minzoom = 0.01f;
186   ar->v2d.maxzoom = 100.0f;
187
188   ar->v2d.scroll |= (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL);
189   ar->v2d.scroll |= (V2D_SCROLL_LEFT | V2D_SCROLL_SCALE_VERTICAL);
190   ar->v2d.keepzoom = 0;
191   ar->v2d.keeptot = 0;
192   ar->v2d.align = V2D_ALIGN_NO_NEG_Y;
193
194   return (SpaceLink *)sseq;
195 }
196
197 /* not spacelink itself */
198 static void sequencer_free(SpaceLink *sl)
199 {
200   SpaceSeq *sseq = (SpaceSeq *)sl;
201   SequencerScopes *scopes = &sseq->scopes;
202
203   // XXX  if (sseq->gpd) BKE_gpencil_free(sseq->gpd);
204
205   if (scopes->zebra_ibuf) {
206     IMB_freeImBuf(scopes->zebra_ibuf);
207   }
208
209   if (scopes->waveform_ibuf) {
210     IMB_freeImBuf(scopes->waveform_ibuf);
211   }
212
213   if (scopes->sep_waveform_ibuf) {
214     IMB_freeImBuf(scopes->sep_waveform_ibuf);
215   }
216
217   if (scopes->vector_ibuf) {
218     IMB_freeImBuf(scopes->vector_ibuf);
219   }
220
221   if (scopes->histogram_ibuf) {
222     IMB_freeImBuf(scopes->histogram_ibuf);
223   }
224 }
225
226 /* spacetype; init callback */
227 static void sequencer_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
228 {
229 }
230
231 static void sequencer_refresh(const bContext *C, ScrArea *sa)
232 {
233   wmWindowManager *wm = CTX_wm_manager(C);
234   wmWindow *window = CTX_wm_window(C);
235   SpaceSeq *sseq = (SpaceSeq *)sa->spacedata.first;
236   ARegion *ar_main = sequencer_find_region(sa, RGN_TYPE_WINDOW);
237   ARegion *ar_preview = sequencer_find_region(sa, RGN_TYPE_PREVIEW);
238   bool view_changed = false;
239
240   switch (sseq->view) {
241     case SEQ_VIEW_SEQUENCE:
242       if (ar_main && (ar_main->flag & RGN_FLAG_HIDDEN)) {
243         ar_main->flag &= ~RGN_FLAG_HIDDEN;
244         ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
245         view_changed = true;
246       }
247       if (ar_preview && !(ar_preview->flag & RGN_FLAG_HIDDEN)) {
248         ar_preview->flag |= RGN_FLAG_HIDDEN;
249         ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
250         WM_event_remove_handlers((bContext *)C, &ar_preview->handlers);
251         view_changed = true;
252       }
253       if (ar_main && ar_main->alignment != RGN_ALIGN_NONE) {
254         ar_main->alignment = RGN_ALIGN_NONE;
255         view_changed = true;
256       }
257       if (ar_preview && ar_preview->alignment != RGN_ALIGN_NONE) {
258         ar_preview->alignment = RGN_ALIGN_NONE;
259         view_changed = true;
260       }
261       break;
262     case SEQ_VIEW_PREVIEW:
263       if (ar_main && !(ar_main->flag & RGN_FLAG_HIDDEN)) {
264         ar_main->flag |= RGN_FLAG_HIDDEN;
265         ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
266         WM_event_remove_handlers((bContext *)C, &ar_main->handlers);
267         view_changed = true;
268       }
269       if (ar_preview && (ar_preview->flag & RGN_FLAG_HIDDEN)) {
270         ar_preview->flag &= ~RGN_FLAG_HIDDEN;
271         ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
272         ar_preview->v2d.cur = ar_preview->v2d.tot;
273         view_changed = true;
274       }
275       if (ar_main && ar_main->alignment != RGN_ALIGN_NONE) {
276         ar_main->alignment = RGN_ALIGN_NONE;
277         view_changed = true;
278       }
279       if (ar_preview && ar_preview->alignment != RGN_ALIGN_NONE) {
280         ar_preview->alignment = RGN_ALIGN_NONE;
281         view_changed = true;
282       }
283       break;
284     case SEQ_VIEW_SEQUENCE_PREVIEW:
285       if (ar_main && ar_preview) {
286         /* Get available height (without DPI correction). */
287         const float height = (sa->winy - ED_area_headersize()) / UI_DPI_FAC;
288
289         /* We reuse hidden region's size, allows to find same layout as before if we just switch
290          * between one 'full window' view and the combined one. This gets lost if we switch to both
291          * 'full window' views before, though... Better than nothing. */
292         if (ar_main->flag & RGN_FLAG_HIDDEN) {
293           ar_main->flag &= ~RGN_FLAG_HIDDEN;
294           ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
295           ar_preview->sizey = (int)(height - ar_main->sizey);
296           view_changed = true;
297         }
298         if (ar_preview->flag & RGN_FLAG_HIDDEN) {
299           ar_preview->flag &= ~RGN_FLAG_HIDDEN;
300           ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
301           ar_preview->v2d.cur = ar_preview->v2d.tot;
302           ar_main->sizey = (int)(height - ar_preview->sizey);
303           view_changed = true;
304         }
305         if (ar_main->alignment != RGN_ALIGN_NONE) {
306           ar_main->alignment = RGN_ALIGN_NONE;
307           view_changed = true;
308         }
309         if (ar_preview->alignment != RGN_ALIGN_TOP) {
310           ar_preview->alignment = RGN_ALIGN_TOP;
311           view_changed = true;
312         }
313         /* Final check that both preview and main height are reasonable! */
314         if (ar_preview->sizey < 10 || ar_main->sizey < 10 ||
315             ar_preview->sizey + ar_main->sizey > height) {
316           ar_preview->sizey = (int)(height * 0.4f + 0.5f);
317           ar_main->sizey = (int)(height - ar_preview->sizey);
318           view_changed = true;
319         }
320       }
321       break;
322   }
323
324   if (view_changed) {
325     ED_area_initialize(wm, window, sa);
326     ED_area_tag_redraw(sa);
327   }
328 }
329
330 static SpaceLink *sequencer_duplicate(SpaceLink *sl)
331 {
332   SpaceSeq *sseqn = MEM_dupallocN(sl);
333
334   /* clear or remove stuff from old */
335   // XXX  sseq->gpd = gpencil_data_duplicate(sseq->gpd, false);
336
337   memset(&sseqn->scopes, 0, sizeof(sseqn->scopes));
338
339   return (SpaceLink *)sseqn;
340 }
341
342 static void sequencer_listener(wmWindow *UNUSED(win),
343                                ScrArea *sa,
344                                wmNotifier *wmn,
345                                Scene *UNUSED(scene))
346 {
347   /* context changes */
348   switch (wmn->category) {
349     case NC_SCENE:
350       switch (wmn->data) {
351         case ND_FRAME:
352         case ND_SEQUENCER:
353           sequencer_scopes_tag_refresh(sa);
354           break;
355       }
356       break;
357     case NC_WINDOW:
358     case NC_SPACE:
359       if (wmn->data == ND_SPACE_SEQUENCER) {
360         sequencer_scopes_tag_refresh(sa);
361       }
362       break;
363     case NC_GPENCIL:
364       if (wmn->data & ND_GPENCIL_EDITMODE) {
365         ED_area_tag_redraw(sa);
366       }
367       break;
368   }
369 }
370
371 /* ************* dropboxes ************* */
372
373 static bool image_drop_poll(bContext *C,
374                             wmDrag *drag,
375                             const wmEvent *event,
376                             const char **UNUSED(tooltip))
377 {
378   ARegion *ar = CTX_wm_region(C);
379   Scene *scene = CTX_data_scene(C);
380   int hand;
381
382   if (drag->type == WM_DRAG_PATH) {
383     if (ELEM(drag->icon, ICON_FILE_IMAGE, ICON_FILE_BLANK)) { /* rule might not work? */
384       if (find_nearest_seq(scene, &ar->v2d, &hand, event->mval) == NULL) {
385         return 1;
386       }
387     }
388   }
389
390   return 0;
391 }
392
393 static bool movie_drop_poll(bContext *C,
394                             wmDrag *drag,
395                             const wmEvent *event,
396                             const char **UNUSED(tooltip))
397 {
398   ARegion *ar = CTX_wm_region(C);
399   Scene *scene = CTX_data_scene(C);
400   int hand;
401
402   if (drag->type == WM_DRAG_PATH) {
403     if (ELEM(drag->icon, 0, ICON_FILE_MOVIE, ICON_FILE_BLANK)) { /* rule might not work? */
404       if (find_nearest_seq(scene, &ar->v2d, &hand, event->mval) == NULL) {
405         return 1;
406       }
407     }
408   }
409   return 0;
410 }
411
412 static bool sound_drop_poll(bContext *C,
413                             wmDrag *drag,
414                             const wmEvent *event,
415                             const char **UNUSED(tooltip))
416 {
417   ARegion *ar = CTX_wm_region(C);
418   Scene *scene = CTX_data_scene(C);
419   int hand;
420
421   if (drag->type == WM_DRAG_PATH) {
422     if (ELEM(drag->icon, ICON_FILE_SOUND, ICON_FILE_BLANK)) { /* rule might not work? */
423       if (find_nearest_seq(scene, &ar->v2d, &hand, event->mval) == NULL) {
424         return 1;
425       }
426     }
427   }
428   return 0;
429 }
430
431 static void sequencer_drop_copy(wmDrag *drag, wmDropBox *drop)
432 {
433   /* copy drag path to properties */
434   if (RNA_struct_find_property(drop->ptr, "filepath")) {
435     RNA_string_set(drop->ptr, "filepath", drag->path);
436   }
437
438   if (RNA_struct_find_property(drop->ptr, "directory")) {
439     PointerRNA itemptr;
440     char dir[FILE_MAX], file[FILE_MAX];
441
442     BLI_split_dirfile(drag->path, dir, file, sizeof(dir), sizeof(file));
443
444     RNA_string_set(drop->ptr, "directory", dir);
445
446     RNA_collection_clear(drop->ptr, "files");
447     RNA_collection_add(drop->ptr, "files", &itemptr);
448     RNA_string_set(&itemptr, "name", file);
449   }
450 }
451
452 /* this region dropbox definition */
453 static void sequencer_dropboxes(void)
454 {
455   ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW);
456
457   WM_dropbox_add(lb, "SEQUENCER_OT_image_strip_add", image_drop_poll, sequencer_drop_copy);
458   WM_dropbox_add(lb, "SEQUENCER_OT_movie_strip_add", movie_drop_poll, sequencer_drop_copy);
459   WM_dropbox_add(lb, "SEQUENCER_OT_sound_strip_add", sound_drop_poll, sequencer_drop_copy);
460 }
461
462 /* ************* end drop *********** */
463
464 /* DO NOT make this static, this hides the symbol and breaks API generation script. */
465 extern const char *sequencer_context_dir[]; /* quiet warning. */
466 const char *sequencer_context_dir[] = {"edit_mask", NULL};
467
468 static int sequencer_context(const bContext *C, const char *member, bContextDataResult *result)
469 {
470   Scene *scene = CTX_data_scene(C);
471
472   if (CTX_data_dir(member)) {
473     CTX_data_dir_set(result, sequencer_context_dir);
474
475     return true;
476   }
477   else if (CTX_data_equals(member, "edit_mask")) {
478     Mask *mask = BKE_sequencer_mask_get(scene);
479     if (mask) {
480       CTX_data_id_pointer_set(result, &mask->id);
481     }
482     return true;
483   }
484
485   return false;
486 }
487
488 /* *********************** sequencer (main) region ************************ */
489 /* add handlers, stuff you only do once or on area/region changes */
490 static void sequencer_main_region_init(wmWindowManager *wm, ARegion *ar)
491 {
492   wmKeyMap *keymap;
493   ListBase *lb;
494
495   UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
496
497 #if 0
498   keymap = WM_keymap_ensure(wm->defaultconf, "Mask Editing", 0, 0);
499   WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
500 #endif
501
502   keymap = WM_keymap_ensure(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0);
503   WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
504
505   /* own keymap */
506   keymap = WM_keymap_ensure(wm->defaultconf, "Sequencer", SPACE_SEQ, 0);
507   WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
508
509   /* add drop boxes */
510   lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW);
511
512   WM_event_add_dropbox_handler(&ar->handlers, lb);
513 }
514
515 static void sequencer_main_region_draw(const bContext *C, ARegion *ar)
516 {
517   /* NLE - strip editing timeline interface */
518   draw_timeline_seq(C, ar);
519 }
520
521 static void sequencer_main_region_listener(wmWindow *UNUSED(win),
522                                            ScrArea *UNUSED(sa),
523                                            ARegion *ar,
524                                            wmNotifier *wmn,
525                                            const Scene *UNUSED(scene))
526 {
527   /* context changes */
528   switch (wmn->category) {
529     case NC_SCENE:
530       switch (wmn->data) {
531         case ND_FRAME:
532         case ND_FRAME_RANGE:
533         case ND_MARKERS:
534         case ND_RENDER_OPTIONS: /* for FPS and FPS Base */
535         case ND_SEQUENCER:
536         case ND_RENDER_RESULT:
537           ED_region_tag_redraw(ar);
538           break;
539       }
540       break;
541     case NC_ANIMATION:
542       switch (wmn->data) {
543         case ND_KEYFRAME:
544           ED_region_tag_redraw(ar);
545           break;
546       }
547       break;
548     case NC_SPACE:
549       if (wmn->data == ND_SPACE_SEQUENCER) {
550         ED_region_tag_redraw(ar);
551       }
552       break;
553     case NC_ID:
554       if (wmn->action == NA_RENAME) {
555         ED_region_tag_redraw(ar);
556       }
557       break;
558     case NC_SCREEN:
559       if (ELEM(wmn->data, ND_ANIMPLAY)) {
560         ED_region_tag_redraw(ar);
561       }
562       break;
563   }
564 }
565
566 static void sequencer_main_region_message_subscribe(const struct bContext *UNUSED(C),
567                                                     struct WorkSpace *UNUSED(workspace),
568                                                     struct Scene *scene,
569                                                     struct bScreen *UNUSED(screen),
570                                                     struct ScrArea *UNUSED(sa),
571                                                     struct ARegion *ar,
572                                                     struct wmMsgBus *mbus)
573 {
574   wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
575       .owner = ar,
576       .user_data = ar,
577       .notify = ED_region_do_msg_notify_tag_redraw,
578   };
579
580   /* Timeline depends on scene properties. */
581   {
582     bool use_preview = (scene->r.flag & SCER_PRV_RANGE);
583     extern PropertyRNA rna_Scene_frame_start;
584     extern PropertyRNA rna_Scene_frame_end;
585     extern PropertyRNA rna_Scene_frame_preview_start;
586     extern PropertyRNA rna_Scene_frame_preview_end;
587     extern PropertyRNA rna_Scene_use_preview_range;
588     extern PropertyRNA rna_Scene_frame_current;
589     const PropertyRNA *props[] = {
590         use_preview ? &rna_Scene_frame_preview_start : &rna_Scene_frame_start,
591         use_preview ? &rna_Scene_frame_preview_end : &rna_Scene_frame_end,
592         &rna_Scene_use_preview_range,
593         &rna_Scene_frame_current,
594     };
595
596     PointerRNA idptr;
597     RNA_id_pointer_create(&scene->id, &idptr);
598
599     for (int i = 0; i < ARRAY_SIZE(props); i++) {
600       WM_msg_subscribe_rna(mbus, &idptr, props[i], &msg_sub_value_region_tag_redraw, __func__);
601     }
602   }
603
604   {
605     StructRNA *type_array[] = {
606         &RNA_SequenceEditor,
607
608         &RNA_Sequence,
609         /* Members of 'Sequence'. */
610         &RNA_SequenceCrop,
611         &RNA_SequenceTransform,
612         &RNA_SequenceModifier,
613         &RNA_SequenceColorBalanceData,
614     };
615     wmMsgParams_RNA msg_key_params = {{{0}}};
616     for (int i = 0; i < ARRAY_SIZE(type_array); i++) {
617       msg_key_params.ptr.type = type_array[i];
618       WM_msg_subscribe_rna_params(
619           mbus, &msg_key_params, &msg_sub_value_region_tag_redraw, __func__);
620     }
621   }
622 }
623
624 /* *********************** header region ************************ */
625 /* add handlers, stuff you only do once or on area/region changes */
626 static void sequencer_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
627 {
628   ED_region_header_init(ar);
629 }
630
631 static void sequencer_header_region_draw(const bContext *C, ARegion *ar)
632 {
633   ED_region_header(C, ar);
634 }
635
636 /* *********************** preview region ************************ */
637 static void sequencer_preview_region_init(wmWindowManager *wm, ARegion *ar)
638 {
639   wmKeyMap *keymap;
640
641   UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
642
643 #if 0
644   keymap = WM_keymap_ensure(wm->defaultconf, "Mask Editing", 0, 0);
645   WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
646 #endif
647
648   keymap = WM_keymap_ensure(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0);
649   WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
650
651   /* own keymap */
652   keymap = WM_keymap_ensure(wm->defaultconf, "SequencerPreview", SPACE_SEQ, 0);
653   WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
654 }
655
656 static void sequencer_preview_region_draw(const bContext *C, ARegion *ar)
657 {
658   ScrArea *sa = CTX_wm_area(C);
659   SpaceSeq *sseq = sa->spacedata.first;
660   Scene *scene = CTX_data_scene(C);
661   wmWindowManager *wm = CTX_wm_manager(C);
662   const bool show_split = (scene->ed && (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) &&
663                            (sseq->mainb == SEQ_DRAW_IMG_IMBUF));
664
665   /* XXX temp fix for wrong setting in sseq->mainb */
666   if (sseq->mainb == SEQ_DRAW_SEQUENCE) {
667     sseq->mainb = SEQ_DRAW_IMG_IMBUF;
668   }
669
670   if (!show_split || sseq->overlay_type != SEQ_DRAW_OVERLAY_REFERENCE) {
671     sequencer_draw_preview(C, scene, ar, sseq, scene->r.cfra, 0, false, false);
672   }
673
674   if (show_split && sseq->overlay_type != SEQ_DRAW_OVERLAY_CURRENT) {
675     int over_cfra;
676
677     if (scene->ed->over_flag & SEQ_EDIT_OVERLAY_ABS) {
678       over_cfra = scene->ed->over_cfra;
679     }
680     else {
681       over_cfra = scene->r.cfra + scene->ed->over_ofs;
682     }
683
684     if (over_cfra != scene->r.cfra || sseq->overlay_type != SEQ_DRAW_OVERLAY_RECT) {
685       sequencer_draw_preview(
686           C, scene, ar, sseq, scene->r.cfra, over_cfra - scene->r.cfra, true, false);
687     }
688   }
689
690   if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) {
691     rcti rect;
692     ED_region_visible_rect(ar, &rect);
693     int xoffset = rect.xmin + U.widget_unit;
694     int yoffset = rect.ymax;
695     ED_scene_draw_fps(scene, xoffset, &yoffset);
696   }
697 }
698
699 static void sequencer_preview_region_listener(wmWindow *UNUSED(win),
700                                               ScrArea *UNUSED(sa),
701                                               ARegion *ar,
702                                               wmNotifier *wmn,
703                                               const Scene *UNUSED(scene))
704 {
705   /* context changes */
706   switch (wmn->category) {
707     case NC_GPENCIL:
708       if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
709         ED_region_tag_redraw(ar);
710       }
711       break;
712     case NC_SCENE:
713       switch (wmn->data) {
714         case ND_FRAME:
715         case ND_MARKERS:
716         case ND_SEQUENCER:
717         case ND_RENDER_OPTIONS:
718         case ND_DRAW_RENDER_VIEWPORT:
719           ED_region_tag_redraw(ar);
720           break;
721       }
722       break;
723     case NC_ANIMATION:
724       switch (wmn->data) {
725         case ND_KEYFRAME:
726           /* Otherwise, often prevents seeing immediately effects of keyframe editing... */
727           BKE_sequencer_cache_cleanup();
728           ED_region_tag_redraw(ar);
729           break;
730       }
731       break;
732     case NC_SPACE:
733       if (wmn->data == ND_SPACE_SEQUENCER) {
734         ED_region_tag_redraw(ar);
735       }
736       break;
737     case NC_ID:
738       switch (wmn->data) {
739         case NA_RENAME:
740           ED_region_tag_redraw(ar);
741           break;
742       }
743       break;
744     case NC_MASK:
745       if (wmn->action == NA_EDITED) {
746         ED_region_tag_redraw(ar);
747       }
748       break;
749   }
750 }
751
752 /* *********************** buttons region ************************ */
753
754 /* add handlers, stuff you only do once or on area/region changes */
755 static void sequencer_buttons_region_init(wmWindowManager *wm, ARegion *ar)
756 {
757   wmKeyMap *keymap;
758
759   keymap = WM_keymap_ensure(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0);
760   WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
761
762   ED_region_panels_init(wm, ar);
763 }
764
765 static void sequencer_buttons_region_draw(const bContext *C, ARegion *ar)
766 {
767   ED_region_panels(C, ar);
768 }
769
770 static void sequencer_buttons_region_listener(wmWindow *UNUSED(win),
771                                               ScrArea *UNUSED(sa),
772                                               ARegion *ar,
773                                               wmNotifier *wmn,
774                                               const Scene *UNUSED(scene))
775 {
776   /* context changes */
777   switch (wmn->category) {
778     case NC_GPENCIL:
779       if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
780         ED_region_tag_redraw(ar);
781       }
782       break;
783     case NC_SCENE:
784       switch (wmn->data) {
785         case ND_FRAME:
786         case ND_SEQUENCER:
787           ED_region_tag_redraw(ar);
788           break;
789       }
790       break;
791     case NC_SPACE:
792       if (wmn->data == ND_SPACE_SEQUENCER) {
793         ED_region_tag_redraw(ar);
794       }
795       break;
796     case NC_ID:
797       if (wmn->action == NA_RENAME) {
798         ED_region_tag_redraw(ar);
799       }
800       break;
801   }
802 }
803
804 static void sequencer_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
805 {
806   SpaceSeq *sseq = (SpaceSeq *)slink;
807
808   if (!ELEM(GS(old_id->name), ID_GD)) {
809     return;
810   }
811
812   if ((ID *)sseq->gpd == old_id) {
813     sseq->gpd = (bGPdata *)new_id;
814     id_us_min(old_id);
815     id_us_plus(new_id);
816   }
817 }
818
819 /* ************************************* */
820
821 /* only called once, from space/spacetypes.c */
822 void ED_spacetype_sequencer(void)
823 {
824   SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype sequencer");
825   ARegionType *art;
826
827   st->spaceid = SPACE_SEQ;
828   strncpy(st->name, "Sequencer", BKE_ST_MAXNAME);
829
830   st->new = sequencer_new;
831   st->free = sequencer_free;
832   st->init = sequencer_init;
833   st->duplicate = sequencer_duplicate;
834   st->operatortypes = sequencer_operatortypes;
835   st->keymap = sequencer_keymap;
836   st->context = sequencer_context;
837   st->dropboxes = sequencer_dropboxes;
838   st->refresh = sequencer_refresh;
839   st->listener = sequencer_listener;
840   st->id_remap = sequencer_id_remap;
841
842   /* regions: main window */
843   art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
844   art->regionid = RGN_TYPE_WINDOW;
845   art->init = sequencer_main_region_init;
846   art->draw = sequencer_main_region_draw;
847   art->listener = sequencer_main_region_listener;
848   art->message_subscribe = sequencer_main_region_message_subscribe;
849   art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION;
850
851   BLI_addhead(&st->regiontypes, art);
852
853   /* preview */
854   art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
855   art->regionid = RGN_TYPE_PREVIEW;
856   art->init = sequencer_preview_region_init;
857   art->draw = sequencer_preview_region_draw;
858   art->listener = sequencer_preview_region_listener;
859   art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL;
860   BLI_addhead(&st->regiontypes, art);
861
862   /* regions: listview/buttons */
863   art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
864   art->regionid = RGN_TYPE_UI;
865   art->prefsizex = 220;  // XXX
866   art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
867   art->listener = sequencer_buttons_region_listener;
868   art->init = sequencer_buttons_region_init;
869   art->draw = sequencer_buttons_region_draw;
870   BLI_addhead(&st->regiontypes, art);
871
872   sequencer_buttons_register(art);
873
874   /* regions: header */
875   art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
876   art->regionid = RGN_TYPE_HEADER;
877   art->prefsizey = HEADERY;
878   art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
879
880   art->init = sequencer_header_region_init;
881   art->draw = sequencer_header_region_draw;
882   art->listener = sequencer_main_region_listener;
883
884   BLI_addhead(&st->regiontypes, art);
885
886   BKE_spacetype_register(st);
887
888   /* set the sequencer callback when not in background mode */
889   if (G.background == 0) {
890     sequencer_view3d_cb = ED_view3d_draw_offscreen_imbuf_simple;
891   }
892 }