doxygen: prevent GPL license block from being parsed as doxygen comment.
[blender.git] / source / blender / editors / space_sequencer / space_sequencer.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <string.h>
30 #include <stdio.h>
31
32 #include "DNA_scene_types.h"
33
34 #include "MEM_guardedalloc.h"
35
36 #include "BLI_blenlib.h"
37 #include "BLI_math.h"
38 #include "BLI_path_util.h"
39 #include "BLI_utildefines.h"
40
41 #include "BKE_context.h"
42 #include "BKE_screen.h"
43 #include "BKE_sequencer.h"
44 #include "BKE_global.h"
45
46 #include "ED_space_api.h"
47 #include "ED_sequencer.h"
48 #include "ED_screen.h"
49 #include "ED_view3d.h" /* only for sequencer view3d drawing callback */
50
51 #include "WM_api.h"
52 #include "WM_types.h"
53
54 #include "UI_resources.h"
55 #include "UI_view2d.h"
56
57 #include "sequencer_intern.h"   // own include
58
59 /* ******************** manage regions ********************* */
60
61 ARegion *sequencer_has_buttons_region(ScrArea *sa)
62 {
63         ARegion *ar, *arnew;
64         
65         for(ar= sa->regionbase.first; ar; ar= ar->next)
66                 if(ar->regiontype==RGN_TYPE_UI)
67                         return ar;
68         
69         /* add subdiv level; after header */
70         for(ar= sa->regionbase.first; ar; ar= ar->next)
71                 if(ar->regiontype==RGN_TYPE_HEADER)
72                         break;
73         
74         /* is error! */
75         if(ar==NULL) return NULL;
76         
77         arnew= MEM_callocN(sizeof(ARegion), "buttons for sequencer");
78         
79         BLI_insertlinkafter(&sa->regionbase, ar, arnew);
80         arnew->regiontype= RGN_TYPE_UI;
81         arnew->alignment= RGN_ALIGN_RIGHT;
82         
83         arnew->flag = RGN_FLAG_HIDDEN;
84         
85         return arnew;
86 }
87
88 static ARegion *sequencer_find_region(ScrArea *sa, short type)
89 {
90         ARegion *ar=NULL;
91         
92         for(ar= sa->regionbase.first; ar; ar= ar->next)
93                 if(ar->regiontype==type)
94                         return ar;
95
96         return ar;
97 }
98
99 void ED_sequencer_update_view(bContext *C, int view)
100 {
101         ScrArea *sa= CTX_wm_area(C);
102         
103         ARegion *ar_main= sequencer_find_region(sa, RGN_TYPE_WINDOW);
104         ARegion *ar_preview= sequencer_find_region(sa, RGN_TYPE_PREVIEW);
105
106         switch (view) {
107                 case SEQ_VIEW_SEQUENCE:
108                         if (ar_main && (ar_main->flag & RGN_FLAG_HIDDEN)) {
109                                 ar_main->flag &= ~RGN_FLAG_HIDDEN;
110                                 ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
111                         }
112                         if (ar_preview && !(ar_preview->flag & RGN_FLAG_HIDDEN)) {
113                                 ar_preview->flag |= RGN_FLAG_HIDDEN;
114                                 ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
115                                 WM_event_remove_handlers(C, &ar_preview->handlers);
116                         }
117                         if (ar_main) ar_main->alignment= RGN_ALIGN_NONE;
118                         if (ar_preview) ar_preview->alignment= RGN_ALIGN_NONE;
119                         break;
120                 case SEQ_VIEW_PREVIEW:
121                         if (ar_main && !(ar_main->flag & RGN_FLAG_HIDDEN)) {
122                                 ar_main->flag |= RGN_FLAG_HIDDEN;
123                                 ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
124                                 WM_event_remove_handlers(C, &ar_main->handlers);
125                         }
126                         if (ar_preview && (ar_preview->flag & RGN_FLAG_HIDDEN)) {
127                                 ar_preview->flag &= ~RGN_FLAG_HIDDEN;
128                                 ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
129                                 ar_preview->v2d.cur = ar_preview->v2d.tot;
130                         }
131                         if (ar_main) ar_main->alignment= RGN_ALIGN_NONE;
132                         if (ar_preview) ar_preview->alignment= RGN_ALIGN_NONE;
133                         break;
134                 case SEQ_VIEW_SEQUENCE_PREVIEW:
135                         if (ar_main && (ar_main->flag & RGN_FLAG_HIDDEN)) {
136                                 ar_main->flag &= ~RGN_FLAG_HIDDEN;
137                                 ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
138                         }
139                         if (ar_preview && (ar_preview->flag & RGN_FLAG_HIDDEN)) {
140                                 ar_preview->flag &= ~RGN_FLAG_HIDDEN;
141                                 ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
142                                 ar_preview->v2d.cur = ar_preview->v2d.tot;
143                         }
144                         if (ar_main) ar_main->alignment= RGN_ALIGN_NONE;
145                         if (ar_preview) ar_preview->alignment= RGN_ALIGN_TOP;
146                         break;
147         }
148
149         ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
150         ED_area_tag_redraw(sa);
151 }
152
153
154 /* ******************** default callbacks for sequencer space ***************** */
155
156 static SpaceLink *sequencer_new(const bContext *C)
157 {
158         Scene *scene= CTX_data_scene(C);
159         ARegion *ar;
160         SpaceSeq *sseq;
161         
162         sseq= MEM_callocN(sizeof(SpaceSeq), "initsequencer");
163         sseq->spacetype= SPACE_SEQ;
164         sseq->zoom= 4;
165         sseq->chanshown = 0;
166         sseq->view = SEQ_VIEW_SEQUENCE;
167         sseq->mainb = SEQ_DRAW_IMG_IMBUF;
168         /* header */
169         ar= MEM_callocN(sizeof(ARegion), "header for sequencer");
170         
171         BLI_addtail(&sseq->regionbase, ar);
172         ar->regiontype= RGN_TYPE_HEADER;
173         ar->alignment= RGN_ALIGN_BOTTOM;
174         
175         /* buttons/list view */
176         ar= MEM_callocN(sizeof(ARegion), "buttons for sequencer");
177         
178         BLI_addtail(&sseq->regionbase, ar);
179         ar->regiontype= RGN_TYPE_UI;
180         ar->alignment= RGN_ALIGN_RIGHT;
181         ar->flag = RGN_FLAG_HIDDEN;
182         
183         /* preview area */
184         /* NOTE: if you change values here, also change them in sequencer_init_preview_region */
185         ar= MEM_callocN(sizeof(ARegion), "preview area for sequencer");
186         BLI_addtail(&sseq->regionbase, ar);
187         ar->regiontype= RGN_TYPE_PREVIEW;
188         ar->alignment= RGN_ALIGN_TOP;
189         ar->flag |= RGN_FLAG_HIDDEN;
190         /* for now, aspect ratio should be maintained, and zoom is clamped within sane default limits */
191         ar->v2d.keepzoom= V2D_KEEPASPECT | V2D_KEEPZOOM;
192         ar->v2d.minzoom= 0.00001f;
193         ar->v2d.maxzoom= 100000.0f;
194         ar->v2d.tot.xmin= -960.0f; /* 1920 width centered */
195         ar->v2d.tot.ymin= -540.0f; /* 1080 height centered */
196         ar->v2d.tot.xmax= 960.0f;
197         ar->v2d.tot.ymax= 540.0f;
198         ar->v2d.min[0]= 0.0f;
199         ar->v2d.min[1]= 0.0f;
200         ar->v2d.max[0]= 12000.0f;
201         ar->v2d.max[1]= 12000.0f;
202         ar->v2d.cur= ar->v2d.tot;
203         ar->v2d.align= V2D_ALIGN_FREE; 
204         ar->v2d.keeptot= V2D_KEEPTOT_FREE;
205
206
207         /* main area */
208         ar= MEM_callocN(sizeof(ARegion), "main area for sequencer");
209         
210         BLI_addtail(&sseq->regionbase, ar);
211         ar->regiontype= RGN_TYPE_WINDOW;
212         
213         
214         /* seq space goes from (0,8) to (0, efra) */
215         
216         ar->v2d.tot.xmin= 0.0f;
217         ar->v2d.tot.ymin= 0.0f;
218         ar->v2d.tot.xmax= scene->r.efra;
219         ar->v2d.tot.ymax= 8.0f;
220         
221         ar->v2d.cur= ar->v2d.tot;
222         
223         ar->v2d.min[0]= 10.0f;
224         ar->v2d.min[1]= 4.0f;
225         
226         ar->v2d.max[0]= MAXFRAMEF;
227         ar->v2d.max[1]= MAXSEQ;
228         
229         ar->v2d.minzoom= 0.01f;
230         ar->v2d.maxzoom= 100.0f;
231         
232         ar->v2d.scroll |= (V2D_SCROLL_BOTTOM|V2D_SCROLL_SCALE_HORIZONTAL);
233         ar->v2d.scroll |= (V2D_SCROLL_LEFT|V2D_SCROLL_SCALE_VERTICAL);
234         ar->v2d.keepzoom= 0;
235         ar->v2d.keeptot= 0;
236         ar->v2d.align= V2D_ALIGN_NO_NEG_Y;
237
238         return (SpaceLink *)sseq;
239 }
240
241 /* not spacelink itself */
242 static void sequencer_free(SpaceLink *UNUSED(sl))
243 {       
244 //      SpaceSeq *sseq= (SpaceSequencer*) sl;
245         
246 // XXX  if(sseq->gpd) free_gpencil_data(sseq->gpd);
247
248 }
249
250
251 /* spacetype; init callback */
252 static void sequencer_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
253 {
254         
255 }
256
257 static SpaceLink *sequencer_duplicate(SpaceLink *sl)
258 {
259         SpaceSeq *sseqn= MEM_dupallocN(sl);
260         
261         /* clear or remove stuff from old */
262 // XXX  sseq->gpd= gpencil_data_duplicate(sseq->gpd);
263
264         return (SpaceLink *)sseqn;
265 }
266
267
268
269 /* *********************** sequencer (main) region ************************ */
270 /* add handlers, stuff you only do once or on area/region changes */
271 static void sequencer_main_area_init(wmWindowManager *wm, ARegion *ar)
272 {
273         wmKeyMap *keymap;
274         ListBase *lb;
275         
276         UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
277         
278         keymap= WM_keymap_find(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0);
279         WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
280         
281         /* own keymap */
282         keymap= WM_keymap_find(wm->defaultconf, "Sequencer", SPACE_SEQ, 0);
283         WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
284         
285         /* add drop boxes */
286         lb= WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW);
287         
288         WM_event_add_dropbox_handler(&ar->handlers, lb);
289         
290 }
291
292 static void sequencer_main_area_draw(const bContext *C, ARegion *ar)
293 {
294 //      ScrArea *sa= CTX_wm_area(C);
295         
296         /* NLE - strip editing timeline interface */
297         draw_timeline_seq(C, ar);
298 }
299
300 /* ************* dropboxes ************* */
301
302 static int image_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
303 {
304         if(drag->type==WM_DRAG_PATH)
305                 if(ELEM(drag->icon, ICON_FILE_IMAGE, ICON_FILE_BLANK))  /* rule might not work? */
306                         return 1;
307         return 0;
308 }
309
310 static int movie_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
311 {
312         if(drag->type==WM_DRAG_PATH)
313                 if(ELEM3(drag->icon, 0, ICON_FILE_MOVIE, ICON_FILE_BLANK))      /* rule might not work? */
314                         return 1;
315         return 0;
316 }
317
318 static int sound_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
319 {
320         if(drag->type==WM_DRAG_PATH)
321                 if(ELEM(drag->icon, ICON_FILE_SOUND, ICON_FILE_BLANK))  /* rule might not work? */
322                         return 1;
323         return 0;
324 }
325
326 static void sequencer_drop_copy(wmDrag *drag, wmDropBox *drop)
327 {
328         /* copy drag path to properties */
329         if(RNA_struct_find_property(drop->ptr, "filepath"))
330                 RNA_string_set(drop->ptr, "filepath", drag->path);
331
332         if(RNA_struct_find_property(drop->ptr, "directory")) {
333                 PointerRNA itemptr;
334                 char dir[FILE_MAX], file[FILE_MAX];
335
336                 BLI_split_dirfile(drag->path, dir, file);
337                 
338                 RNA_string_set(drop->ptr, "directory", dir);
339
340                 RNA_collection_clear(drop->ptr, "files");
341                 RNA_collection_add(drop->ptr, "files", &itemptr);
342                 RNA_string_set(&itemptr, "name", file);
343         }
344 }
345
346 /* this region dropbox definition */
347 static void sequencer_dropboxes(void)
348 {
349         ListBase *lb= WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW);
350         
351         WM_dropbox_add(lb, "SEQUENCER_OT_image_strip_add", image_drop_poll, sequencer_drop_copy);
352         WM_dropbox_add(lb, "SEQUENCER_OT_movie_strip_add", movie_drop_poll, sequencer_drop_copy);
353         WM_dropbox_add(lb, "SEQUENCER_OT_sound_strip_add", sound_drop_poll, sequencer_drop_copy);
354 }
355
356 /* ************* end drop *********** */
357
358 /* add handlers, stuff you only do once or on area/region changes */
359 static void sequencer_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
360 {
361         ED_region_header_init(ar);
362 }
363
364 static void sequencer_header_area_draw(const bContext *C, ARegion *ar)
365 {
366         ED_region_header(C, ar);
367 }
368
369 static void sequencer_main_area_listener(ARegion *ar, wmNotifier *wmn)
370 {
371         /* context changes */
372         switch(wmn->category) {
373                 case NC_SCENE:
374                         switch(wmn->data) {
375                                 case ND_FRAME:
376                                 case ND_FRAME_RANGE:
377                                 case ND_MARKERS:
378                                 case ND_RENDER_OPTIONS: /* for FPS and FPS Base */
379                                 case ND_SEQUENCER:
380                                         ED_region_tag_redraw(ar);
381                                         break;
382                         }
383                         break;
384                 case NC_SPACE:
385                         if(wmn->data == ND_SPACE_SEQUENCER)
386                                 ED_region_tag_redraw(ar);
387                         break;
388                 case NC_ID:
389                         if(wmn->action == NA_RENAME)
390                                 ED_region_tag_redraw(ar);
391                         break;
392         }
393 }
394
395 /* *********************** preview region ************************ */
396 static void sequencer_preview_area_init(wmWindowManager *wm, ARegion *ar)
397 {
398         wmKeyMap *keymap;
399
400         UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
401         
402         keymap= WM_keymap_find(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0);
403         WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
404
405         /* own keymap */
406         keymap= WM_keymap_find(wm->defaultconf, "SequencerPreview", SPACE_SEQ, 0);
407         WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
408 }
409
410 static void sequencer_preview_area_draw(const bContext *C, ARegion *ar)
411 {
412         ScrArea *sa= CTX_wm_area(C);
413         SpaceSeq *sseq= sa->spacedata.first;
414         Scene *scene= CTX_data_scene(C);
415         
416         /* XXX temp fix for wrong setting in sseq->mainb */
417         if (sseq->mainb == SEQ_DRAW_SEQUENCE) sseq->mainb = SEQ_DRAW_IMG_IMBUF;
418
419         draw_image_seq(C, scene, ar, sseq, scene->r.cfra, 0);
420
421         if(scene->ed && scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW && sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
422                 int over_cfra;
423
424                 if(scene->ed->over_flag & SEQ_EDIT_OVERLAY_ABS)
425                         over_cfra= scene->ed->over_cfra;
426                 else
427                         over_cfra= scene->r.cfra + scene->ed->over_ofs;
428
429                 if(over_cfra != scene->r.cfra)
430                         draw_image_seq(C, scene, ar, sseq, scene->r.cfra, over_cfra - scene->r.cfra);
431         }
432
433 }
434
435 static void sequencer_preview_area_listener(ARegion *ar, wmNotifier *wmn)
436 {
437         /* context changes */
438         switch(wmn->category) {
439                 case NC_SCENE:
440                         switch(wmn->data) {
441                                 case ND_FRAME:
442                                 case ND_MARKERS:
443                                 case ND_SEQUENCER:
444                                         ED_region_tag_redraw(ar);
445                                         break;
446                         }
447                         break;
448                 case NC_SPACE:
449                         if(wmn->data == ND_SPACE_SEQUENCER)
450                                 ED_region_tag_redraw(ar);
451                         break;
452                 case NC_ID:
453                         switch(wmn->data) {
454                                 case NA_RENAME:
455                                         ED_region_tag_redraw(ar);
456                                         break;
457                         }
458                         break;
459         }
460 }
461
462 /* *********************** buttons region ************************ */
463
464 /* add handlers, stuff you only do once or on area/region changes */
465 static void sequencer_buttons_area_init(wmWindowManager *wm, ARegion *ar)
466 {
467         
468         ED_region_panels_init(wm, ar);
469         
470 }
471
472 static void sequencer_buttons_area_draw(const bContext *C, ARegion *ar)
473 {
474         ED_region_panels(C, ar, 1, NULL, -1);
475 }
476
477 static void sequencer_buttons_area_listener(ARegion *ar, wmNotifier *wmn)
478 {
479         /* context changes */
480         switch(wmn->category) {
481                 case NC_SCENE:
482                 switch(wmn->data) {
483                         case ND_FRAME:
484                         case ND_SEQUENCER:
485                                 ED_region_tag_redraw(ar);
486                                 break;
487                 }
488                 break;
489                 case NC_SPACE:
490                         if(wmn->data == ND_SPACE_SEQUENCER)
491                                 ED_region_tag_redraw(ar);
492                         break;
493                 case NC_ID:
494                         if(wmn->action == NA_RENAME)
495                                 ED_region_tag_redraw(ar);
496                         break;
497         }
498 }
499 /* ************************************* */
500
501 /* only called once, from space/spacetypes.c */
502 void ED_spacetype_sequencer(void)
503 {
504         SpaceType *st= MEM_callocN(sizeof(SpaceType), "spacetype sequencer");
505         ARegionType *art;
506         
507         st->spaceid= SPACE_SEQ;
508         strncpy(st->name, "Sequencer", BKE_ST_MAXNAME);
509         
510         st->new= sequencer_new;
511         st->free= sequencer_free;
512         st->init= sequencer_init;
513         st->duplicate= sequencer_duplicate;
514         st->operatortypes= sequencer_operatortypes;
515         st->keymap= sequencer_keymap;
516         st->dropboxes= sequencer_dropboxes;
517
518         /* regions: main window */
519         art= MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
520         art->regionid = RGN_TYPE_WINDOW;
521         art->init= sequencer_main_area_init;
522         art->draw= sequencer_main_area_draw;
523         art->listener= sequencer_main_area_listener;
524         art->keymapflag= ED_KEYMAP_VIEW2D|ED_KEYMAP_MARKERS|ED_KEYMAP_FRAMES|ED_KEYMAP_ANIMATION;
525
526         BLI_addhead(&st->regiontypes, art);
527
528         /* preview */
529         art= MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
530         art->regionid = RGN_TYPE_PREVIEW;
531         art->prefsizey = 240; // XXX
532         art->init= sequencer_preview_area_init;
533         art->draw= sequencer_preview_area_draw;
534         art->listener= sequencer_preview_area_listener;
535         art->keymapflag= ED_KEYMAP_VIEW2D|ED_KEYMAP_FRAMES|ED_KEYMAP_ANIMATION;
536         BLI_addhead(&st->regiontypes, art);
537         
538         /* regions: listview/buttons */
539         art= MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
540         art->regionid = RGN_TYPE_UI;
541         art->prefsizex= 220; // XXX
542         art->keymapflag= ED_KEYMAP_UI|ED_KEYMAP_FRAMES;
543         art->listener= sequencer_buttons_area_listener;
544         art->init= sequencer_buttons_area_init;
545         art->draw= sequencer_buttons_area_draw;
546         BLI_addhead(&st->regiontypes, art);
547         
548         /* Keep as python only for now
549         sequencer_buttons_register(art);
550         */
551
552         /* regions: header */
553         art= MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
554         art->regionid = RGN_TYPE_HEADER;
555         art->prefsizey= HEADERY;
556         art->keymapflag= ED_KEYMAP_UI|ED_KEYMAP_VIEW2D|ED_KEYMAP_FRAMES|ED_KEYMAP_HEADER;
557         
558         art->init= sequencer_header_area_init;
559         art->draw= sequencer_header_area_draw;
560         art->listener= sequencer_main_area_listener;
561         
562         BLI_addhead(&st->regiontypes, art);
563         
564         BKE_spacetype_register(st);
565
566         /* set the sequencer callback when not in background mode */
567         if(G.background==0) {
568                 sequencer_view3d_cb= ED_view3d_draw_offscreen_imbuf_simple;
569         }
570 }
571