added mask tool to recalculate handles (Ctrl+N)
[blender.git] / release / scripts / startup / bl_ui / space_clip.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8-80 compliant>
20
21 import bpy
22 from bpy.types import Panel, Header, Menu
23
24
25 class CLIP_HT_header(Header):
26     bl_space_type = 'CLIP_EDITOR'
27
28     def _draw_tracking(self, context):
29         layout = self.layout
30
31         sc = context.space_data
32         clip = sc.clip
33
34         row = layout.row(align=True)
35         row.template_header()
36
37         if context.area.show_menus:
38             sub = row.row(align=True)
39             sub.menu("CLIP_MT_view")
40
41             if sc.view == 'CLIP':
42                 if clip:
43                     sub.menu("CLIP_MT_select")
44                     sub.menu("CLIP_MT_clip")
45                     sub.menu("CLIP_MT_track")
46                     sub.menu("CLIP_MT_reconstruction")
47                 else:
48                     sub.menu("CLIP_MT_clip")
49
50         row = layout.row()
51         row.template_ID(sc, "clip", open='clip.open')
52
53         if clip:
54             tracking = clip.tracking
55             active_object = tracking.objects.active
56
57             if sc.view == 'CLIP':
58                 layout.prop(sc, "mode", text="")
59                 layout.prop(sc, "view", text="", expand=True)
60                 layout.prop(sc, "pivot_point", text="", icon_only=True)
61
62                 r = active_object.reconstruction
63
64                 if r.is_valid and sc.view == 'CLIP':
65                     layout.label(text="Solve error: %.4f" %
66                                  (r.average_error))
67             elif sc.view == 'GRAPH':
68                 layout.prop(sc, "view", text="", expand=True)
69
70                 row = layout.row(align=True)
71                 row.prop(sc, "show_graph_only_selected", text="")
72                 row.prop(sc, "show_graph_hidden", text="")
73
74                 row = layout.row(align=True)
75
76                 if sc.show_filters:
77                     row.prop(sc, "show_filters", icon='DISCLOSURE_TRI_DOWN',
78                              text="Filters")
79
80                     sub = row.column()
81                     sub.active = clip.tracking.reconstruction.is_valid
82                     sub.prop(sc, "show_graph_frames", icon='SEQUENCE', text="")
83
84                     row.prop(sc, "show_graph_tracks", icon='ANIM', text="")
85                 else:
86                     row.prop(sc, "show_filters", icon='DISCLOSURE_TRI_RIGHT',
87                              text="Filters")
88             elif sc.view == 'DOPESHEET':
89                 dopesheet = tracking.dopesheet
90                 layout.prop(sc, "view", text="", expand=True)
91
92                 row = layout.row(align=True)
93                 row.prop(dopesheet, "show_only_selected", text="")
94                 row.prop(dopesheet, "show_hidden", text="")
95
96                 row = layout.row(align=True)
97                 row.prop(dopesheet, "sort_method", text="")
98                 row.prop(dopesheet, "use_invert_sort", text="Invert", toggle=True)
99         else:
100             layout.prop(sc, "view", text="", expand=True)
101
102     def _draw_masking(self, context):
103         layout = self.layout
104
105         toolsettings = context.tool_settings
106         sc = context.space_data
107         clip = sc.clip
108
109         row = layout.row(align=True)
110         row.template_header()
111
112         if context.area.show_menus:
113             sub = row.row(align=True)
114             sub.menu("CLIP_MT_view")
115
116             if clip:
117                 sub.menu("CLIP_MT_select")
118                 sub.menu("CLIP_MT_clip")
119                 sub.menu("CLIP_MT_mask")
120             else:
121                 sub.menu("CLIP_MT_clip")
122
123         row = layout.row()
124         row.template_ID(sc, "clip", open='clip.open')
125
126         layout.prop(sc, "mode", text="")
127
128         row = layout.row()
129         row.template_ID(sc, "mask", new="mask.new")
130
131         layout.prop(sc, "pivot_point", text="", icon_only=True)
132
133         row = layout.row(align=True)
134         row.prop(toolsettings, "use_proportional_edit_mask",
135                  text="", icon_only=True)
136         if toolsettings.use_proportional_edit_mask:
137             row.prop(toolsettings, "proportional_edit_falloff",
138                      text="", icon_only=True)
139
140     def draw(self, context):
141         layout = self.layout
142
143         sc = context.space_data
144
145         if sc.mode in {'TRACKING', 'RECONSTRUCTION', 'DISTORTION'}:
146             self._draw_tracking(context)
147         else:
148             self._draw_masking(context)
149
150         layout.template_running_jobs()
151
152
153 class CLIP_PT_clip_view_panel:
154
155     @classmethod
156     def poll(cls, context):
157         sc = context.space_data
158         clip = sc.clip
159
160         return clip and sc.view == 'CLIP'
161
162
163 class CLIP_PT_mask_view_panel:
164
165     @classmethod
166     def poll(cls, context):
167         sc = context.space_data
168         clip = sc.clip
169
170         return clip and sc.view == 'CLIP' and sc.mode == 'MASKEDIT'
171
172
173 class CLIP_PT_tracking_panel:
174
175     @classmethod
176     def poll(cls, context):
177         sc = context.space_data
178         clip = sc.clip
179
180         return clip and sc.mode == 'TRACKING' and sc.view == 'CLIP'
181
182
183 class CLIP_PT_reconstruction_panel:
184
185     @classmethod
186     def poll(cls, context):
187         sc = context.space_data
188         clip = sc.clip
189
190         return clip and sc.mode == 'RECONSTRUCTION' and sc.view == 'CLIP'
191
192
193 class CLIP_PT_tools_marker(CLIP_PT_tracking_panel, Panel):
194     bl_space_type = 'CLIP_EDITOR'
195     bl_region_type = 'TOOLS'
196     bl_label = "Marker"
197
198     def draw(self, context):
199         sc = context.space_data
200         clip = sc.clip
201         settings = clip.tracking.settings
202         layout = self.layout
203
204         col = layout.column(align=True)
205         col.operator("clip.add_marker_move")
206         col.operator("clip.detect_features")
207         col.operator("clip.delete_track")
208
209         box = layout.box()
210         row = box.row(align=True)
211         row.prop(settings, "show_default_expanded", text="", emboss=False)
212         row.label(text="Tracking Settings")
213
214         if settings.show_default_expanded:
215             col = box.column()
216             row = col.row(align=True)
217             label = CLIP_MT_tracking_settings_presets.bl_label
218             row.menu('CLIP_MT_tracking_settings_presets', text=label)
219             row.operator("clip.tracking_settings_preset_add",
220                          text="", icon='ZOOMIN')
221             props = row.operator("clip.tracking_settings_preset_add",
222                                  text="", icon='ZOOMOUT')
223             props.remove_active = True
224
225             col.separator()
226
227             row = col.row(align=True)
228             row.prop(settings, "use_default_red_channel",
229                      text="R", toggle=True)
230             row.prop(settings, "use_default_green_channel",
231                      text="G", toggle=True)
232             row.prop(settings, "use_default_blue_channel",
233                      text="B", toggle=True)
234
235             col.separator()
236
237             sub = col.column(align=True)
238             sub.prop(settings, "default_pattern_size")
239             sub.prop(settings, "default_search_size")
240
241             col.label(text="Tracker:")
242             col.prop(settings, "default_motion_model")
243             col.prop(settings, "default_use_brute")
244             col.prop(settings, "default_use_normalization")
245             col.prop(settings, "default_use_mask")
246             col.prop(settings, "default_correlation_min")
247
248             col.separator()
249
250             sub = col.column(align=True)
251             sub.prop(settings, "default_frames_limit")
252             sub.prop(settings, "default_margin")
253
254             col.label(text="Match:")
255             col.prop(settings, "default_pattern_match", text="")
256
257             col.separator()
258             col.operator('clip.track_settings_as_default',
259                          text="Copy From Active Track")
260
261
262 class CLIP_PT_tools_tracking(CLIP_PT_tracking_panel, Panel):
263     bl_space_type = 'CLIP_EDITOR'
264     bl_region_type = 'TOOLS'
265     bl_label = "Track"
266
267     def draw(self, context):
268         layout = self.layout
269
270         row = layout.row(align=True)
271
272         props = row.operator("clip.track_markers", text="", icon='FRAME_PREV')
273         props.backwards = True
274         props.sequence = False
275         props = row.operator("clip.track_markers", text="",
276                              icon='PLAY_REVERSE')
277         props.backwards = True
278         props.sequence = True
279         props = row.operator("clip.track_markers", text="", icon='PLAY')
280         props.backwards = False
281         props.sequence = True
282         props = row.operator("clip.track_markers", text="", icon='FRAME_NEXT')
283         props.backwards = False
284         props.sequence = False
285
286         col = layout.column(align=True)
287         props = col.operator("clip.clear_track_path", text="Clear After")
288         props.action = 'REMAINED'
289
290         props = col.operator("clip.clear_track_path", text="Clear Before")
291         props.action = 'UPTO'
292         col.operator("clip.clear_track_path", text="Clear").action = 'ALL'
293
294         layout.operator("clip.join_tracks", text="Join")
295
296
297 class CLIP_PT_tools_solve(CLIP_PT_tracking_panel, Panel):
298     bl_space_type = 'CLIP_EDITOR'
299     bl_region_type = 'TOOLS'
300     bl_label = "Solve"
301
302     def draw(self, context):
303         layout = self.layout
304         clip = context.space_data.clip
305         tracking = clip.tracking
306         settings = tracking.settings
307         tracking_object = tracking.objects.active
308
309         col = layout.column(align=True)
310
311         col.operator("clip.solve_camera",
312                      text="Camera Motion" if tracking_object.is_camera
313                      else "Object Motion")
314         col.operator("clip.clear_solution")
315
316         col = layout.column()
317         col.prop(settings, "use_tripod_solver")
318
319         col = layout.column(align=True)
320         col.active = not settings.use_tripod_solver
321         col.prop(settings, "keyframe_a")
322         col.prop(settings, "keyframe_b")
323
324         col = layout.column(align=True)
325         col.active = (tracking_object.is_camera and
326                       not settings.use_tripod_solver)
327         col.label(text="Refine:")
328         col.prop(settings, "refine_intrinsics", text="")
329
330
331 class CLIP_PT_tools_cleanup(CLIP_PT_tracking_panel, Panel):
332     bl_space_type = 'CLIP_EDITOR'
333     bl_region_type = 'TOOLS'
334     bl_label = "Clean up"
335
336     def draw(self, context):
337         layout = self.layout
338         clip = context.space_data.clip
339         settings = clip.tracking.settings
340
341         layout.operator("clip.clean_tracks")
342
343         layout.prop(settings, 'clean_frames', text="Frames")
344         layout.prop(settings, 'clean_error', text="Error")
345         layout.prop(settings, 'clean_action', text="")
346
347
348 class CLIP_PT_tools_geometry(CLIP_PT_reconstruction_panel, Panel):
349     bl_space_type = 'CLIP_EDITOR'
350     bl_region_type = 'TOOLS'
351     bl_label = "Geometry"
352
353     def draw(self, context):
354         layout = self.layout
355
356         layout.operator("clip.bundles_to_mesh")
357         layout.operator("clip.track_to_empty")
358
359
360 class CLIP_PT_tools_orientation(CLIP_PT_reconstruction_panel, Panel):
361     bl_space_type = 'CLIP_EDITOR'
362     bl_region_type = 'TOOLS'
363     bl_label = "Orientation"
364
365     def draw(self, context):
366         sc = context.space_data
367         layout = self.layout
368         settings = sc.clip.tracking.settings
369
370         col = layout.column(align=True)
371         row = col.row()
372         props = row.operator("clip.set_plane", text="Floor")
373         props.plane = 'FLOOR'
374         props = row.operator("clip.set_plane", text="Wall")
375         props.plane = 'WALL'
376         col.operator("clip.set_origin")
377
378         row = col.row()
379         row.operator("clip.set_axis", text="Set X Axis").axis = 'X'
380         row.operator("clip.set_axis", text="Set Y Axis").axis = 'Y'
381
382         layout.separator()
383
384         col = layout.column()
385         col.operator("clip.set_scale")
386         col.prop(settings, "distance")
387
388
389 class CLIP_PT_tools_object(CLIP_PT_reconstruction_panel, Panel):
390     bl_space_type = 'CLIP_EDITOR'
391     bl_region_type = 'TOOLS'
392     bl_label = "Object"
393
394     @classmethod
395     def poll(cls, context):
396         if CLIP_PT_reconstruction_panel.poll(context):
397             sc = context.space_data
398             clip = sc.clip
399
400             tracking_object = clip.tracking.objects.active
401
402             return not tracking_object.is_camera
403
404         return False
405
406     def draw(self, context):
407         layout = self.layout
408
409         sc = context.space_data
410         clip = sc.clip
411         tracking_object = clip.tracking.objects.active
412         settings = sc.clip.tracking.settings
413
414         col = layout.column()
415
416         col.prop(tracking_object, "scale")
417
418         col.separator()
419
420         col.operator("clip.set_solution_scale", text="Set Scale")
421         col.prop(settings, "object_distance")
422
423
424 class CLIP_PT_tools_mask(CLIP_PT_mask_view_panel, Panel):
425     bl_space_type = 'CLIP_EDITOR'
426     bl_region_type = 'TOOLS'
427     bl_label = "Mask Tools"
428
429     def draw(self, context):
430         layout = self.layout
431
432         col = layout.column(align=True)
433         col.label(text="Transform:")
434         col.operator("transform.translate")
435         col.operator("transform.rotate")
436         col.operator("transform.resize", text="Scale")
437         props = col.operator("transform.transform", text="Shrink/Fatten")
438         props.mode = 'MASK_SHRINKFATTEN'
439
440         col = layout.column(align=True)
441         col.label(text="Spline:")
442         col.operator("mask.delete")
443         col.operator("mask.cyclic_toggle")
444         col.operator("mask.switch_direction")
445
446         col = layout.column(align=True)
447         col.label(text="Parenting:")
448         col.operator("mask.parent_set")
449         col.operator("mask.parent_clear")
450
451
452 class CLIP_PT_tools_grease_pencil(Panel):
453     bl_space_type = 'CLIP_EDITOR'
454     bl_region_type = 'TOOLS'
455     bl_label = "Grease Pencil"
456
457     @classmethod
458     def poll(cls, context):
459         sc = context.space_data
460         clip = sc.clip
461
462         if not clip:
463             return False
464
465         if sc.mode == 'DISTORTION':
466             return sc.view == 'CLIP'
467         elif sc.mode == 'MASKEDIT':
468             return True
469
470         return False
471
472     def draw(self, context):
473         layout = self.layout
474
475         col = layout.column(align=True)
476
477         row = col.row(align=True)
478         row.operator("gpencil.draw", text="Draw").mode = 'DRAW'
479         row.operator("gpencil.draw", text="Line").mode = 'DRAW_STRAIGHT'
480
481         row = col.row(align=True)
482         row.operator("gpencil.draw", text="Poly").mode = 'DRAW_POLY'
483         row.operator("gpencil.draw", text="Erase").mode = 'ERASER'
484
485         row = col.row()
486         row.prop(context.tool_settings, "use_grease_pencil_sessions")
487
488
489 class CLIP_PT_objects(CLIP_PT_clip_view_panel, Panel):
490     bl_space_type = 'CLIP_EDITOR'
491     bl_region_type = 'UI'
492     bl_label = "Objects"
493     bl_options = {'DEFAULT_CLOSED'}
494
495     def draw(self, context):
496         layout = self.layout
497
498         sc = context.space_data
499         tracking = sc.clip.tracking
500
501         row = layout.row()
502         row.template_list(tracking, "objects",
503                           tracking, "active_object_index", rows=3)
504
505         sub = row.column(align=True)
506
507         sub.operator("clip.tracking_object_new", icon='ZOOMIN', text="")
508         sub.operator("clip.tracking_object_remove", icon='ZOOMOUT', text="")
509
510         active = tracking.objects.active
511         if active:
512             layout.prop(active, "name")
513
514
515 class CLIP_PT_track(CLIP_PT_tracking_panel, Panel):
516     bl_space_type = 'CLIP_EDITOR'
517     bl_region_type = 'UI'
518     bl_label = "Track"
519
520     def draw(self, context):
521         layout = self.layout
522         sc = context.space_data
523         clip = context.space_data.clip
524         act_track = clip.tracking.tracks.active
525
526         if not act_track:
527             layout.active = False
528             layout.label(text="No active track")
529             return
530
531         row = layout.row()
532         row.prop(act_track, "name", text="")
533
534         sub = row.row(align=True)
535
536         sub.template_marker(sc, "clip", sc.clip_user, act_track, True)
537
538         icon = 'LOCKED' if act_track.lock else 'UNLOCKED'
539         sub.prop(act_track, "lock", text="", icon=icon)
540
541         layout.template_track(sc, "scopes")
542
543         row = layout.row(align=True)
544         sub = row.row()
545         sub.prop(act_track, "use_red_channel", text="R", toggle=True)
546         sub.prop(act_track, "use_green_channel", text="G", toggle=True)
547         sub.prop(act_track, "use_blue_channel", text="B", toggle=True)
548
549         row.separator()
550
551         sub = row.row()
552         sub.prop(act_track, "use_grayscale_preview", text="B/W", toggle=True)
553
554         row.separator()
555         sub = row.row()
556         sub.prop(act_track, "use_alpha_preview", text="", toggle=True, icon='IMAGE_ALPHA')
557
558         layout.separator()
559
560         row = layout.row(align=True)
561         label = bpy.types.CLIP_MT_track_color_presets.bl_label
562         row.menu('CLIP_MT_track_color_presets', text=label)
563         row.menu('CLIP_MT_track_color_specials', text="", icon='DOWNARROW_HLT')
564         row.operator("clip.track_color_preset_add", text="", icon='ZOOMIN')
565         props = row.operator("clip.track_color_preset_add",
566                              text="", icon='ZOOMOUT')
567         props.remove_active = True
568
569         row = layout.row()
570         row.prop(act_track, "use_custom_color")
571         if act_track.use_custom_color:
572             row.prop(act_track, "color", text="")
573
574         if act_track.has_bundle:
575             label_text = "Average Error: %.4f" % (act_track.average_error)
576             layout.label(text=label_text)
577
578
579 class CLIP_PT_track_settings(CLIP_PT_tracking_panel, Panel):
580     bl_space_type = 'CLIP_EDITOR'
581     bl_region_type = 'UI'
582     bl_label = "Tracking Settings"
583     bl_options = {'DEFAULT_CLOSED'}
584
585     def draw(self, context):
586         layout = self.layout
587         clip = context.space_data.clip
588         settings = clip.tracking.settings
589
590         col = layout.column()
591
592         active = clip.tracking.tracks.active
593         if active:
594             col.prop(active, "motion_model")
595             col.prop(active, "use_brute")
596             col.prop(active, "use_normalization")
597             col.prop(active, "use_mask")
598             col.prop(active, "correlation_min")
599
600             col.separator()
601             col.prop(active, "frames_limit")
602             col.prop(active, "margin")
603             col.prop(active, "pattern_match", text="Match")
604
605         col.prop(settings, "speed")
606
607
608 class CLIP_PT_tracking_camera(Panel):
609     bl_space_type = 'CLIP_EDITOR'
610     bl_region_type = 'UI'
611     bl_label = "Camera Data"
612     bl_options = {'DEFAULT_CLOSED'}
613
614     @classmethod
615     def poll(cls, context):
616         if CLIP_PT_clip_view_panel.poll(context):
617             sc = context.space_data
618
619             return sc.mode in {'TRACKING', 'DISTORTION'} and sc.clip
620
621         return False
622
623     def draw(self, context):
624         layout = self.layout
625
626         sc = context.space_data
627         clip = sc.clip
628
629         row = layout.row(align=True)
630         label = bpy.types.CLIP_MT_camera_presets.bl_label
631         row.menu('CLIP_MT_camera_presets', text=label)
632         row.operator("clip.camera_preset_add", text="", icon='ZOOMIN')
633         props = row.operator("clip.camera_preset_add", text="", icon='ZOOMOUT')
634         props.remove_active = True
635
636         row = layout.row(align=True)
637         sub = row.split(percentage=0.65)
638         if clip.tracking.camera.units == 'MILLIMETERS':
639             sub.prop(clip.tracking.camera, "focal_length")
640         else:
641             sub.prop(clip.tracking.camera, "focal_length_pixels")
642         sub.prop(clip.tracking.camera, "units", text="")
643
644         col = layout.column(align=True)
645         col.label(text="Sensor:")
646         col.prop(clip.tracking.camera, "sensor_width", text="Width")
647         col.prop(clip.tracking.camera, "pixel_aspect")
648
649         col = layout.column()
650         col.label(text="Optical Center:")
651         row = col.row()
652         row.prop(clip.tracking.camera, "principal", text="")
653         col.operator("clip.set_center_principal", text="Center")
654
655         col = layout.column(align=True)
656         col.label(text="Lens Distortion:")
657         col.prop(clip.tracking.camera, "k1")
658         col.prop(clip.tracking.camera, "k2")
659         col.prop(clip.tracking.camera, "k3")
660
661
662 class CLIP_PT_mask_layers(Panel):
663     bl_space_type = 'CLIP_EDITOR'
664     bl_region_type = 'UI'
665     bl_label = "Mask Layers"
666
667     @classmethod
668     def poll(cls, context):
669         sc = context.space_data
670
671         return sc.mask and sc.mode == 'MASKEDIT'
672
673     def draw(self, context):
674         layout = self.layout
675
676         sc = context.space_data
677         mask = sc.mask
678
679         row = layout.row()
680         row.template_list(mask, "layers",
681                           mask, "active_layer_index", rows=3)
682
683         sub = row.column(align=True)
684
685         sub.operator("mask.layer_new", icon='ZOOMIN', text="")
686         sub.operator("mask.layer_remove", icon='ZOOMOUT', text="")
687
688         active = mask.layers.active
689         if active:
690             layout.prop(active, "name")
691
692             # blending
693             row = layout.row(align=True)
694             row.prop(active, "alpha")
695             row.prop(active, "invert", text="", icon='IMAGE_ALPHA')
696
697             layout.prop(active, "blend")
698
699
700 class CLIP_PT_active_mask_spline(Panel):
701     bl_space_type = 'CLIP_EDITOR'
702     bl_region_type = 'UI'
703     bl_label = "Active Spline"
704
705     @classmethod
706     def poll(cls, context):
707         sc = context.space_data
708         mask = sc.mask
709
710         if mask and sc.mode == 'MASKEDIT':
711             return mask.layers.active and mask.layers.active.splines.active
712
713         return False
714
715     def draw(self, context):
716         layout = self.layout
717
718         sc = context.space_data
719         mask = sc.mask
720         spline = mask.layers.active.splines.active
721
722         col = layout.column()
723         col.prop(spline, "weight_interpolation")
724         col.prop(spline, "use_cyclic")
725
726
727 class CLIP_PT_active_mask_point(Panel):
728     bl_space_type = 'CLIP_EDITOR'
729     bl_region_type = 'UI'
730     bl_label = "Active Point"
731
732     @classmethod
733     def poll(cls, context):
734         sc = context.space_data
735         mask = sc.mask
736
737         if mask and sc.mode == 'MASKEDIT':
738             return mask.layers.active and mask.layers.active.splines.active_point
739
740         return False
741
742     def draw(self, context):
743         layout = self.layout
744
745         sc = context.space_data
746         mask = sc.mask
747         point = mask.layers.active.splines.active_point
748         parent = point.parent
749
750         col = layout.column()
751         col.prop(point, "handle_type")
752
753         col = layout.column()
754         # Currently only parenting yo movie clip is allowed, so do not
755         # ver-oplicate things for now and use single template_ID
756         #col.template_any_ID(parent, "id", "id_type", text="")
757
758         col.label("Parent:")
759         col.prop(parent, "id", text="")
760
761         if parent.id_type == 'MOVIECLIP' and parent.id:
762             clip = parent.id
763             tracking = clip.tracking
764
765             col.prop_search(parent, "parent", tracking,
766                             "objects", icon='OBJECT_DATA', text="Object:")
767
768             if parent.parent in tracking.objects:
769                 object = tracking.objects[parent.parent]
770                 col.prop_search(parent, "sub_parent", object,
771                                 "tracks", icon='ANIM_DATA', text="Track:")
772             else:
773                 col.prop_search(parent, "sub_parent", tracking,
774                                 "tracks", icon='ANIM_DATA', text="Track:")
775
776
777 class CLIP_PT_display(CLIP_PT_clip_view_panel, Panel):
778     bl_space_type = 'CLIP_EDITOR'
779     bl_region_type = 'UI'
780     bl_label = "Display"
781
782     def draw(self, context):
783         layout = self.layout
784         sc = context.space_data
785
786         row = layout.row(align=True)
787         sub = row.row()
788         sub.prop(sc, "show_red_channel", text="R", toggle=True)
789         sub.prop(sc, "show_green_channel", text="G", toggle=True)
790         sub.prop(sc, "show_blue_channel", text="B", toggle=True)
791
792         row.separator()
793
794         sub = row.row()
795         sub.prop(sc, "use_grayscale_preview", text="B/W", toggle=True)
796
797         col = layout.column(align=True)
798
799         col.prop(sc, "show_disabled", "Disabled Tracks")
800         col.prop(sc, "show_names", text="Names and Status")
801         col.prop(sc, "show_bundles", text="3D Markers")
802
803         col.prop(sc, "use_mute_footage", text="Mute Footage")
804         col.prop(sc, "lock_selection")
805
806         if sc.view == 'GRAPH':
807             col.prop(sc, "lock_time_cursor")
808
809         if sc.mode == 'DISTORTION':
810             col.prop(sc, "show_grid", text="Grid")
811             col.prop(sc, "use_manual_calibration")
812         elif sc.mode == 'RECONSTRUCTION':
813             col.prop(sc, "show_stable", text="Stable")
814
815         clip = sc.clip
816         if clip:
817             col.label(text="Display Aspect Ratio:")
818             row = col.row()
819             row.prop(clip, "display_aspect", text="")
820
821         if sc.mode == 'MASKEDIT':
822             col = layout.column()
823             col.prop(sc, "mask_draw_type", text="")
824             col.prop(sc, "show_mask_smooth")
825
826
827 # TODO, move into its own file
828 class CLIP_PT_mask(CLIP_PT_mask_view_panel, Panel):
829     bl_space_type = 'CLIP_EDITOR'
830     bl_region_type = 'UI'
831     bl_label = "Mask Settings"
832     bl_options = {'DEFAULT_CLOSED'}
833
834     def draw(self, context):
835         layout = self.layout
836
837         sc = context.space_data
838         mask = sc.mask
839
840         col = layout.column(align=True)
841         col.prop(mask, "frame_start")
842         col.prop(mask, "frame_end")
843
844
845 class CLIP_PT_marker_display(CLIP_PT_clip_view_panel, Panel):
846     bl_space_type = 'CLIP_EDITOR'
847     bl_region_type = 'UI'
848     bl_label = "Marker Display"
849
850     @classmethod
851     def poll(cls, context):
852         sc = context.space_data
853
854         return sc.mode != 'MASKEDIT'
855
856     def draw(self, context):
857         layout = self.layout
858         sc = context.space_data
859
860         col = layout.column(align=True)
861
862         row = col.row()
863         row.prop(sc, "show_marker_pattern", text="Pattern")
864         row.prop(sc, "show_marker_search", text="Search")
865
866         col.prop(sc, "show_tiny_markers", text="Thin Markers")
867         col.prop(sc, "show_track_path", text="Path")
868
869         row = col.row()
870         row.active = sc.show_track_path
871         row.prop(sc, "path_length", text="Length")
872
873
874 class CLIP_PT_stabilization(CLIP_PT_reconstruction_panel, Panel):
875     bl_space_type = 'CLIP_EDITOR'
876     bl_region_type = 'UI'
877     bl_label = "2D Stabilization"
878     bl_options = {'DEFAULT_CLOSED'}
879
880     def draw_header(self, context):
881         stab = context.space_data.clip.tracking.stabilization
882
883         self.layout.prop(stab, "use_2d_stabilization", text="")
884
885     def draw(self, context):
886         layout = self.layout
887
888         tracking = context.space_data.clip.tracking
889         stab = tracking.stabilization
890
891         layout.active = stab.use_2d_stabilization
892
893         row = layout.row()
894         row.template_list(stab, "tracks", stab, "active_track_index", rows=3)
895
896         sub = row.column(align=True)
897
898         sub.operator("clip.stabilize_2d_add", icon='ZOOMIN', text="")
899         sub.operator("clip.stabilize_2d_remove", icon='ZOOMOUT', text="")
900
901         sub.menu('CLIP_MT_stabilize_2d_specials', text="",
902                  icon='DOWNARROW_HLT')
903
904         layout.prop(stab, "influence_location")
905
906         layout.prop(stab, "use_autoscale")
907         col = layout.column()
908         col.active = stab.use_autoscale
909         col.prop(stab, "scale_max")
910         col.prop(stab, "influence_scale")
911
912         layout.prop(stab, "use_stabilize_rotation")
913         col = layout.column()
914         col.active = stab.use_stabilize_rotation
915
916         row = col.row(align=True)
917         row.prop_search(stab, "rotation_track", tracking, "tracks", text="")
918         row.operator("clip.stabilize_2d_set_rotation", text="", icon='ZOOMIN')
919
920         row = col.row()
921         row.active = stab.rotation_track is not None
922         row.prop(stab, "influence_rotation")
923
924         layout.prop(stab, "filter_type")
925
926
927 class CLIP_PT_marker(CLIP_PT_tracking_panel, Panel):
928     bl_space_type = 'CLIP_EDITOR'
929     bl_region_type = 'UI'
930     bl_label = "Marker"
931     bl_options = {'DEFAULT_CLOSED'}
932
933     def draw(self, context):
934         layout = self.layout
935         sc = context.space_data
936         clip = context.space_data.clip
937         act_track = clip.tracking.tracks.active
938
939         if act_track:
940             layout.template_marker(sc, "clip", sc.clip_user, act_track, False)
941         else:
942             layout.active = False
943             layout.label(text="No active track")
944
945
946 class CLIP_PT_proxy(CLIP_PT_clip_view_panel, Panel):
947     bl_space_type = 'CLIP_EDITOR'
948     bl_region_type = 'UI'
949     bl_label = "Proxy / Timecode"
950     bl_options = {'DEFAULT_CLOSED'}
951
952     def draw_header(self, context):
953         sc = context.space_data
954
955         self.layout.prop(sc.clip, "use_proxy", text="")
956
957     def draw(self, context):
958         layout = self.layout
959         sc = context.space_data
960         clip = sc.clip
961
962         layout.active = clip.use_proxy
963
964         layout.label(text="Build Original:")
965
966         row = layout.row(align=True)
967         row.prop(clip.proxy, "build_25", toggle=True)
968         row.prop(clip.proxy, "build_50", toggle=True)
969         row.prop(clip.proxy, "build_75", toggle=True)
970         row.prop(clip.proxy, "build_100", toggle=True)
971
972         layout.label(text="Build Undistorted:")
973
974         row = layout.row(align=True)
975         row.prop(clip.proxy, "build_undistorted_25", toggle=True)
976         row.prop(clip.proxy, "build_undistorted_50", toggle=True)
977         row.prop(clip.proxy, "build_undistorted_75", toggle=True)
978         row.prop(clip.proxy, "build_undistorted_100", toggle=True)
979
980         layout.prop(clip.proxy, "quality")
981
982         layout.prop(clip, 'use_proxy_custom_directory')
983         if clip.use_proxy_custom_directory:
984             layout.prop(clip.proxy, "directory")
985
986         layout.operator("clip.rebuild_proxy", text="Build Proxy")
987
988         if clip.source == 'MOVIE':
989             col = layout.column()
990
991             col.label(text="Use timecode index:")
992             col.prop(clip.proxy, "timecode", text="")
993
994         col = layout.column()
995         col.label(text="Proxy render size:")
996
997         col.prop(sc.clip_user, "proxy_render_size", text="")
998         col.prop(sc.clip_user, "use_render_undistorted")
999
1000
1001 class CLIP_PT_footage(CLIP_PT_clip_view_panel, Panel):
1002     bl_space_type = 'CLIP_EDITOR'
1003     bl_region_type = 'UI'
1004     bl_label = "Footage Settings"
1005     bl_options = {'DEFAULT_CLOSED'}
1006
1007     def draw(self, context):
1008         layout = self.layout
1009
1010         sc = context.space_data
1011         clip = sc.clip
1012
1013         col = layout.column()
1014         col.template_movieclip(sc, "clip", compact=True)
1015         col.prop(clip, "start_frame")
1016         col.prop(clip, "frame_offset")
1017
1018
1019 class CLIP_PT_tools_clip(CLIP_PT_clip_view_panel, Panel):
1020     bl_space_type = 'CLIP_EDITOR'
1021     bl_region_type = 'TOOLS'
1022     bl_label = "Clip"
1023
1024     def draw(self, context):
1025         layout = self.layout
1026
1027         layout.operator("clip.set_viewport_background")
1028         layout.operator("clip.setup_tracking_scene")
1029
1030
1031 class CLIP_MT_view(Menu):
1032     bl_label = "View"
1033
1034     def draw(self, context):
1035         layout = self.layout
1036         sc = context.space_data
1037
1038         if sc.view == 'CLIP':
1039             layout.operator("clip.properties", icon='MENU_PANEL')
1040             layout.operator("clip.tools", icon='MENU_PANEL')
1041             layout.separator()
1042
1043             layout.operator("clip.view_selected")
1044             layout.operator("clip.view_all")
1045
1046             layout.separator()
1047             layout.operator("clip.view_zoom_in")
1048             layout.operator("clip.view_zoom_out")
1049
1050             layout.separator()
1051
1052             ratios = ((1, 8), (1, 4), (1, 2), (1, 1), (2, 1), (4, 1), (8, 1))
1053
1054             for a, b in ratios:
1055                 text = "Zoom %d:%d" % (a, b)
1056                 layout.operator("clip.view_zoom_ratio", text=text).ratio = a / b
1057         else:
1058             layout.prop(sc, "show_seconds")
1059             layout.separator()
1060
1061         layout.separator()
1062         layout.operator("screen.area_dupli")
1063         layout.operator("screen.screen_full_area")
1064
1065
1066 class CLIP_MT_clip(Menu):
1067     bl_label = "Clip"
1068
1069     def draw(self, context):
1070         layout = self.layout
1071
1072         sc = context.space_data
1073         clip = sc.clip
1074
1075         layout.operator("clip.open")
1076
1077         if clip:
1078             layout.operator("clip.reload")
1079             layout.menu("CLIP_MT_proxy")
1080
1081
1082 class CLIP_MT_proxy(Menu):
1083     bl_label = "Proxy"
1084
1085     def draw(self, context):
1086         layout = self.layout
1087
1088         layout.operator("clip.rebuild_proxy")
1089         layout.operator("clip.delete_proxy")
1090
1091
1092 class CLIP_MT_track(Menu):
1093     bl_label = "Track"
1094
1095     def draw(self, context):
1096         layout = self.layout
1097
1098         layout.operator("clip.clear_solution")
1099         layout.operator("clip.solve_camera")
1100
1101         layout.separator()
1102         props = layout.operator("clip.clear_track_path", text="Clear After")
1103         props.action = 'REMAINED'
1104
1105         props = layout.operator("clip.clear_track_path", text="Clear Before")
1106         props.action = 'UPTO'
1107
1108         props = layout.operator("clip.clear_track_path",
1109             text="Clear Track Path")
1110         props.action = 'ALL'
1111
1112         layout.separator()
1113         layout.operator("clip.join_tracks")
1114
1115         layout.separator()
1116         layout.operator("clip.clean_tracks")
1117
1118         layout.separator()
1119         layout.operator("clip.copy_tracks")
1120         layout.operator("clip.paste_tracks")
1121
1122         layout.separator()
1123         props = layout.operator("clip.track_markers",
1124             text="Track Frame Backwards")
1125         props.backwards = True
1126
1127         props = layout.operator("clip.track_markers", text="Track Backwards")
1128         props.backwards = True
1129         props.sequence = True
1130
1131         props = layout.operator("clip.track_markers", text="Track Forwards")
1132         props.sequence = True
1133         layout.operator("clip.track_markers", text="Track Frame Forwards")
1134
1135         layout.separator()
1136         layout.operator("clip.delete_track")
1137         layout.operator("clip.delete_marker")
1138
1139         layout.separator()
1140         layout.operator("clip.add_marker_move")
1141
1142         layout.separator()
1143         layout.menu("CLIP_MT_track_visibility")
1144         layout.menu("CLIP_MT_track_transform")
1145
1146
1147 class CLIP_MT_reconstruction(Menu):
1148     bl_label = "Reconstruction"
1149
1150     def draw(self, context):
1151         layout = self.layout
1152
1153         layout.operator("clip.set_origin")
1154         props = layout.operator("clip.set_plane", text="Set Floor")
1155         props.plane = 'FLOOR'
1156         props = layout.operator("clip.set_plane", text="Set Wall")
1157         props.plane = 'WALL'
1158
1159         layout.operator("clip.set_axis", text="Set X Axis").axis = "X"
1160         layout.operator("clip.set_axis", text="Set Y Axis").axis = "Y"
1161
1162         layout.operator("clip.set_scale")
1163
1164         layout.separator()
1165
1166         layout.operator("clip.track_to_empty")
1167         layout.operator("clip.bundles_to_mesh")
1168
1169
1170 class CLIP_MT_track_visibility(Menu):
1171     bl_label = "Show/Hide"
1172
1173     def draw(self, context):
1174         layout = self.layout
1175
1176         layout.operator("clip.hide_tracks_clear", text="Show Hidden")
1177         layout.operator("clip.hide_tracks", text="Hide Selected")
1178
1179         props = layout.operator("clip.hide_tracks", text="Hide Unselected")
1180         props.unselected = True
1181
1182
1183 class CLIP_MT_track_transform(Menu):
1184     bl_label = "Transform"
1185
1186     def draw(self, context):
1187         layout = self.layout
1188
1189         layout.operator("transform.translate")
1190         layout.operator("transform.resize")
1191
1192
1193 class CLIP_MT_select(Menu):
1194     bl_label = "Select"
1195
1196     def draw(self, context):
1197         layout = self.layout
1198         sc = context.space_data
1199
1200         if sc.mode == 'MASKEDIT':
1201             layout.operator("mask.select_border")
1202             layout.operator("mask.select_circle")
1203
1204             layout.separator()
1205
1206             layout.operator("mask.select_all").action = 'TOGGLE'
1207             layout.operator("mask.select_all", text="Inverse").action = 'INVERT'
1208         else:
1209             layout.operator("clip.select_border")
1210             layout.operator("clip.select_circle")
1211
1212             layout.separator()
1213
1214             layout.operator("clip.select_all").action = 'TOGGLE'
1215             layout.operator("clip.select_all", text="Inverse").action = 'INVERT'
1216
1217             layout.menu("CLIP_MT_select_grouped")
1218
1219
1220 class CLIP_MT_select_grouped(Menu):
1221     bl_label = "Select Grouped"
1222
1223     def draw(self, context):
1224         layout = self.layout
1225
1226         layout.operator_enum("clip.select_grouped", "group")
1227
1228
1229 class CLIP_MT_tracking_specials(Menu):
1230     bl_label = "Specials"
1231
1232     @classmethod
1233     def poll(cls, context):
1234         return context.space_data.clip
1235
1236     def draw(self, context):
1237         layout = self.layout
1238
1239         props = layout.operator("clip.disable_markers",
1240                                 text="Enable Markers")
1241         props.action = 'ENABLE'
1242
1243         props = layout.operator("clip.disable_markers", text="Disable markers")
1244         props.action = 'DISABLE'
1245
1246         layout.separator()
1247         layout.operator("clip.set_origin")
1248
1249         layout.separator()
1250         layout.operator("clip.hide_tracks")
1251         layout.operator("clip.hide_tracks_clear", text="Show Tracks")
1252
1253         layout.separator()
1254         props = layout.operator("clip.lock_tracks", text="Lock Tracks")
1255         props.action = 'LOCK'
1256
1257         props = layout.operator("clip.lock_tracks", text="Unlock Tracks")
1258         props.action = 'UNLOCK'
1259
1260
1261 class CLIP_MT_mask(Menu):
1262     bl_label = "Mask"
1263
1264     def draw(self, context):
1265         layout = self.layout
1266
1267         layout.operator("mask.delete")
1268
1269         layout.separator()
1270         layout.operator("mask.cyclic_toggle")
1271         layout.operator("mask.switch_direction")
1272         layout.operator("mask.normals_make_consistent")
1273         layout.operator("mask.feather_weight_clear")  # TODO, better place?
1274
1275         layout.separator()
1276         layout.operator("mask.parent_clear")
1277         layout.operator("mask.parent_set")
1278
1279         layout.separator()
1280         layout.menu("CLIP_MT_mask_visibility")
1281         layout.menu("CLIP_MT_mask_transform")
1282         layout.menu("CLIP_MT_mask_animation")
1283
1284
1285 class CLIP_MT_mask_visibility(Menu):
1286     bl_label = "Show/Hide"
1287
1288     def draw(self, context):
1289         layout = self.layout
1290
1291         layout.operator("mask.hide_view_clear", text="Show Hidden")
1292         layout.operator("mask.hide_view_set", text="Hide Selected")
1293
1294         props = layout.operator("mask.hide_view_set", text="Hide Unselected")
1295         props.unselected = True
1296
1297
1298 class CLIP_MT_mask_transform(Menu):
1299     bl_label = "Transform"
1300
1301     def draw(self, context):
1302         layout = self.layout
1303
1304         layout.operator("transform.translate")
1305         layout.operator("transform.rotate")
1306         layout.operator("transform.resize")
1307         props = layout.operator("transform.transform", text="Shrink/Fatten")
1308         props.mode = 'MASK_SHRINKFATTEN'
1309
1310
1311 class CLIP_MT_mask_animation(Menu):
1312     bl_label = "Animation"
1313
1314     def draw(self, context):
1315         layout = self.layout
1316
1317         layout.operator("mask.shape_key_clear")
1318         layout.operator("mask.shape_key_insert")
1319         layout.operator("mask.shape_key_feather_reset")
1320
1321
1322 class CLIP_MT_camera_presets(Menu):
1323     """Predefined tracking camera intrinsics"""
1324     bl_label = "Camera Presets"
1325     preset_subdir = "tracking_camera"
1326     preset_operator = "script.execute_preset"
1327     draw = Menu.draw_preset
1328
1329
1330 class CLIP_MT_track_color_presets(Menu):
1331     """Predefined track color"""
1332     bl_label = "Color Presets"
1333     preset_subdir = "tracking_track_color"
1334     preset_operator = "script.execute_preset"
1335     draw = Menu.draw_preset
1336
1337
1338 class CLIP_MT_tracking_settings_presets(Menu):
1339     """Predefined tracking settings"""
1340     bl_label = "Tracking Presets"
1341     preset_subdir = "tracking_settings"
1342     preset_operator = "script.execute_preset"
1343     draw = Menu.draw_preset
1344
1345
1346 class CLIP_MT_track_color_specials(Menu):
1347     bl_label = "Track Color Specials"
1348
1349     def draw(self, context):
1350         layout = self.layout
1351
1352         layout.operator('clip.track_copy_color', icon='COPY_ID')
1353
1354
1355 class CLIP_MT_stabilize_2d_specials(Menu):
1356     bl_label = "Track Color Specials"
1357
1358     def draw(self, context):
1359         layout = self.layout
1360
1361         layout.operator('clip.stabilize_2d_select')
1362
1363 if __name__ == "__main__":  # only for live edit.
1364     bpy.utils.register_module(__name__)