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