e9997d43c04cedba58c8950c981759e8707b7866
[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
1017
1018 class CLIP_PT_tools_clip(CLIP_PT_clip_view_panel, Panel):
1019     bl_space_type = 'CLIP_EDITOR'
1020     bl_region_type = 'TOOLS'
1021     bl_label = "Clip"
1022
1023     def draw(self, context):
1024         layout = self.layout
1025
1026         layout.operator("clip.set_viewport_background")
1027         layout.operator("clip.setup_tracking_scene")
1028
1029
1030 class CLIP_MT_view(Menu):
1031     bl_label = "View"
1032
1033     def draw(self, context):
1034         layout = self.layout
1035         sc = context.space_data
1036
1037         if sc.view == 'CLIP':
1038             layout.operator("clip.properties", icon='MENU_PANEL')
1039             layout.operator("clip.tools", icon='MENU_PANEL')
1040             layout.separator()
1041
1042             layout.operator("clip.view_selected")
1043             layout.operator("clip.view_all")
1044
1045             layout.separator()
1046             layout.operator("clip.view_zoom_in")
1047             layout.operator("clip.view_zoom_out")
1048
1049             layout.separator()
1050
1051             ratios = ((1, 8), (1, 4), (1, 2), (1, 1), (2, 1), (4, 1), (8, 1))
1052
1053             for a, b in ratios:
1054                 text = "Zoom %d:%d" % (a, b)
1055                 layout.operator("clip.view_zoom_ratio", text=text).ratio = a / b
1056         else:
1057             layout.prop(sc, "show_seconds")
1058             layout.separator()
1059
1060         layout.separator()
1061         layout.operator("screen.area_dupli")
1062         layout.operator("screen.screen_full_area")
1063
1064
1065 class CLIP_MT_clip(Menu):
1066     bl_label = "Clip"
1067
1068     def draw(self, context):
1069         layout = self.layout
1070
1071         sc = context.space_data
1072         clip = sc.clip
1073
1074         layout.operator("clip.open")
1075
1076         if clip:
1077             layout.operator("clip.reload")
1078             layout.menu("CLIP_MT_proxy")
1079
1080
1081 class CLIP_MT_proxy(Menu):
1082     bl_label = "Proxy"
1083
1084     def draw(self, context):
1085         layout = self.layout
1086
1087         layout.operator("clip.rebuild_proxy")
1088         layout.operator("clip.delete_proxy")
1089
1090
1091 class CLIP_MT_track(Menu):
1092     bl_label = "Track"
1093
1094     def draw(self, context):
1095         layout = self.layout
1096
1097         layout.operator("clip.clear_solution")
1098         layout.operator("clip.solve_camera")
1099
1100         layout.separator()
1101         props = layout.operator("clip.clear_track_path", text="Clear After")
1102         props.action = 'REMAINED'
1103
1104         props = layout.operator("clip.clear_track_path", text="Clear Before")
1105         props.action = 'UPTO'
1106
1107         props = layout.operator("clip.clear_track_path",
1108             text="Clear Track Path")
1109         props.action = 'ALL'
1110
1111         layout.separator()
1112         layout.operator("clip.join_tracks")
1113
1114         layout.separator()
1115         layout.operator("clip.clean_tracks")
1116
1117         layout.separator()
1118         layout.operator("clip.copy_tracks")
1119         layout.operator("clip.paste_tracks")
1120
1121         layout.separator()
1122         props = layout.operator("clip.track_markers",
1123             text="Track Frame Backwards")
1124         props.backwards = True
1125
1126         props = layout.operator("clip.track_markers", text="Track Backwards")
1127         props.backwards = True
1128         props.sequence = True
1129
1130         props = layout.operator("clip.track_markers", text="Track Forwards")
1131         props.sequence = True
1132         layout.operator("clip.track_markers", text="Track Frame Forwards")
1133
1134         layout.separator()
1135         layout.operator("clip.delete_track")
1136         layout.operator("clip.delete_marker")
1137
1138         layout.separator()
1139         layout.operator("clip.add_marker_move")
1140
1141         layout.separator()
1142         layout.menu("CLIP_MT_track_visibility")
1143         layout.menu("CLIP_MT_track_transform")
1144
1145
1146 class CLIP_MT_reconstruction(Menu):
1147     bl_label = "Reconstruction"
1148
1149     def draw(self, context):
1150         layout = self.layout
1151
1152         layout.operator("clip.set_origin")
1153         props = layout.operator("clip.set_plane", text="Set Floor")
1154         props.plane = 'FLOOR'
1155         props = layout.operator("clip.set_plane", text="Set Wall")
1156         props.plane = 'WALL'
1157
1158         layout.operator("clip.set_axis", text="Set X Axis").axis = "X"
1159         layout.operator("clip.set_axis", text="Set Y Axis").axis = "Y"
1160
1161         layout.operator("clip.set_scale")
1162
1163         layout.separator()
1164
1165         layout.operator("clip.track_to_empty")
1166         layout.operator("clip.bundles_to_mesh")
1167
1168
1169 class CLIP_MT_track_visibility(Menu):
1170     bl_label = "Show/Hide"
1171
1172     def draw(self, context):
1173         layout = self.layout
1174
1175         layout.operator("clip.hide_tracks_clear", text="Show Hidden")
1176         layout.operator("clip.hide_tracks", text="Hide Selected")
1177
1178         props = layout.operator("clip.hide_tracks", text="Hide Unselected")
1179         props.unselected = True
1180
1181
1182 class CLIP_MT_track_transform(Menu):
1183     bl_label = "Transform"
1184
1185     def draw(self, context):
1186         layout = self.layout
1187
1188         layout.operator("transform.translate")
1189         layout.operator("transform.resize")
1190
1191
1192 class CLIP_MT_select(Menu):
1193     bl_label = "Select"
1194
1195     def draw(self, context):
1196         layout = self.layout
1197         sc = context.space_data
1198
1199         if sc.mode == 'MASKEDIT':
1200             layout.operator("mask.select_border")
1201             layout.operator("mask.select_circle")
1202
1203             layout.separator()
1204
1205             layout.operator("mask.select_all").action = 'TOGGLE'
1206             layout.operator("mask.select_all", text="Inverse").action = 'INVERT'
1207         else:
1208             layout.operator("clip.select_border")
1209             layout.operator("clip.select_circle")
1210
1211             layout.separator()
1212
1213             layout.operator("clip.select_all").action = 'TOGGLE'
1214             layout.operator("clip.select_all", text="Inverse").action = 'INVERT'
1215
1216             layout.menu("CLIP_MT_select_grouped")
1217
1218
1219 class CLIP_MT_select_grouped(Menu):
1220     bl_label = "Select Grouped"
1221
1222     def draw(self, context):
1223         layout = self.layout
1224
1225         layout.operator_enum("clip.select_grouped", "group")
1226
1227
1228 class CLIP_MT_tracking_specials(Menu):
1229     bl_label = "Specials"
1230
1231     @classmethod
1232     def poll(cls, context):
1233         return context.space_data.clip
1234
1235     def draw(self, context):
1236         layout = self.layout
1237
1238         props = layout.operator("clip.disable_markers",
1239                                 text="Enable Markers")
1240         props.action = 'ENABLE'
1241
1242         props = layout.operator("clip.disable_markers", text="Disable markers")
1243         props.action = 'DISABLE'
1244
1245         layout.separator()
1246         layout.operator("clip.set_origin")
1247
1248         layout.separator()
1249         layout.operator("clip.hide_tracks")
1250         layout.operator("clip.hide_tracks_clear", text="Show Tracks")
1251
1252         layout.separator()
1253         props = layout.operator("clip.lock_tracks", text="Lock Tracks")
1254         props.action = 'LOCK'
1255
1256         props = layout.operator("clip.lock_tracks", text="Unlock Tracks")
1257         props.action = 'UNLOCK'
1258
1259
1260 class CLIP_MT_mask(Menu):
1261     bl_label = "Mask"
1262
1263     def draw(self, context):
1264         layout = self.layout
1265
1266         layout.operator("mask.delete")
1267
1268         layout.separator()
1269         layout.operator("mask.cyclic_toggle")
1270         layout.operator("mask.switch_direction")
1271         layout.operator("mask.feather_weight_clear")  # TODO, better place?
1272
1273         layout.separator()
1274         layout.operator("mask.parent_clear")
1275         layout.operator("mask.parent_set")
1276
1277         layout.separator()
1278         layout.menu("CLIP_MT_mask_visibility")
1279         layout.menu("CLIP_MT_mask_transform")
1280         layout.menu("CLIP_MT_mask_animation")
1281
1282
1283 class CLIP_MT_mask_visibility(Menu):
1284     bl_label = "Show/Hide"
1285
1286     def draw(self, context):
1287         layout = self.layout
1288
1289         layout.operator("mask.hide_view_clear", text="Show Hidden")
1290         layout.operator("mask.hide_view_set", text="Hide Selected")
1291
1292         props = layout.operator("mask.hide_view_set", text="Hide Unselected")
1293         props.unselected = True
1294
1295
1296 class CLIP_MT_mask_transform(Menu):
1297     bl_label = "Transform"
1298
1299     def draw(self, context):
1300         layout = self.layout
1301
1302         layout.operator("transform.translate")
1303         layout.operator("transform.rotate")
1304         layout.operator("transform.resize")
1305         props = layout.operator("transform.transform", text="Shrink/Fatten")
1306         props.mode = 'MASK_SHRINKFATTEN'
1307
1308
1309 class CLIP_MT_mask_animation(Menu):
1310     bl_label = "Animation"
1311
1312     def draw(self, context):
1313         layout = self.layout
1314
1315         layout.operator("mask.shape_key_clear")
1316         layout.operator("mask.shape_key_insert")
1317         layout.operator("mask.shape_key_feather_reset")
1318
1319
1320 class CLIP_MT_camera_presets(Menu):
1321     """Predefined tracking camera intrinsics"""
1322     bl_label = "Camera Presets"
1323     preset_subdir = "tracking_camera"
1324     preset_operator = "script.execute_preset"
1325     draw = Menu.draw_preset
1326
1327
1328 class CLIP_MT_track_color_presets(Menu):
1329     """Predefined track color"""
1330     bl_label = "Color Presets"
1331     preset_subdir = "tracking_track_color"
1332     preset_operator = "script.execute_preset"
1333     draw = Menu.draw_preset
1334
1335
1336 class CLIP_MT_tracking_settings_presets(Menu):
1337     """Predefined tracking settings"""
1338     bl_label = "Tracking Presets"
1339     preset_subdir = "tracking_settings"
1340     preset_operator = "script.execute_preset"
1341     draw = Menu.draw_preset
1342
1343
1344 class CLIP_MT_track_color_specials(Menu):
1345     bl_label = "Track Color Specials"
1346
1347     def draw(self, context):
1348         layout = self.layout
1349
1350         layout.operator('clip.track_copy_color', icon='COPY_ID')
1351
1352
1353 class CLIP_MT_stabilize_2d_specials(Menu):
1354     bl_label = "Track Color Specials"
1355
1356     def draw(self, context):
1357         layout = self.layout
1358
1359         layout.operator('clip.stabilize_2d_select')
1360
1361 if __name__ == "__main__":  # only for live edit.
1362     bpy.utils.register_module(__name__)