78fb7843f1454f33b0ea0f00fcdf2cebc81a847d
[blender-staging.git] / release / scripts / startup / bl_ui / properties_mask_common.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 # panels get subclassed (not registered directly)
22 # menus are referenced `as is`
23
24 import bpy
25 from bpy.types import Menu, UIList
26
27
28 class MASK_UL_layers(UIList):
29     def draw_item(self, context, layout, data, item, icon,
30                   active_data, active_propname, index):
31         # assert(isinstance(item, bpy.types.MaskLayer)
32         mask = item
33         if self.layout_type in {'DEFAULT', 'COMPACT'}:
34             layout.prop(mask, "name", text="", emboss=False, icon_value=icon)
35             row = layout.row(align=True)
36             row.prop(mask, "hide", text="", emboss=False)
37             row.prop(mask, "hide_select", text="", emboss=False)
38             row.prop(mask, "hide_render", text="", emboss=False)
39         elif self.layout_type == 'GRID':
40             layout.alignment = 'CENTER'
41             layout.label(text="", icon_value=icon)
42
43
44 class MASK_PT_mask:
45     # subclasses must define...
46     #~ bl_space_type = 'CLIP_EDITOR'
47     #~ bl_region_type = 'UI'
48     bl_label = "Mask Settings"
49     bl_options = {'DEFAULT_CLOSED'}
50
51     @classmethod
52     def poll(cls, context):
53         space_data = context.space_data
54         return space_data.mask and space_data.mode == 'MASK'
55
56     def draw(self, context):
57         layout = self.layout
58
59         sc = context.space_data
60         mask = sc.mask
61
62         col = layout.column(align=True)
63         col.prop(mask, "frame_start")
64         col.prop(mask, "frame_end")
65
66
67 class MASK_PT_layers:
68     # subclasses must define...
69     #~ bl_space_type = 'CLIP_EDITOR'
70     #~ bl_region_type = 'UI'
71     bl_label = "Mask Layers"
72
73     @classmethod
74     def poll(cls, context):
75         space_data = context.space_data
76         return space_data.mask and space_data.mode == 'MASK'
77
78     def draw(self, context):
79         layout = self.layout
80
81         sc = context.space_data
82         mask = sc.mask
83         active_layer = mask.layers.active
84
85         rows = 4 if active_layer else 1
86
87         row = layout.row()
88         row.template_list("MASK_UL_layers", "", mask, "layers",
89                           mask, "active_layer_index", rows=rows)
90
91         sub = row.column(align=True)
92
93         sub.operator("mask.layer_new", icon='ZOOMIN', text="")
94         sub.operator("mask.layer_remove", icon='ZOOMOUT', text="")
95
96         if active_layer:
97             sub.separator()
98
99             sub.operator("mask.layer_move", icon='TRIA_UP', text="").direction = 'UP'
100             sub.operator("mask.layer_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
101
102             # blending
103             row = layout.row(align=True)
104             row.prop(active_layer, "alpha")
105             row.prop(active_layer, "invert", text="", icon='IMAGE_ALPHA')
106
107             layout.prop(active_layer, "blend")
108             layout.prop(active_layer, "falloff")
109
110             row = layout.row(align=True)
111             row.prop(active_layer, "use_fill_overlap", text="Overlap")
112             row.prop(active_layer, "use_fill_holes", text="Holes")
113
114
115 class MASK_PT_spline:
116     # subclasses must define...
117     #~ bl_space_type = 'CLIP_EDITOR'
118     #~ bl_region_type = 'UI'
119     bl_label = "Active Spline"
120
121     @classmethod
122     def poll(cls, context):
123         sc = context.space_data
124         mask = sc.mask
125
126         if mask and sc.mode == 'MASK':
127             return mask.layers.active and mask.layers.active.splines.active
128
129         return False
130
131     def draw(self, context):
132         layout = self.layout
133
134         sc = context.space_data
135         mask = sc.mask
136         spline = mask.layers.active.splines.active
137
138         col = layout.column()
139         col.prop(spline, "offset_mode")
140         col.prop(spline, "weight_interpolation")
141
142         row = col.row()
143         row.prop(spline, "use_cyclic")
144         row.prop(spline, "use_fill")
145
146         col.prop(spline, "use_self_intersection_check")
147
148
149 class MASK_PT_point:
150     # subclasses must define...
151     #~ bl_space_type = 'CLIP_EDITOR'
152     #~ bl_region_type = 'UI'
153     bl_label = "Active Point"
154
155     @classmethod
156     def poll(cls, context):
157         sc = context.space_data
158         mask = sc.mask
159
160         if mask and sc.mode == 'MASK':
161             mask_layer_active = mask.layers.active
162             return (mask_layer_active and
163                     mask_layer_active.splines.active_point)
164
165         return False
166
167     def draw(self, context):
168         layout = self.layout
169
170         sc = context.space_data
171         mask = sc.mask
172         point = mask.layers.active.splines.active_point
173         parent = point.parent
174
175         col = layout.column()
176         # Currently only parenting the movie-clip is allowed,
177         # so do not over-complicate things for now by using single template_ID
178         #col.template_any_ID(parent, "id", "id_type", text="")
179
180         col.label("Parent:")
181         col.prop(parent, "id", text="")
182
183         if parent.id_type == 'MOVIECLIP' and parent.id:
184             clip = parent.id
185             tracking = clip.tracking
186
187             row = col.row()
188             row.prop(parent, "type", expand=True)
189
190             col.prop_search(parent, "parent", tracking,
191                             "objects", icon='OBJECT_DATA', text="Object:")
192
193             tracks_list = "tracks" if parent.type == 'POINT_TRACK' else "plane_tracks"
194
195             if parent.parent in tracking.objects:
196                 object = tracking.objects[parent.parent]
197                 col.prop_search(parent, "sub_parent", object,
198                                 tracks_list, icon='ANIM_DATA', text="Track:")
199             else:
200                 col.prop_search(parent, "sub_parent", tracking,
201                                 tracks_list, icon='ANIM_DATA', text="Track:")
202
203
204 class MASK_PT_display:
205     # subclasses must define...
206     #~ bl_space_type = 'CLIP_EDITOR'
207     #~ bl_region_type = 'UI'
208     bl_label = "Mask Display"
209     bl_options = {'DEFAULT_CLOSED'}
210
211     @classmethod
212     def poll(cls, context):
213         space_data = context.space_data
214         return space_data.mask and space_data.mode == 'MASK'
215
216     def draw(self, context):
217         layout = self.layout
218
219         space_data = context.space_data
220         row = layout.row(align=True)
221         row.prop(space_data, "show_mask_smooth", text="Smooth")
222         row.prop(space_data, "mask_draw_type", text="")
223         row = layout.row(align=True)
224         row.prop(space_data, "show_mask_overlay", text="Overlay")
225         sub = row.row()
226         sub.active = space_data.show_mask_overlay
227         sub.prop(space_data, "mask_overlay_mode", text="")
228
229
230 class MASK_PT_transforms:
231     # subclasses must define...
232     #~ bl_space_type = 'CLIP_EDITOR'
233     #~ bl_region_type = 'TOOLS'
234     bl_label = "Transforms"
235     bl_category = "Mask"
236     bl_options = {'DEFAULT_CLOSED'}
237
238     @classmethod
239     def poll(cls, context):
240         space_data = context.space_data
241         return space_data.mask and space_data.mode == 'MASK'
242
243     def draw(self, context):
244         layout = self.layout
245
246         col = layout.column(align=True)
247         col.label(text="Transform:")
248         col.operator("transform.translate")
249         col.operator("transform.rotate")
250         col.operator("transform.resize", text="Scale")
251         col.operator("transform.transform", text="Scale Feather").mode = 'MASK_SHRINKFATTEN'
252
253
254 class MASK_PT_tools:
255     # subclasses must define...
256     #~ bl_space_type = 'CLIP_EDITOR'
257     #~ bl_region_type = 'TOOLS'
258     bl_label = "Mask Tools"
259     bl_category = "Mask"
260
261     @classmethod
262     def poll(cls, context):
263         space_data = context.space_data
264         return space_data.mask and space_data.mode == 'MASK'
265
266     def draw(self, context):
267         layout = self.layout
268
269         col = layout.column(align=True)
270         col.label(text="Spline:")
271         col.operator("mask.delete")
272         col.operator("mask.cyclic_toggle")
273         col.operator("mask.switch_direction")
274         col.operator("mask.handle_type_set")
275         col.operator("mask.feather_weight_clear")
276
277         col = layout.column(align=True)
278         col.label(text="Parenting:")
279         row = col.row(align=True)
280         row.operator("mask.parent_set", text="Parent")
281         row.operator("mask.parent_clear", text="Clear")
282
283         col = layout.column(align=True)
284         col.label(text="Animation:")
285         row = col.row(align=True)
286         row.operator("mask.shape_key_insert", text="Insert Key")
287         row.operator("mask.shape_key_clear", text="Clear Key")
288         col.operator("mask.shape_key_feather_reset", text="Reset Feather Animation")
289         col.operator("mask.shape_key_rekey", text="Re-Key Shape Points")
290
291
292 class MASK_PT_add:
293     # subclasses must define...
294     #~ bl_space_type = 'CLIP_EDITOR'
295     #~ bl_region_type = 'TOOLS'
296     bl_label = "Add"
297     bl_category = "Mask"
298
299     @classmethod
300     def poll(cls, context):
301         space_data = context.space_data
302         return space_data.mode == 'MASK'
303
304     def draw(self, context):
305         layout = self.layout
306
307         col = layout.column(align=True)
308         col.operator("mask.primitive_circle_add", icon='MESH_CIRCLE')
309         col.operator("mask.primitive_square_add", icon='MESH_PLANE')
310
311
312 class MASK_MT_mask(Menu):
313     bl_label = "Mask"
314
315     def draw(self, context):
316         layout = self.layout
317
318         layout.operator("mask.delete")
319
320         layout.separator()
321         layout.operator("mask.cyclic_toggle")
322         layout.operator("mask.switch_direction")
323         layout.operator("mask.normals_make_consistent")
324         layout.operator("mask.feather_weight_clear")  # TODO, better place?
325
326         layout.separator()
327         layout.operator("mask.parent_clear")
328         layout.operator("mask.parent_set")
329
330         layout.separator()
331         layout.operator("mask.copy_splines")
332         layout.operator("mask.paste_splines")
333
334         layout.separator()
335         layout.menu("MASK_MT_visibility")
336         layout.menu("MASK_MT_transform")
337         layout.menu("MASK_MT_animation")
338
339
340 class MASK_MT_visibility(Menu):
341     bl_label = "Show/Hide"
342
343     def draw(self, context):
344         layout = self.layout
345
346         layout.operator("mask.hide_view_clear", text="Show Hidden")
347         layout.operator("mask.hide_view_set", text="Hide Selected").unselected = False
348         layout.operator("mask.hide_view_set", text="Hide Unselected").unselected = True
349
350
351 class MASK_MT_transform(Menu):
352     bl_label = "Transform"
353
354     def draw(self, context):
355         layout = self.layout
356
357         layout.operator("transform.translate")
358         layout.operator("transform.rotate")
359         layout.operator("transform.resize")
360         layout.operator("transform.transform", text="Scale Feather").mode = 'MASK_SHRINKFATTEN'
361
362
363 class MASK_MT_animation(Menu):
364     bl_label = "Animation"
365
366     def draw(self, context):
367         layout = self.layout
368
369         layout.operator("mask.shape_key_clear")
370         layout.operator("mask.shape_key_insert")
371         layout.operator("mask.shape_key_feather_reset")
372         layout.operator("mask.shape_key_rekey")
373
374
375 class MASK_MT_select(Menu):
376     bl_label = "Select"
377
378     def draw(self, context):
379         layout = self.layout
380
381         layout.operator("mask.select_border")
382         layout.operator("mask.select_circle")
383
384         layout.separator()
385
386         layout.operator("mask.select_more")
387         layout.operator("mask.select_less")
388
389         layout.separator()
390
391         layout.operator("mask.select_all").action = 'TOGGLE'
392         layout.operator("mask.select_all", text="Inverse").action = 'INVERT'
393         layout.operator("mask.select_linked", text="Select Linked")
394
395
396 classes = (
397     MASK_MT_animation,
398     MASK_MT_mask,
399     MASK_MT_select,
400     MASK_MT_transform,
401     MASK_MT_visibility,
402     MASK_UL_layers,
403 )
404
405 if __name__ == "__main__":  # only for live edit.
406     from bpy.utils import register_class
407     for cls in classes:
408         register_class(cls)