93584011844f31a0f3891eeef5e909550ab2c825
[blender.git] / source / blender / editors / space_clip / space_clip.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) 2011 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup spclip
22  */
23
24 #include <string.h>
25 #include <stdio.h>
26
27 #include "DNA_scene_types.h"
28 #include "DNA_mask_types.h"
29 #include "DNA_movieclip_types.h"
30 #include "DNA_view3d_types.h" /* for pivot point */
31
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_blenlib.h"
35 #include "BLI_utildefines.h"
36 #include "BLI_math.h"
37
38 #include "BKE_context.h"
39 #include "BKE_library.h"
40 #include "BKE_movieclip.h"
41 #include "BKE_tracking.h"
42 #include "BKE_screen.h"
43
44 #include "IMB_imbuf_types.h"
45
46 #include "ED_anim_api.h" /* for timeline cursor drawing */
47 #include "ED_mask.h"
48 #include "ED_space_api.h"
49 #include "ED_screen.h"
50 #include "ED_time_scrub_ui.h"
51 #include "ED_select_utils.h"
52 #include "ED_clip.h"
53 #include "ED_transform.h"
54 #include "ED_uvedit.h" /* just for ED_image_draw_cursor */
55
56 #include "IMB_imbuf.h"
57
58 #include "GPU_glew.h"
59 #include "GPU_matrix.h"
60 #include "GPU_framebuffer.h"
61
62 #include "WM_api.h"
63 #include "WM_types.h"
64
65 #include "UI_interface.h"
66 #include "UI_resources.h"
67 #include "UI_view2d.h"
68
69 #include "RNA_access.h"
70
71 #include "clip_intern.h" /* own include */
72
73 static void init_preview_region(const Scene *scene,
74                                 const ScrArea *sa,
75                                 const SpaceClip *sc,
76                                 ARegion *ar)
77 {
78   ar->regiontype = RGN_TYPE_PREVIEW;
79   ar->alignment = RGN_ALIGN_TOP;
80   ar->flag |= RGN_FLAG_HIDDEN;
81
82   if (sc->view == SC_VIEW_DOPESHEET) {
83     ar->v2d.tot.xmin = -10.0f;
84     ar->v2d.tot.ymin = (float)(-sa->winy) / 3.0f;
85     ar->v2d.tot.xmax = (float)(sa->winx);
86     ar->v2d.tot.ymax = 0.0f;
87
88     ar->v2d.cur = ar->v2d.tot;
89
90     ar->v2d.min[0] = 0.0f;
91     ar->v2d.min[1] = 0.0f;
92
93     ar->v2d.max[0] = MAXFRAMEF;
94     ar->v2d.max[1] = FLT_MAX;
95
96     ar->v2d.minzoom = 0.01f;
97     ar->v2d.maxzoom = 50;
98     ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES);
99     ar->v2d.scroll |= (V2D_SCROLL_RIGHT);
100     ar->v2d.keepzoom = V2D_LOCKZOOM_Y;
101     ar->v2d.keepofs = V2D_KEEPOFS_Y;
102     ar->v2d.align = V2D_ALIGN_NO_POS_Y;
103     ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL;
104   }
105   else {
106     ar->v2d.tot.xmin = 0.0f;
107     ar->v2d.tot.ymin = -10.0f;
108     ar->v2d.tot.xmax = (float)scene->r.efra;
109     ar->v2d.tot.ymax = 10.0f;
110
111     ar->v2d.cur = ar->v2d.tot;
112
113     ar->v2d.min[0] = FLT_MIN;
114     ar->v2d.min[1] = FLT_MIN;
115
116     ar->v2d.max[0] = MAXFRAMEF;
117     ar->v2d.max[1] = FLT_MAX;
118
119     ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES);
120     ar->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HANDLES);
121
122     ar->v2d.minzoom = 0.0f;
123     ar->v2d.maxzoom = 0.0f;
124     ar->v2d.keepzoom = 0;
125     ar->v2d.keepofs = 0;
126     ar->v2d.align = 0;
127     ar->v2d.flag = 0;
128
129     ar->v2d.keeptot = 0;
130   }
131 }
132
133 static void reinit_preview_region(const bContext *C, ARegion *ar)
134 {
135   Scene *scene = CTX_data_scene(C);
136   ScrArea *sa = CTX_wm_area(C);
137   SpaceClip *sc = CTX_wm_space_clip(C);
138
139   if (sc->view == SC_VIEW_DOPESHEET) {
140     if ((ar->v2d.flag & V2D_VIEWSYNC_AREA_VERTICAL) == 0) {
141       init_preview_region(scene, sa, sc, ar);
142     }
143   }
144   else {
145     if (ar->v2d.flag & V2D_VIEWSYNC_AREA_VERTICAL) {
146       init_preview_region(scene, sa, sc, ar);
147     }
148   }
149 }
150
151 static ARegion *ED_clip_has_preview_region(const bContext *C, ScrArea *sa)
152 {
153   ARegion *ar, *arnew;
154
155   ar = BKE_area_find_region_type(sa, RGN_TYPE_PREVIEW);
156   if (ar) {
157     return ar;
158   }
159
160   /* add subdiv level; after header */
161   ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
162
163   /* is error! */
164   if (ar == NULL) {
165     return NULL;
166   }
167
168   arnew = MEM_callocN(sizeof(ARegion), "clip preview region");
169
170   BLI_insertlinkbefore(&sa->regionbase, ar, arnew);
171   init_preview_region(CTX_data_scene(C), sa, CTX_wm_space_clip(C), arnew);
172
173   return arnew;
174 }
175
176 static ARegion *ED_clip_has_channels_region(ScrArea *sa)
177 {
178   ARegion *ar, *arnew;
179
180   ar = BKE_area_find_region_type(sa, RGN_TYPE_CHANNELS);
181   if (ar) {
182     return ar;
183   }
184
185   /* add subdiv level; after header */
186   ar = BKE_area_find_region_type(sa, RGN_TYPE_PREVIEW);
187
188   /* is error! */
189   if (ar == NULL) {
190     return NULL;
191   }
192
193   arnew = MEM_callocN(sizeof(ARegion), "clip channels region");
194
195   BLI_insertlinkbefore(&sa->regionbase, ar, arnew);
196   arnew->regiontype = RGN_TYPE_CHANNELS;
197   arnew->alignment = RGN_ALIGN_LEFT;
198
199   arnew->v2d.scroll = V2D_SCROLL_BOTTOM;
200   arnew->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL;
201
202   return arnew;
203 }
204
205 static void clip_scopes_tag_refresh(ScrArea *sa)
206 {
207   SpaceClip *sc = (SpaceClip *)sa->spacedata.first;
208   ARegion *ar;
209
210   if (sc->mode != SC_MODE_TRACKING) {
211     return;
212   }
213
214   /* only while properties are visible */
215   for (ar = sa->regionbase.first; ar; ar = ar->next) {
216     if (ar->regiontype == RGN_TYPE_UI && ar->flag & RGN_FLAG_HIDDEN) {
217       return;
218     }
219   }
220
221   sc->scopes.ok = false;
222 }
223
224 static void clip_scopes_check_gpencil_change(ScrArea *sa)
225 {
226   SpaceClip *sc = (SpaceClip *)sa->spacedata.first;
227
228   if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
229     clip_scopes_tag_refresh(sa);
230   }
231 }
232
233 static void clip_area_sync_frame_from_scene(ScrArea *sa, Scene *scene)
234 {
235   SpaceClip *space_clip = (SpaceClip *)sa->spacedata.first;
236   BKE_movieclip_user_set_frame(&space_clip->user, scene->r.cfra);
237 }
238
239 /* ******************** default callbacks for clip space ***************** */
240
241 static SpaceLink *clip_new(const ScrArea *sa, const Scene *scene)
242 {
243   ARegion *ar;
244   SpaceClip *sc;
245
246   sc = MEM_callocN(sizeof(SpaceClip), "initclip");
247   sc->spacetype = SPACE_CLIP;
248   sc->flag = SC_SHOW_MARKER_PATTERN | SC_SHOW_TRACK_PATH | SC_SHOW_GRAPH_TRACKS_MOTION |
249              SC_SHOW_GRAPH_FRAMES | SC_SHOW_ANNOTATION;
250   sc->zoom = 1.0f;
251   sc->path_length = 20;
252   sc->scopes.track_preview_height = 120;
253   sc->around = V3D_AROUND_CENTER_MEDIAN;
254
255   /* header */
256   ar = MEM_callocN(sizeof(ARegion), "header for clip");
257
258   BLI_addtail(&sc->regionbase, ar);
259   ar->regiontype = RGN_TYPE_HEADER;
260   ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
261
262   /* tools view */
263   ar = MEM_callocN(sizeof(ARegion), "tools for clip");
264
265   BLI_addtail(&sc->regionbase, ar);
266   ar->regiontype = RGN_TYPE_TOOLS;
267   ar->alignment = RGN_ALIGN_LEFT;
268
269   /* properties view */
270   ar = MEM_callocN(sizeof(ARegion), "properties for clip");
271
272   BLI_addtail(&sc->regionbase, ar);
273   ar->regiontype = RGN_TYPE_UI;
274   ar->alignment = RGN_ALIGN_RIGHT;
275
276   /* channels view */
277   ar = MEM_callocN(sizeof(ARegion), "channels for clip");
278
279   BLI_addtail(&sc->regionbase, ar);
280   ar->regiontype = RGN_TYPE_CHANNELS;
281   ar->alignment = RGN_ALIGN_LEFT;
282
283   ar->v2d.scroll = V2D_SCROLL_BOTTOM;
284   ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL;
285
286   /* preview view */
287   ar = MEM_callocN(sizeof(ARegion), "preview for clip");
288
289   BLI_addtail(&sc->regionbase, ar);
290   init_preview_region(scene, sa, sc, ar);
291
292   /* main region */
293   ar = MEM_callocN(sizeof(ARegion), "main region for clip");
294
295   BLI_addtail(&sc->regionbase, ar);
296   ar->regiontype = RGN_TYPE_WINDOW;
297
298   return (SpaceLink *)sc;
299 }
300
301 /* not spacelink itself */
302 static void clip_free(SpaceLink *sl)
303 {
304   SpaceClip *sc = (SpaceClip *)sl;
305
306   sc->clip = NULL;
307
308   if (sc->scopes.track_preview) {
309     IMB_freeImBuf(sc->scopes.track_preview);
310   }
311
312   if (sc->scopes.track_search) {
313     IMB_freeImBuf(sc->scopes.track_search);
314   }
315 }
316
317 /* spacetype; init callback */
318 static void clip_init(struct wmWindowManager *UNUSED(wm), ScrArea *sa)
319 {
320   ListBase *lb = WM_dropboxmap_find("Clip", SPACE_CLIP, 0);
321
322   /* add drop boxes */
323   WM_event_add_dropbox_handler(&sa->handlers, lb);
324 }
325
326 static SpaceLink *clip_duplicate(SpaceLink *sl)
327 {
328   SpaceClip *scn = MEM_dupallocN(sl);
329
330   /* clear or remove stuff from old */
331   scn->scopes.track_search = NULL;
332   scn->scopes.track_preview = NULL;
333   scn->scopes.ok = false;
334
335   return (SpaceLink *)scn;
336 }
337
338 static void clip_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, Scene *scene)
339 {
340   /* context changes */
341   switch (wmn->category) {
342     case NC_SCENE:
343       switch (wmn->data) {
344         case ND_FRAME:
345           clip_scopes_tag_refresh(sa);
346           ATTR_FALLTHROUGH;
347
348         case ND_FRAME_RANGE:
349           ED_area_tag_redraw(sa);
350           break;
351       }
352       break;
353     case NC_MOVIECLIP:
354       switch (wmn->data) {
355         case ND_DISPLAY:
356         case ND_SELECT:
357           clip_scopes_tag_refresh(sa);
358           ED_area_tag_redraw(sa);
359           break;
360       }
361       switch (wmn->action) {
362         case NA_REMOVED:
363         case NA_EDITED:
364         case NA_EVALUATED:
365           /* fall-through */
366
367         case NA_SELECTED:
368           clip_scopes_tag_refresh(sa);
369           ED_area_tag_redraw(sa);
370           break;
371       }
372       break;
373     case NC_MASK:
374       switch (wmn->data) {
375         case ND_SELECT:
376         case ND_DATA:
377         case ND_DRAW:
378           ED_area_tag_redraw(sa);
379           break;
380       }
381       switch (wmn->action) {
382         case NA_SELECTED:
383           ED_area_tag_redraw(sa);
384           break;
385         case NA_EDITED:
386           ED_area_tag_redraw(sa);
387           break;
388       }
389       break;
390     case NC_GEOM:
391       switch (wmn->data) {
392         case ND_SELECT:
393           clip_scopes_tag_refresh(sa);
394           ED_area_tag_redraw(sa);
395           break;
396       }
397       break;
398     case NC_SCREEN:
399       switch (wmn->data) {
400         case ND_ANIMPLAY:
401           ED_area_tag_redraw(sa);
402           break;
403         case ND_LAYOUTSET:
404           clip_area_sync_frame_from_scene(sa, scene);
405           break;
406       }
407       break;
408     case NC_SPACE:
409       if (wmn->data == ND_SPACE_CLIP) {
410         clip_scopes_tag_refresh(sa);
411         ED_area_tag_redraw(sa);
412       }
413       break;
414     case NC_GPENCIL:
415       if (wmn->action == NA_EDITED) {
416         clip_scopes_check_gpencil_change(sa);
417         ED_area_tag_redraw(sa);
418       }
419       else if (wmn->data & ND_GPENCIL_EDITMODE) {
420         ED_area_tag_redraw(sa);
421       }
422       break;
423     case NC_WM:
424       switch (wmn->data) {
425         case ND_FILEREAD:
426         case ND_UNDO:
427           clip_area_sync_frame_from_scene(sa, scene);
428           break;
429       }
430       break;
431   }
432 }
433
434 static void clip_operatortypes(void)
435 {
436   /* ** clip_ops.c ** */
437   WM_operatortype_append(CLIP_OT_open);
438   WM_operatortype_append(CLIP_OT_reload);
439   WM_operatortype_append(CLIP_OT_view_pan);
440   WM_operatortype_append(CLIP_OT_view_zoom);
441   WM_operatortype_append(CLIP_OT_view_zoom_in);
442   WM_operatortype_append(CLIP_OT_view_zoom_out);
443   WM_operatortype_append(CLIP_OT_view_zoom_ratio);
444   WM_operatortype_append(CLIP_OT_view_all);
445   WM_operatortype_append(CLIP_OT_view_selected);
446   WM_operatortype_append(CLIP_OT_change_frame);
447   WM_operatortype_append(CLIP_OT_rebuild_proxy);
448   WM_operatortype_append(CLIP_OT_mode_set);
449 #ifdef WITH_INPUT_NDOF
450   WM_operatortype_append(CLIP_OT_view_ndof);
451 #endif
452   WM_operatortype_append(CLIP_OT_prefetch);
453   WM_operatortype_append(CLIP_OT_set_scene_frames);
454   WM_operatortype_append(CLIP_OT_cursor_set);
455
456   /* ** tracking_ops.c ** */
457
458   /* navigation */
459   WM_operatortype_append(CLIP_OT_frame_jump);
460
461   /* set optical center to frame center */
462   WM_operatortype_append(CLIP_OT_set_center_principal);
463
464   /* selection */
465   WM_operatortype_append(CLIP_OT_select);
466   WM_operatortype_append(CLIP_OT_select_all);
467   WM_operatortype_append(CLIP_OT_select_box);
468   WM_operatortype_append(CLIP_OT_select_lasso);
469   WM_operatortype_append(CLIP_OT_select_circle);
470   WM_operatortype_append(CLIP_OT_select_grouped);
471
472   /* markers */
473   WM_operatortype_append(CLIP_OT_add_marker);
474   WM_operatortype_append(CLIP_OT_add_marker_at_click);
475   WM_operatortype_append(CLIP_OT_slide_marker);
476   WM_operatortype_append(CLIP_OT_delete_track);
477   WM_operatortype_append(CLIP_OT_delete_marker);
478
479   /* track */
480   WM_operatortype_append(CLIP_OT_track_markers);
481   WM_operatortype_append(CLIP_OT_refine_markers);
482
483   /* solving */
484   WM_operatortype_append(CLIP_OT_solve_camera);
485   WM_operatortype_append(CLIP_OT_clear_solution);
486
487   WM_operatortype_append(CLIP_OT_disable_markers);
488   WM_operatortype_append(CLIP_OT_hide_tracks);
489   WM_operatortype_append(CLIP_OT_hide_tracks_clear);
490   WM_operatortype_append(CLIP_OT_lock_tracks);
491
492   WM_operatortype_append(CLIP_OT_set_solver_keyframe);
493
494   /* orientation */
495   WM_operatortype_append(CLIP_OT_set_origin);
496   WM_operatortype_append(CLIP_OT_set_plane);
497   WM_operatortype_append(CLIP_OT_set_axis);
498   WM_operatortype_append(CLIP_OT_set_scale);
499   WM_operatortype_append(CLIP_OT_set_solution_scale);
500   WM_operatortype_append(CLIP_OT_apply_solution_scale);
501
502   /* detect */
503   WM_operatortype_append(CLIP_OT_detect_features);
504
505   /* stabilization */
506   WM_operatortype_append(CLIP_OT_stabilize_2d_add);
507   WM_operatortype_append(CLIP_OT_stabilize_2d_remove);
508   WM_operatortype_append(CLIP_OT_stabilize_2d_select);
509   WM_operatortype_append(CLIP_OT_stabilize_2d_rotation_add);
510   WM_operatortype_append(CLIP_OT_stabilize_2d_rotation_remove);
511   WM_operatortype_append(CLIP_OT_stabilize_2d_rotation_select);
512
513   /* clean-up */
514   WM_operatortype_append(CLIP_OT_clear_track_path);
515   WM_operatortype_append(CLIP_OT_join_tracks);
516   WM_operatortype_append(CLIP_OT_track_copy_color);
517
518   WM_operatortype_append(CLIP_OT_clean_tracks);
519
520   /* object tracking */
521   WM_operatortype_append(CLIP_OT_tracking_object_new);
522   WM_operatortype_append(CLIP_OT_tracking_object_remove);
523
524   /* clipboard */
525   WM_operatortype_append(CLIP_OT_copy_tracks);
526   WM_operatortype_append(CLIP_OT_paste_tracks);
527
528   /* Plane tracker */
529   WM_operatortype_append(CLIP_OT_create_plane_track);
530   WM_operatortype_append(CLIP_OT_slide_plane_marker);
531
532   WM_operatortype_append(CLIP_OT_keyframe_insert);
533   WM_operatortype_append(CLIP_OT_keyframe_delete);
534
535   /* ** clip_graph_ops.c  ** */
536
537   /* graph editing */
538
539   /* selection */
540   WM_operatortype_append(CLIP_OT_graph_select);
541   WM_operatortype_append(CLIP_OT_graph_select_box);
542   WM_operatortype_append(CLIP_OT_graph_select_all_markers);
543
544   WM_operatortype_append(CLIP_OT_graph_delete_curve);
545   WM_operatortype_append(CLIP_OT_graph_delete_knot);
546   WM_operatortype_append(CLIP_OT_graph_view_all);
547   WM_operatortype_append(CLIP_OT_graph_center_current_frame);
548
549   WM_operatortype_append(CLIP_OT_graph_disable_markers);
550
551   /* ** clip_dopesheet_ops.c  ** */
552
553   WM_operatortype_append(CLIP_OT_dopesheet_select_channel);
554   WM_operatortype_append(CLIP_OT_dopesheet_view_all);
555 }
556
557 static void clip_keymap(struct wmKeyConfig *keyconf)
558 {
559   /* ******** Global hotkeys avalaible for all regions ******** */
560   WM_keymap_ensure(keyconf, "Clip", SPACE_CLIP, 0);
561
562   /* ******** Hotkeys avalaible for main region only ******** */
563   WM_keymap_ensure(keyconf, "Clip Editor", SPACE_CLIP, 0);
564   //  keymap->poll = ED_space_clip_tracking_poll;
565
566   /* ******** Hotkeys avalaible for preview region only ******** */
567   WM_keymap_ensure(keyconf, "Clip Graph Editor", SPACE_CLIP, 0);
568
569   /* ******** Hotkeys avalaible for channels region only ******** */
570   WM_keymap_ensure(keyconf, "Clip Dopesheet Editor", SPACE_CLIP, 0);
571 }
572
573 /* DO NOT make this static, this hides the symbol and breaks API generation script. */
574 extern const char *clip_context_dir[]; /* quiet warning. */
575 const char *clip_context_dir[] = {"edit_movieclip", "edit_mask", NULL};
576
577 static int clip_context(const bContext *C, const char *member, bContextDataResult *result)
578 {
579   SpaceClip *sc = CTX_wm_space_clip(C);
580
581   if (CTX_data_dir(member)) {
582     CTX_data_dir_set(result, clip_context_dir);
583
584     return true;
585   }
586   else if (CTX_data_equals(member, "edit_movieclip")) {
587     if (sc->clip) {
588       CTX_data_id_pointer_set(result, &sc->clip->id);
589     }
590     return true;
591   }
592   else if (CTX_data_equals(member, "edit_mask")) {
593     if (sc->mask_info.mask) {
594       CTX_data_id_pointer_set(result, &sc->mask_info.mask->id);
595     }
596     return true;
597   }
598
599   return false;
600 }
601
602 /* dropboxes */
603 static bool clip_drop_poll(bContext *UNUSED(C),
604                            wmDrag *drag,
605                            const wmEvent *UNUSED(event),
606                            const char **UNUSED(tooltip))
607 {
608   if (drag->type == WM_DRAG_PATH) {
609     /* rule might not work? */
610     if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE, ICON_FILE_BLANK)) {
611       return true;
612     }
613   }
614
615   return false;
616 }
617
618 static void clip_drop_copy(wmDrag *drag, wmDropBox *drop)
619 {
620   PointerRNA itemptr;
621   char dir[FILE_MAX], file[FILE_MAX];
622
623   BLI_split_dirfile(drag->path, dir, file, sizeof(dir), sizeof(file));
624
625   RNA_string_set(drop->ptr, "directory", dir);
626
627   RNA_collection_clear(drop->ptr, "files");
628   RNA_collection_add(drop->ptr, "files", &itemptr);
629   RNA_string_set(&itemptr, "name", file);
630 }
631
632 /* area+region dropbox definition */
633 static void clip_dropboxes(void)
634 {
635   ListBase *lb = WM_dropboxmap_find("Clip", SPACE_CLIP, 0);
636
637   WM_dropbox_add(lb, "CLIP_OT_open", clip_drop_poll, clip_drop_copy);
638 }
639
640 static void clip_refresh(const bContext *C, ScrArea *sa)
641 {
642   wmWindowManager *wm = CTX_wm_manager(C);
643   wmWindow *window = CTX_wm_window(C);
644   Scene *scene = CTX_data_scene(C);
645   SpaceClip *sc = (SpaceClip *)sa->spacedata.first;
646   ARegion *ar_main = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
647   ARegion *ar_tools = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS);
648   ARegion *ar_preview = ED_clip_has_preview_region(C, sa);
649   ARegion *ar_properties = ED_clip_has_properties_region(sa);
650   ARegion *ar_channels = ED_clip_has_channels_region(sa);
651   bool main_visible = false, preview_visible = false, tools_visible = false;
652   bool properties_visible = false, channels_visible = false;
653   bool view_changed = false;
654
655   switch (sc->view) {
656     case SC_VIEW_CLIP:
657       main_visible = true;
658       preview_visible = false;
659       tools_visible = true;
660       properties_visible = true;
661       channels_visible = false;
662       break;
663     case SC_VIEW_GRAPH:
664       main_visible = false;
665       preview_visible = true;
666       tools_visible = false;
667       properties_visible = false;
668       channels_visible = false;
669
670       reinit_preview_region(C, ar_preview);
671       break;
672     case SC_VIEW_DOPESHEET:
673       main_visible = false;
674       preview_visible = true;
675       tools_visible = false;
676       properties_visible = false;
677       channels_visible = true;
678
679       reinit_preview_region(C, ar_preview);
680       break;
681   }
682
683   if (main_visible) {
684     if (ar_main && (ar_main->flag & RGN_FLAG_HIDDEN)) {
685       ar_main->flag &= ~RGN_FLAG_HIDDEN;
686       ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
687       view_changed = true;
688     }
689
690     if (ar_main && ar_main->alignment != RGN_ALIGN_NONE) {
691       ar_main->alignment = RGN_ALIGN_NONE;
692       view_changed = true;
693     }
694   }
695   else {
696     if (ar_main && !(ar_main->flag & RGN_FLAG_HIDDEN)) {
697       ar_main->flag |= RGN_FLAG_HIDDEN;
698       ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
699       WM_event_remove_handlers((bContext *)C, &ar_main->handlers);
700       view_changed = true;
701     }
702     if (ar_main && ar_main->alignment != RGN_ALIGN_NONE) {
703       ar_main->alignment = RGN_ALIGN_NONE;
704       view_changed = true;
705     }
706   }
707
708   if (properties_visible) {
709     if (ar_properties && (ar_properties->flag & RGN_FLAG_HIDDEN)) {
710       ar_properties->flag &= ~RGN_FLAG_HIDDEN;
711       ar_properties->v2d.flag &= ~V2D_IS_INITIALISED;
712       view_changed = true;
713     }
714     if (ar_properties && ar_properties->alignment != RGN_ALIGN_RIGHT) {
715       ar_properties->alignment = RGN_ALIGN_RIGHT;
716       view_changed = true;
717     }
718   }
719   else {
720     if (ar_properties && !(ar_properties->flag & RGN_FLAG_HIDDEN)) {
721       ar_properties->flag |= RGN_FLAG_HIDDEN;
722       ar_properties->v2d.flag &= ~V2D_IS_INITIALISED;
723       WM_event_remove_handlers((bContext *)C, &ar_properties->handlers);
724       view_changed = true;
725     }
726     if (ar_properties && ar_properties->alignment != RGN_ALIGN_NONE) {
727       ar_properties->alignment = RGN_ALIGN_NONE;
728       view_changed = true;
729     }
730   }
731
732   if (tools_visible) {
733     if (ar_tools && (ar_tools->flag & RGN_FLAG_HIDDEN)) {
734       ar_tools->flag &= ~RGN_FLAG_HIDDEN;
735       ar_tools->v2d.flag &= ~V2D_IS_INITIALISED;
736       view_changed = true;
737     }
738     if (ar_tools && ar_tools->alignment != RGN_ALIGN_LEFT) {
739       ar_tools->alignment = RGN_ALIGN_LEFT;
740       view_changed = true;
741     }
742   }
743   else {
744     if (ar_tools && !(ar_tools->flag & RGN_FLAG_HIDDEN)) {
745       ar_tools->flag |= RGN_FLAG_HIDDEN;
746       ar_tools->v2d.flag &= ~V2D_IS_INITIALISED;
747       WM_event_remove_handlers((bContext *)C, &ar_tools->handlers);
748       view_changed = true;
749     }
750     if (ar_tools && ar_tools->alignment != RGN_ALIGN_NONE) {
751       ar_tools->alignment = RGN_ALIGN_NONE;
752       view_changed = true;
753     }
754   }
755
756   if (preview_visible) {
757     if (ar_preview && (ar_preview->flag & RGN_FLAG_HIDDEN)) {
758       ar_preview->flag &= ~RGN_FLAG_HIDDEN;
759       ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
760       ar_preview->v2d.cur = ar_preview->v2d.tot;
761       view_changed = true;
762     }
763     if (ar_preview && ar_preview->alignment != RGN_ALIGN_NONE) {
764       ar_preview->alignment = RGN_ALIGN_NONE;
765       view_changed = true;
766     }
767   }
768   else {
769     if (ar_preview && !(ar_preview->flag & RGN_FLAG_HIDDEN)) {
770       ar_preview->flag |= RGN_FLAG_HIDDEN;
771       ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
772       WM_event_remove_handlers((bContext *)C, &ar_preview->handlers);
773       view_changed = true;
774     }
775     if (ar_preview && ar_preview->alignment != RGN_ALIGN_NONE) {
776       ar_preview->alignment = RGN_ALIGN_NONE;
777       view_changed = true;
778     }
779   }
780
781   if (channels_visible) {
782     if (ar_channels && (ar_channels->flag & RGN_FLAG_HIDDEN)) {
783       ar_channels->flag &= ~RGN_FLAG_HIDDEN;
784       ar_channels->v2d.flag &= ~V2D_IS_INITIALISED;
785       view_changed = true;
786     }
787     if (ar_channels && ar_channels->alignment != RGN_ALIGN_LEFT) {
788       ar_channels->alignment = RGN_ALIGN_LEFT;
789       view_changed = true;
790     }
791   }
792   else {
793     if (ar_channels && !(ar_channels->flag & RGN_FLAG_HIDDEN)) {
794       ar_channels->flag |= RGN_FLAG_HIDDEN;
795       ar_channels->v2d.flag &= ~V2D_IS_INITIALISED;
796       WM_event_remove_handlers((bContext *)C, &ar_channels->handlers);
797       view_changed = true;
798     }
799     if (ar_channels && ar_channels->alignment != RGN_ALIGN_NONE) {
800       ar_channels->alignment = RGN_ALIGN_NONE;
801       view_changed = true;
802     }
803   }
804
805   if (view_changed) {
806     ED_area_initialize(wm, window, sa);
807     ED_area_tag_redraw(sa);
808   }
809
810   BKE_movieclip_user_set_frame(&sc->user, scene->r.cfra);
811 }
812
813 static void CLIP_GGT_navigate(wmGizmoGroupType *gzgt)
814 {
815   VIEW2D_GGT_navigate_impl(gzgt, "CLIP_GGT_navigate");
816 }
817
818 static void clip_gizmos(void)
819 {
820   wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(
821       &(const struct wmGizmoMapType_Params){SPACE_CLIP, RGN_TYPE_WINDOW});
822
823   WM_gizmogrouptype_append_and_link(gzmap_type, CLIP_GGT_navigate);
824 }
825
826 /********************* main region ********************/
827
828 /* sets up the fields of the View2D from zoom and offset */
829 static void movieclip_main_area_set_view2d(const bContext *C, ARegion *ar)
830 {
831   SpaceClip *sc = CTX_wm_space_clip(C);
832   float x1, y1, w, h, aspx, aspy;
833   int width, height, winx, winy;
834
835   ED_space_clip_get_size(sc, &width, &height);
836   ED_space_clip_get_aspect(sc, &aspx, &aspy);
837
838   w = width * aspx;
839   h = height * aspy;
840
841   winx = BLI_rcti_size_x(&ar->winrct) + 1;
842   winy = BLI_rcti_size_y(&ar->winrct) + 1;
843
844   ar->v2d.tot.xmin = 0;
845   ar->v2d.tot.ymin = 0;
846   ar->v2d.tot.xmax = w;
847   ar->v2d.tot.ymax = h;
848
849   ar->v2d.mask.xmin = ar->v2d.mask.ymin = 0;
850   ar->v2d.mask.xmax = winx;
851   ar->v2d.mask.ymax = winy;
852
853   /* which part of the image space do we see? */
854   x1 = ar->winrct.xmin + (winx - sc->zoom * w) / 2.0f;
855   y1 = ar->winrct.ymin + (winy - sc->zoom * h) / 2.0f;
856
857   x1 -= sc->zoom * sc->xof;
858   y1 -= sc->zoom * sc->yof;
859
860   /* relative display right */
861   ar->v2d.cur.xmin = (ar->winrct.xmin - (float)x1) / sc->zoom;
862   ar->v2d.cur.xmax = ar->v2d.cur.xmin + ((float)winx / sc->zoom);
863
864   /* relative display left */
865   ar->v2d.cur.ymin = (ar->winrct.ymin - (float)y1) / sc->zoom;
866   ar->v2d.cur.ymax = ar->v2d.cur.ymin + ((float)winy / sc->zoom);
867
868   /* normalize 0.0..1.0 */
869   ar->v2d.cur.xmin /= w;
870   ar->v2d.cur.xmax /= w;
871   ar->v2d.cur.ymin /= h;
872   ar->v2d.cur.ymax /= h;
873 }
874
875 /* add handlers, stuff you only do once or on area/region changes */
876 static void clip_main_region_init(wmWindowManager *wm, ARegion *ar)
877 {
878   wmKeyMap *keymap;
879
880   UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_STANDARD, ar->winx, ar->winy);
881
882   /* mask polls mode */
883   keymap = WM_keymap_ensure(wm->defaultconf, "Mask Editing", 0, 0);
884   WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap);
885
886   /* own keymap */
887   keymap = WM_keymap_ensure(wm->defaultconf, "Clip", SPACE_CLIP, 0);
888   WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap);
889
890   keymap = WM_keymap_ensure(wm->defaultconf, "Clip Editor", SPACE_CLIP, 0);
891   WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap);
892 }
893
894 static void clip_main_region_draw(const bContext *C, ARegion *ar)
895 {
896   /* draw entirely, view changes should be handled here */
897   SpaceClip *sc = CTX_wm_space_clip(C);
898   MovieClip *clip = ED_space_clip_get_clip(sc);
899   float aspx, aspy, zoomx, zoomy, x, y;
900   int width, height;
901   bool show_cursor = false;
902
903   /* if tracking is in progress, we should synchronize framenr from clipuser
904    * so latest tracked frame would be shown */
905   if (clip && clip->tracking_context) {
906     BKE_autotrack_context_sync_user(clip->tracking_context, &sc->user);
907   }
908
909   if (sc->flag & SC_LOCK_SELECTION) {
910     ImBuf *tmpibuf = NULL;
911
912     if (clip && clip->tracking.stabilization.flag & TRACKING_2D_STABILIZATION) {
913       tmpibuf = ED_space_clip_get_stable_buffer(sc, NULL, NULL, NULL);
914     }
915
916     if (ED_clip_view_selection(C, ar, 0)) {
917       sc->xof += sc->xlockof;
918       sc->yof += sc->ylockof;
919     }
920
921     if (tmpibuf) {
922       IMB_freeImBuf(tmpibuf);
923     }
924   }
925
926   /* clear and setup matrix */
927   UI_ThemeClearColor(TH_BACK);
928   GPU_clear(GPU_COLOR_BIT);
929
930   /* data... */
931   movieclip_main_area_set_view2d(C, ar);
932
933   /* callback */
934   ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
935
936   clip_draw_main(C, sc, ar);
937
938   /* TODO(sergey): would be nice to find a way to de-duplicate all this space conversions */
939   UI_view2d_view_to_region_fl(&ar->v2d, 0.0f, 0.0f, &x, &y);
940   ED_space_clip_get_size(sc, &width, &height);
941   ED_space_clip_get_zoom(sc, ar, &zoomx, &zoomy);
942   ED_space_clip_get_aspect(sc, &aspx, &aspy);
943
944   if (sc->mode == SC_MODE_MASKEDIT) {
945     Mask *mask = CTX_data_edit_mask(C);
946     if (mask && clip) {
947       ScrArea *sa = CTX_wm_area(C);
948       int mask_width, mask_height;
949       ED_mask_get_size(sa, &mask_width, &mask_height);
950       ED_mask_draw_region(CTX_data_expect_evaluated_depsgraph(C),
951                           mask,
952                           ar,
953                           sc->mask_info.draw_flag,
954                           sc->mask_info.draw_type,
955                           sc->mask_info.overlay_mode,
956                           mask_width,
957                           mask_height,
958                           aspx,
959                           aspy,
960                           true,
961                           true,
962                           sc->stabmat,
963                           C);
964     }
965   }
966
967   show_cursor |= sc->mode == SC_MODE_MASKEDIT;
968   show_cursor |= sc->around == V3D_AROUND_CURSOR;
969
970   if (show_cursor) {
971     GPU_matrix_push();
972     GPU_matrix_translate_2f(x, y);
973     GPU_matrix_scale_2f(zoomx, zoomy);
974     GPU_matrix_mul(sc->stabmat);
975     GPU_matrix_scale_2f(width, height);
976     ED_image_draw_cursor(ar, sc->cursor);
977     GPU_matrix_pop();
978   }
979
980   clip_draw_cache_and_notes(C, sc, ar);
981
982   if (sc->flag & SC_SHOW_ANNOTATION) {
983     /* Grease Pencil */
984     clip_draw_grease_pencil((bContext *)C, true);
985   }
986
987   /* callback */
988   ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
989
990   /* reset view matrix */
991   UI_view2d_view_restore(C);
992
993   if (sc->flag & SC_SHOW_ANNOTATION) {
994     /* draw Grease Pencil - screen space only */
995     clip_draw_grease_pencil((bContext *)C, false);
996   }
997
998   WM_gizmomap_draw(ar->gizmo_map, C, WM_GIZMOMAP_DRAWSTEP_2D);
999 }
1000
1001 static void clip_main_region_listener(wmWindow *UNUSED(win),
1002                                       ScrArea *UNUSED(sa),
1003                                       ARegion *ar,
1004                                       wmNotifier *wmn,
1005                                       const Scene *UNUSED(scene))
1006 {
1007   /* context changes */
1008   switch (wmn->category) {
1009     case NC_GPENCIL:
1010       if (wmn->action == NA_EDITED) {
1011         ED_region_tag_redraw(ar);
1012       }
1013       else if (wmn->data & ND_GPENCIL_EDITMODE) {
1014         ED_region_tag_redraw(ar);
1015       }
1016       break;
1017   }
1018 }
1019
1020 /****************** preview region ******************/
1021
1022 static void clip_preview_region_init(wmWindowManager *wm, ARegion *ar)
1023 {
1024   wmKeyMap *keymap;
1025
1026   UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
1027
1028   /* own keymap */
1029
1030   keymap = WM_keymap_ensure(wm->defaultconf, "Clip", SPACE_CLIP, 0);
1031   WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap);
1032
1033   keymap = WM_keymap_ensure(wm->defaultconf, "Clip Time Scrub", SPACE_CLIP, RGN_TYPE_PREVIEW);
1034   WM_event_add_keymap_handler_poll(&ar->handlers, keymap, ED_time_scrub_event_in_region);
1035
1036   keymap = WM_keymap_ensure(wm->defaultconf, "Clip Graph Editor", SPACE_CLIP, 0);
1037   WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap);
1038
1039   keymap = WM_keymap_ensure(wm->defaultconf, "Clip Dopesheet Editor", SPACE_CLIP, 0);
1040   WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap);
1041 }
1042
1043 static void graph_region_draw(const bContext *C, ARegion *ar)
1044 {
1045   View2D *v2d = &ar->v2d;
1046   View2DScrollers *scrollers;
1047   SpaceClip *sc = CTX_wm_space_clip(C);
1048   Scene *scene = CTX_data_scene(C);
1049   short cfra_flag = 0;
1050
1051   if (sc->flag & SC_LOCK_TIMECURSOR) {
1052     ED_clip_graph_center_current_frame(scene, ar);
1053   }
1054
1055   /* clear and setup matrix */
1056   UI_ThemeClearColor(TH_BACK);
1057   GPU_clear(GPU_COLOR_BIT);
1058
1059   UI_view2d_view_ortho(v2d);
1060
1061   /* data... */
1062   clip_draw_graph(sc, ar, scene);
1063
1064   /* current frame indicator line */
1065   if (sc->flag & SC_SHOW_SECONDS) {
1066     cfra_flag |= DRAWCFRA_UNIT_SECONDS;
1067   }
1068   ANIM_draw_cfra(C, v2d, cfra_flag);
1069
1070   /* reset view matrix */
1071   UI_view2d_view_restore(C);
1072
1073   /* time-scrubbing */
1074   ED_time_scrub_draw(ar, scene, sc->flag & SC_SHOW_SECONDS, true);
1075
1076   /* scrollers */
1077   scrollers = UI_view2d_scrollers_calc(v2d, NULL);
1078   UI_view2d_scrollers_draw(v2d, scrollers);
1079   UI_view2d_scrollers_free(scrollers);
1080
1081   /* scale indicators */
1082   {
1083     rcti rect;
1084     BLI_rcti_init(&rect,
1085                   0,
1086                   15 * UI_DPI_FAC,
1087                   15 * UI_DPI_FAC,
1088                   UI_DPI_FAC * ar->sizey - UI_TIME_SCRUB_MARGIN_Y);
1089     UI_view2d_draw_scale_y__values(ar, v2d, &rect, TH_TEXT);
1090   }
1091 }
1092
1093 static void dopesheet_region_draw(const bContext *C, ARegion *ar)
1094 {
1095   Scene *scene = CTX_data_scene(C);
1096   SpaceClip *sc = CTX_wm_space_clip(C);
1097   MovieClip *clip = ED_space_clip_get_clip(sc);
1098   View2D *v2d = &ar->v2d;
1099   View2DScrollers *scrollers;
1100   short cfra_flag = 0;
1101
1102   if (clip) {
1103     BKE_tracking_dopesheet_update(&clip->tracking);
1104   }
1105
1106   /* clear and setup matrix */
1107   UI_ThemeClearColor(TH_BACK);
1108   GPU_clear(GPU_COLOR_BIT);
1109
1110   UI_view2d_view_ortho(v2d);
1111
1112   /* time grid */
1113   UI_view2d_draw_lines_x__discrete_frames_or_seconds(v2d, scene, sc->flag & SC_SHOW_SECONDS);
1114
1115   /* data... */
1116   clip_draw_dopesheet_main(sc, ar, scene);
1117
1118   /* current frame indicator line */
1119   if (sc->flag & SC_SHOW_SECONDS) {
1120     cfra_flag |= DRAWCFRA_UNIT_SECONDS;
1121   }
1122   ANIM_draw_cfra(C, v2d, cfra_flag);
1123
1124   /* reset view matrix */
1125   UI_view2d_view_restore(C);
1126
1127   /* time-scrubbing */
1128   ED_time_scrub_draw(ar, scene, sc->flag & SC_SHOW_SECONDS, true);
1129
1130   /* scrollers */
1131   scrollers = UI_view2d_scrollers_calc(v2d, NULL);
1132   UI_view2d_scrollers_draw(v2d, scrollers);
1133   UI_view2d_scrollers_free(scrollers);
1134 }
1135
1136 static void clip_preview_region_draw(const bContext *C, ARegion *ar)
1137 {
1138   SpaceClip *sc = CTX_wm_space_clip(C);
1139
1140   if (sc->view == SC_VIEW_GRAPH) {
1141     graph_region_draw(C, ar);
1142   }
1143   else if (sc->view == SC_VIEW_DOPESHEET) {
1144     dopesheet_region_draw(C, ar);
1145   }
1146 }
1147
1148 static void clip_preview_region_listener(wmWindow *UNUSED(win),
1149                                          ScrArea *UNUSED(sa),
1150                                          ARegion *UNUSED(ar),
1151                                          wmNotifier *UNUSED(wmn),
1152                                          const Scene *UNUSED(scene))
1153 {
1154 }
1155
1156 /****************** channels region ******************/
1157
1158 static void clip_channels_region_init(wmWindowManager *wm, ARegion *ar)
1159 {
1160   wmKeyMap *keymap;
1161
1162   /* ensure the 2d view sync works - main region has bottom scroller */
1163   ar->v2d.scroll = V2D_SCROLL_BOTTOM;
1164
1165   UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy);
1166
1167   keymap = WM_keymap_ensure(wm->defaultconf, "Clip Dopesheet Editor", SPACE_CLIP, 0);
1168   WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap);
1169 }
1170
1171 static void clip_channels_region_draw(const bContext *C, ARegion *ar)
1172 {
1173   SpaceClip *sc = CTX_wm_space_clip(C);
1174   MovieClip *clip = ED_space_clip_get_clip(sc);
1175   View2D *v2d = &ar->v2d;
1176
1177   if (clip) {
1178     BKE_tracking_dopesheet_update(&clip->tracking);
1179   }
1180
1181   /* clear and setup matrix */
1182   UI_ThemeClearColor(TH_BACK);
1183   GPU_clear(GPU_COLOR_BIT);
1184
1185   UI_view2d_view_ortho(v2d);
1186
1187   /* data... */
1188   clip_draw_dopesheet_channels(C, ar);
1189
1190   /* reset view matrix */
1191   UI_view2d_view_restore(C);
1192 }
1193
1194 static void clip_channels_region_listener(wmWindow *UNUSED(win),
1195                                           ScrArea *UNUSED(sa),
1196                                           ARegion *UNUSED(ar),
1197                                           wmNotifier *UNUSED(wmn),
1198                                           const Scene *UNUSED(scene))
1199 {
1200 }
1201
1202 /****************** header region ******************/
1203
1204 /* add handlers, stuff you only do once or on area/region changes */
1205 static void clip_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
1206 {
1207   ED_region_header_init(ar);
1208 }
1209
1210 static void clip_header_region_draw(const bContext *C, ARegion *ar)
1211 {
1212   ED_region_header(C, ar);
1213 }
1214
1215 static void clip_header_region_listener(wmWindow *UNUSED(win),
1216                                         ScrArea *UNUSED(sa),
1217                                         ARegion *ar,
1218                                         wmNotifier *wmn,
1219                                         const Scene *UNUSED(scene))
1220 {
1221   /* context changes */
1222   switch (wmn->category) {
1223     case NC_SCENE:
1224       switch (wmn->data) {
1225         /* for proportional editmode only */
1226         case ND_TOOLSETTINGS:
1227           /* TODO - should do this when in mask mode only but no datas available */
1228           // if (sc->mode == SC_MODE_MASKEDIT)
1229           {
1230             ED_region_tag_redraw(ar);
1231             break;
1232           }
1233       }
1234       break;
1235   }
1236 }
1237
1238 /****************** tools region ******************/
1239
1240 /* add handlers, stuff you only do once or on area/region changes */
1241 static void clip_tools_region_init(wmWindowManager *wm, ARegion *ar)
1242 {
1243   wmKeyMap *keymap;
1244
1245   ED_region_panels_init(wm, ar);
1246
1247   keymap = WM_keymap_ensure(wm->defaultconf, "Clip", SPACE_CLIP, 0);
1248   WM_event_add_keymap_handler(&ar->handlers, keymap);
1249 }
1250
1251 static void clip_tools_region_draw(const bContext *C, ARegion *ar)
1252 {
1253   ED_region_panels(C, ar);
1254 }
1255
1256 /****************** tool properties region ******************/
1257
1258 static void clip_props_region_listener(wmWindow *UNUSED(win),
1259                                        ScrArea *UNUSED(sa),
1260                                        ARegion *ar,
1261                                        wmNotifier *wmn,
1262                                        const Scene *UNUSED(scene))
1263 {
1264   /* context changes */
1265   switch (wmn->category) {
1266     case NC_WM:
1267       if (wmn->data == ND_HISTORY) {
1268         ED_region_tag_redraw(ar);
1269       }
1270       break;
1271     case NC_SCENE:
1272       if (wmn->data == ND_MODE) {
1273         ED_region_tag_redraw(ar);
1274       }
1275       break;
1276     case NC_SPACE:
1277       if (wmn->data == ND_SPACE_CLIP) {
1278         ED_region_tag_redraw(ar);
1279       }
1280       break;
1281     case NC_GPENCIL:
1282       if (wmn->action == NA_EDITED) {
1283         ED_region_tag_redraw(ar);
1284       }
1285       break;
1286   }
1287 }
1288
1289 /****************** properties region ******************/
1290
1291 /* add handlers, stuff you only do once or on area/region changes */
1292 static void clip_properties_region_init(wmWindowManager *wm, ARegion *ar)
1293 {
1294   wmKeyMap *keymap;
1295
1296   ED_region_panels_init(wm, ar);
1297
1298   keymap = WM_keymap_ensure(wm->defaultconf, "Clip", SPACE_CLIP, 0);
1299   WM_event_add_keymap_handler(&ar->handlers, keymap);
1300 }
1301
1302 static void clip_properties_region_draw(const bContext *C, ARegion *ar)
1303 {
1304   SpaceClip *sc = CTX_wm_space_clip(C);
1305
1306   BKE_movieclip_update_scopes(sc->clip, &sc->user, &sc->scopes);
1307
1308   ED_region_panels(C, ar);
1309 }
1310
1311 static void clip_properties_region_listener(wmWindow *UNUSED(win),
1312                                             ScrArea *UNUSED(sa),
1313                                             ARegion *ar,
1314                                             wmNotifier *wmn,
1315                                             const Scene *UNUSED(scene))
1316 {
1317   /* context changes */
1318   switch (wmn->category) {
1319     case NC_GPENCIL:
1320       if (ELEM(wmn->data, ND_DATA, ND_GPENCIL_EDITMODE)) {
1321         ED_region_tag_redraw(ar);
1322       }
1323       break;
1324     case NC_BRUSH:
1325       if (wmn->action == NA_EDITED) {
1326         ED_region_tag_redraw(ar);
1327       }
1328       break;
1329   }
1330 }
1331
1332 /********************* registration ********************/
1333
1334 static void clip_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
1335 {
1336   SpaceClip *sclip = (SpaceClip *)slink;
1337
1338   if (!ELEM(GS(old_id->name), ID_MC, ID_MSK)) {
1339     return;
1340   }
1341
1342   if ((ID *)sclip->clip == old_id) {
1343     sclip->clip = (MovieClip *)new_id;
1344     id_us_ensure_real(new_id);
1345   }
1346
1347   if ((ID *)sclip->mask_info.mask == old_id) {
1348     sclip->mask_info.mask = (Mask *)new_id;
1349     id_us_ensure_real(new_id);
1350   }
1351 }
1352
1353 /* only called once, from space/spacetypes.c */
1354 void ED_spacetype_clip(void)
1355 {
1356   SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype clip");
1357   ARegionType *art;
1358
1359   st->spaceid = SPACE_CLIP;
1360   strncpy(st->name, "Clip", BKE_ST_MAXNAME);
1361
1362   st->new = clip_new;
1363   st->free = clip_free;
1364   st->init = clip_init;
1365   st->duplicate = clip_duplicate;
1366   st->operatortypes = clip_operatortypes;
1367   st->keymap = clip_keymap;
1368   st->listener = clip_listener;
1369   st->context = clip_context;
1370   st->gizmos = clip_gizmos;
1371   st->dropboxes = clip_dropboxes;
1372   st->refresh = clip_refresh;
1373   st->id_remap = clip_id_remap;
1374
1375   /* regions: main window */
1376   art = MEM_callocN(sizeof(ARegionType), "spacetype clip region");
1377   art->regionid = RGN_TYPE_WINDOW;
1378   art->init = clip_main_region_init;
1379   art->draw = clip_main_region_draw;
1380   art->listener = clip_main_region_listener;
1381   art->keymapflag = ED_KEYMAP_GIZMO | ED_KEYMAP_FRAMES | ED_KEYMAP_UI | ED_KEYMAP_GPENCIL;
1382
1383   BLI_addhead(&st->regiontypes, art);
1384
1385   /* preview */
1386   art = MEM_callocN(sizeof(ARegionType), "spacetype clip region preview");
1387   art->regionid = RGN_TYPE_PREVIEW;
1388   art->prefsizey = 240;
1389   art->init = clip_preview_region_init;
1390   art->draw = clip_preview_region_draw;
1391   art->listener = clip_preview_region_listener;
1392   art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
1393
1394   BLI_addhead(&st->regiontypes, art);
1395
1396   /* regions: properties */
1397   art = MEM_callocN(sizeof(ARegionType), "spacetype clip region properties");
1398   art->regionid = RGN_TYPE_UI;
1399   art->prefsizex = UI_SIDEBAR_PANEL_WIDTH;
1400   art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI;
1401   art->init = clip_properties_region_init;
1402   art->draw = clip_properties_region_draw;
1403   art->listener = clip_properties_region_listener;
1404   BLI_addhead(&st->regiontypes, art);
1405   ED_clip_buttons_register(art);
1406
1407   /* regions: tools */
1408   art = MEM_callocN(sizeof(ARegionType), "spacetype clip region tools");
1409   art->regionid = RGN_TYPE_TOOLS;
1410   art->prefsizex = UI_SIDEBAR_PANEL_WIDTH;
1411   art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI;
1412   art->listener = clip_props_region_listener;
1413   art->init = clip_tools_region_init;
1414   art->draw = clip_tools_region_draw;
1415
1416   BLI_addhead(&st->regiontypes, art);
1417
1418   /* regions: header */
1419   art = MEM_callocN(sizeof(ARegionType), "spacetype clip region");
1420   art->regionid = RGN_TYPE_HEADER;
1421   art->prefsizey = HEADERY;
1422   art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
1423
1424   art->init = clip_header_region_init;
1425   art->draw = clip_header_region_draw;
1426   art->listener = clip_header_region_listener;
1427
1428   BLI_addhead(&st->regiontypes, art);
1429
1430   BKE_spacetype_register(st);
1431
1432   /* channels */
1433   art = MEM_callocN(sizeof(ARegionType), "spacetype clip channels region");
1434   art->regionid = RGN_TYPE_CHANNELS;
1435   art->prefsizex = UI_COMPACT_PANEL_WIDTH;
1436   art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI;
1437   art->listener = clip_channels_region_listener;
1438   art->init = clip_channels_region_init;
1439   art->draw = clip_channels_region_draw;
1440
1441   BLI_addhead(&st->regiontypes, art);
1442
1443   /* regions: hud */
1444   art = ED_area_type_hud(st->spaceid);
1445   BLI_addhead(&st->regiontypes, art);
1446 }