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