properties_mask_common.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  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. # <pep8-80 compliant>
  19. # panels get subclassed (not registered directly)
  20. # menus are referenced `as is`
  21. from bpy.types import Menu, UIList
  22. class MASK_UL_layers(UIList):
  23. def draw_item(self, _context, layout, _data, item, icon,
  24. _active_data, _active_propname, _index):
  25. # assert(isinstance(item, bpy.types.MaskLayer)
  26. mask = item
  27. if self.layout_type in {'DEFAULT', 'COMPACT'}:
  28. layout.prop(mask, "name", text="", emboss=False, icon_value=icon)
  29. row = layout.row(align=True)
  30. row.prop(mask, "hide", text="", emboss=False)
  31. row.prop(mask, "hide_select", text="", emboss=False)
  32. row.prop(mask, "hide_render", text="", emboss=False)
  33. elif self.layout_type == 'GRID':
  34. layout.alignment = 'CENTER'
  35. layout.label(text="", icon_value=icon)
  36. class MASK_PT_mask:
  37. # subclasses must define...
  38. # ~ bl_space_type = 'CLIP_EDITOR'
  39. # ~ bl_region_type = 'UI'
  40. bl_label = "Mask Settings"
  41. bl_options = {'DEFAULT_CLOSED'}
  42. @classmethod
  43. def poll(cls, context):
  44. space_data = context.space_data
  45. return space_data.mask and space_data.mode == 'MASK'
  46. def draw(self, context):
  47. layout = self.layout
  48. layout.use_property_split = True
  49. layout.use_property_decorate = False
  50. sc = context.space_data
  51. mask = sc.mask
  52. col = layout.column(align=True)
  53. col.prop(mask, "frame_start")
  54. col.prop(mask, "frame_end")
  55. class MASK_PT_layers:
  56. # subclasses must define...
  57. # ~ bl_space_type = 'CLIP_EDITOR'
  58. # ~ bl_region_type = 'UI'
  59. bl_label = "Mask Layers"
  60. @classmethod
  61. def poll(cls, context):
  62. space_data = context.space_data
  63. return space_data.mask and space_data.mode == 'MASK'
  64. def draw(self, context):
  65. layout = self.layout
  66. layout.use_property_split = True
  67. layout.use_property_decorate = False
  68. sc = context.space_data
  69. mask = sc.mask
  70. active_layer = mask.layers.active
  71. rows = 4 if active_layer else 1
  72. row = layout.row()
  73. row.template_list("MASK_UL_layers", "", mask, "layers",
  74. mask, "active_layer_index", rows=rows)
  75. sub = row.column(align=True)
  76. sub.operator("mask.layer_new", icon='ADD', text="")
  77. sub.operator("mask.layer_remove", icon='REMOVE', text="")
  78. if active_layer:
  79. sub.separator()
  80. sub.operator("mask.layer_move", icon='TRIA_UP', text="").direction = 'UP'
  81. sub.operator("mask.layer_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
  82. # blending
  83. row = layout.row(align=True)
  84. row.prop(active_layer, "alpha")
  85. row.prop(active_layer, "invert", text="", icon='IMAGE_ALPHA')
  86. layout.prop(active_layer, "blend")
  87. layout.prop(active_layer, "falloff")
  88. col = layout.column()
  89. col.prop(active_layer, "use_fill_overlap", text="Overlap")
  90. col.prop(active_layer, "use_fill_holes", text="Holes")
  91. class MASK_PT_spline:
  92. # subclasses must define...
  93. # ~ bl_space_type = 'CLIP_EDITOR'
  94. # ~ bl_region_type = 'UI'
  95. bl_label = "Active Spline"
  96. @classmethod
  97. def poll(cls, context):
  98. sc = context.space_data
  99. mask = sc.mask
  100. if mask and sc.mode == 'MASK':
  101. return mask.layers.active and mask.layers.active.splines.active
  102. return False
  103. def draw(self, context):
  104. layout = self.layout
  105. layout.use_property_split = True
  106. layout.use_property_decorate = False
  107. sc = context.space_data
  108. mask = sc.mask
  109. spline = mask.layers.active.splines.active
  110. col = layout.column()
  111. col.prop(spline, "offset_mode")
  112. col.prop(spline, "weight_interpolation", text="Interpolation")
  113. col.prop(spline, "use_cyclic")
  114. col.prop(spline, "use_fill")
  115. col.prop(spline, "use_self_intersection_check")
  116. class MASK_PT_point:
  117. # subclasses must define...
  118. # ~ bl_space_type = 'CLIP_EDITOR'
  119. # ~ bl_region_type = 'UI'
  120. bl_label = "Active Point"
  121. @classmethod
  122. def poll(cls, context):
  123. sc = context.space_data
  124. mask = sc.mask
  125. if mask and sc.mode == 'MASK':
  126. mask_layer_active = mask.layers.active
  127. return (mask_layer_active and
  128. mask_layer_active.splines.active_point)
  129. return False
  130. def draw(self, context):
  131. layout = self.layout
  132. layout.use_property_split = True
  133. layout.use_property_decorate = False
  134. sc = context.space_data
  135. mask = sc.mask
  136. point = mask.layers.active.splines.active_point
  137. parent = point.parent
  138. col = layout.column()
  139. # Currently only parenting the movie-clip is allowed,
  140. # so do not over-complicate things for now by using single template_ID
  141. #col.template_any_ID(parent, "id", "id_type", text="")
  142. col.label(text="Parent:")
  143. col.prop(parent, "id", text="")
  144. if parent.id_type == 'MOVIECLIP' and parent.id:
  145. clip = parent.id
  146. tracking = clip.tracking
  147. row = col.row()
  148. row.prop(parent, "type", expand=True)
  149. col.prop_search(parent, "parent", tracking,
  150. "objects", icon='OBJECT_DATA', text="Object")
  151. tracks_list = "tracks" if parent.type == 'POINT_TRACK' else "plane_tracks"
  152. if parent.parent in tracking.objects:
  153. ob = tracking.objects[parent.parent]
  154. col.prop_search(parent, "sub_parent", ob,
  155. tracks_list, icon='ANIM_DATA', text="Track")
  156. else:
  157. col.prop_search(parent, "sub_parent", tracking,
  158. tracks_list, icon='ANIM_DATA', text="Track")
  159. class MASK_PT_display:
  160. # subclasses must define...
  161. # ~ bl_space_type = 'CLIP_EDITOR'
  162. # ~ bl_region_type = 'UI'
  163. bl_label = "Mask Display"
  164. bl_options = {'DEFAULT_CLOSED'}
  165. @classmethod
  166. def poll(cls, context):
  167. space_data = context.space_data
  168. return space_data.mask and space_data.mode == 'MASK'
  169. def draw(self, context):
  170. layout = self.layout
  171. space_data = context.space_data
  172. row = layout.row(align=True)
  173. row.prop(space_data, "show_mask_smooth", text="Smooth")
  174. row.prop(space_data, "mask_display_type", text="")
  175. row = layout.row(align=True)
  176. row.prop(space_data, "show_mask_overlay", text="Overlay")
  177. sub = row.row()
  178. sub.active = space_data.show_mask_overlay
  179. sub.prop(space_data, "mask_overlay_mode", text="")
  180. class MASK_PT_transforms:
  181. # subclasses must define...
  182. # ~ bl_space_type = 'CLIP_EDITOR'
  183. # ~ bl_region_type = 'TOOLS'
  184. bl_label = "Transforms"
  185. bl_category = "Mask"
  186. @classmethod
  187. def poll(cls, context):
  188. space_data = context.space_data
  189. return space_data.mask and space_data.mode == 'MASK'
  190. def draw(self, _context):
  191. layout = self.layout
  192. col = layout.column(align=True)
  193. col.label(text="Transform:")
  194. col.operator("transform.translate")
  195. col.operator("transform.rotate")
  196. col.operator("transform.resize", text="Scale")
  197. col.operator("transform.transform", text="Scale Feather").mode = 'MASK_SHRINKFATTEN'
  198. class MASK_PT_tools:
  199. bl_label = "Mask Tools"
  200. bl_category = "Mask"
  201. @classmethod
  202. def poll(cls, context):
  203. space_data = context.space_data
  204. return space_data.mask and space_data.mode == 'MASK'
  205. def draw(self, _context):
  206. layout = self.layout
  207. col = layout.column(align=True)
  208. col.label(text="Spline:")
  209. col.operator("mask.delete")
  210. col.operator("mask.cyclic_toggle")
  211. col.operator("mask.switch_direction")
  212. col.operator("mask.handle_type_set").type = 'VECTOR'
  213. col.operator("mask.feather_weight_clear")
  214. col = layout.column(align=True)
  215. col.label(text="Parenting:")
  216. row = col.row(align=True)
  217. row.operator("mask.parent_set", text="Parent")
  218. row.operator("mask.parent_clear", text="Clear")
  219. col = layout.column(align=True)
  220. col.label(text="Animation:")
  221. row = col.row(align=True)
  222. row.operator("mask.shape_key_insert", text="Insert Key")
  223. row.operator("mask.shape_key_clear", text="Clear Key")
  224. col.operator("mask.shape_key_feather_reset", text="Reset Feather Animation")
  225. col.operator("mask.shape_key_rekey", text="Re-Key Shape Points")
  226. class MASK_MT_mask(Menu):
  227. bl_label = "Mask"
  228. def draw(self, _context):
  229. layout = self.layout
  230. layout.operator("mask.delete")
  231. layout.separator()
  232. layout.operator("mask.cyclic_toggle")
  233. layout.operator("mask.switch_direction")
  234. layout.operator("mask.normals_make_consistent")
  235. layout.operator("mask.handle_type_set")
  236. layout.operator("mask.feather_weight_clear") # TODO, better place?
  237. layout.separator()
  238. layout.operator("mask.parent_clear")
  239. layout.operator("mask.parent_set")
  240. layout.separator()
  241. layout.operator("mask.copy_splines")
  242. layout.operator("mask.paste_splines")
  243. layout.separator()
  244. layout.menu("MASK_MT_visibility")
  245. layout.menu("MASK_MT_transform")
  246. layout.menu("MASK_MT_animation")
  247. class MASK_MT_visibility(Menu):
  248. bl_label = "Show/Hide"
  249. def draw(self, _context):
  250. layout = self.layout
  251. layout.operator("mask.hide_view_clear")
  252. layout.operator("mask.hide_view_set", text="Hide Selected").unselected = False
  253. layout.operator("mask.hide_view_set", text="Hide Unselected").unselected = True
  254. class MASK_MT_transform(Menu):
  255. bl_label = "Transform"
  256. def draw(self, _context):
  257. layout = self.layout
  258. layout.operator("transform.translate")
  259. layout.operator("transform.rotate")
  260. layout.operator("transform.resize")
  261. layout.operator("transform.transform", text="Scale Feather").mode = 'MASK_SHRINKFATTEN'
  262. class MASK_MT_animation(Menu):
  263. bl_label = "Animation"
  264. def draw(self, _context):
  265. layout = self.layout
  266. layout.operator("mask.shape_key_clear")
  267. layout.operator("mask.shape_key_insert")
  268. layout.operator("mask.shape_key_feather_reset")
  269. layout.operator("mask.shape_key_rekey")
  270. class MASK_MT_select(Menu):
  271. bl_label = "Select"
  272. def draw(self, _context):
  273. layout = self.layout
  274. layout.operator("mask.select_all", text="All").action = 'SELECT'
  275. layout.operator("mask.select_all", text="None").action = 'DESELECT'
  276. layout.operator("mask.select_all", text="Invert").action = 'INVERT'
  277. layout.separator()
  278. layout.operator("mask.select_box")
  279. layout.operator("mask.select_circle")
  280. layout.separator()
  281. layout.operator("mask.select_more")
  282. layout.operator("mask.select_less")
  283. layout.separator()
  284. layout.operator("mask.select_linked", text="Select Linked")
  285. classes = (
  286. MASK_UL_layers,
  287. MASK_MT_mask,
  288. MASK_MT_visibility,
  289. MASK_MT_transform,
  290. MASK_MT_animation,
  291. MASK_MT_select,
  292. )
  293. if __name__ == "__main__": # only for live edit.
  294. from bpy.utils import register_class
  295. for cls in classes:
  296. register_class(cls)