properties_data_gpencil.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  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 compliant>
  19. import bpy
  20. from bpy.types import Menu, Panel, UIList
  21. from rna_prop_ui import PropertyPanel
  22. ###############################
  23. # Base-Classes (for shared stuff - e.g. poll, attributes, etc.)
  24. class DataButtonsPanel:
  25. bl_space_type = 'PROPERTIES'
  26. bl_region_type = 'WINDOW'
  27. bl_context = "data"
  28. @classmethod
  29. def poll(cls, context):
  30. return context.gpencil
  31. class ObjectButtonsPanel:
  32. bl_space_type = 'PROPERTIES'
  33. bl_region_type = 'WINDOW'
  34. bl_context = "data"
  35. @classmethod
  36. def poll(cls, context):
  37. ob = context.object
  38. return ob and ob.type == 'GPENCIL'
  39. class LayerDataButtonsPanel:
  40. bl_space_type = 'PROPERTIES'
  41. bl_region_type = 'WINDOW'
  42. bl_context = "data"
  43. @classmethod
  44. def poll(cls, context):
  45. gpencil = context.gpencil
  46. return gpencil and gpencil.layers.active
  47. ###############################
  48. # GP Object Properties Panels and Helper Classes
  49. class DATA_PT_context_gpencil(DataButtonsPanel, Panel):
  50. bl_label = ""
  51. bl_options = {'HIDE_HEADER'}
  52. def draw(self, context):
  53. layout = self.layout
  54. ob = context.object
  55. space = context.space_data
  56. if ob:
  57. layout.template_ID(ob, "data")
  58. else:
  59. layout.template_ID(space, "pin_id")
  60. class GPENCIL_MT_layer_context_menu(Menu):
  61. bl_label = "Layer"
  62. def draw(self, context):
  63. layout = self.layout
  64. ob = context.object
  65. gpd = ob.data
  66. layout.operator("gpencil.layer_duplicate", icon='ADD') # XXX: needs a dedicated icon
  67. layout.separator()
  68. layout.operator("gpencil.reveal", icon='RESTRICT_VIEW_OFF', text="Show All")
  69. layout.operator("gpencil.hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True
  70. layout.separator()
  71. layout.operator("gpencil.lock_all", icon='LOCKED', text="Lock All")
  72. layout.operator("gpencil.unlock_all", icon='UNLOCKED', text="UnLock All")
  73. layout.prop(gpd, "use_autolock_layers", text="Autolock Inactive Layers")
  74. layout.separator()
  75. layout.operator("gpencil.layer_merge", icon='SORT_ASC', text="Merge Down")
  76. layout.separator()
  77. layout.menu("VIEW3D_MT_gpencil_copy_layer")
  78. class DATA_PT_gpencil_layers(DataButtonsPanel, Panel):
  79. bl_label = "Layers"
  80. def draw(self, context):
  81. layout = self.layout
  82. #layout.use_property_split = True
  83. layout.use_property_decorate = False
  84. gpd = context.gpencil
  85. # Grease Pencil data...
  86. if (gpd is None) or (not gpd.layers):
  87. layout.operator("gpencil.layer_add", text="New Layer")
  88. else:
  89. self.draw_layers(context, layout, gpd)
  90. def draw_layers(self, _context, layout, gpd):
  91. row = layout.row()
  92. col = row.column()
  93. layer_rows = 7
  94. col.template_list("GPENCIL_UL_layer", "", gpd, "layers", gpd.layers, "active_index",
  95. rows=layer_rows, sort_reverse=True, sort_lock=True)
  96. gpl = gpd.layers.active
  97. if gpl:
  98. srow = col.row(align=True)
  99. srow.prop(gpl, "blend_mode", text="Blend")
  100. srow = col.row(align=True)
  101. srow.prop(gpl, "opacity", text="Opacity", slider=True)
  102. srow.prop(gpl, "mask_layer", text="",
  103. icon='MOD_MASK' if gpl.mask_layer else 'LAYER_ACTIVE')
  104. srow = col.row(align=True)
  105. srow.prop(gpl, "use_solo_mode", text="Show Only On Keyframed")
  106. col = row.column()
  107. sub = col.column(align=True)
  108. sub.operator("gpencil.layer_add", icon='ADD', text="")
  109. sub.operator("gpencil.layer_remove", icon='REMOVE', text="")
  110. if gpl:
  111. sub.menu("GPENCIL_MT_layer_context_menu", icon='DOWNARROW_HLT', text="")
  112. if len(gpd.layers) > 1:
  113. col.separator()
  114. sub = col.column(align=True)
  115. sub.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP'
  116. sub.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN'
  117. col.separator()
  118. sub = col.column(align=True)
  119. sub.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
  120. sub.operator("gpencil.layer_isolate", icon='RESTRICT_VIEW_ON', text="").affect_visibility = True
  121. class DATA_PT_gpencil_layer_adjustments(LayerDataButtonsPanel, Panel):
  122. bl_label = "Adjustments"
  123. bl_parent_id = 'DATA_PT_gpencil_layers'
  124. bl_options = {'DEFAULT_CLOSED'}
  125. def draw(self, context):
  126. layout = self.layout
  127. layout.use_property_split = True
  128. scene = context.scene
  129. gpd = context.gpencil
  130. gpl = gpd.layers.active
  131. layout.active = not gpl.lock
  132. # Layer options
  133. # Offsets - Color Tint
  134. layout.enabled = not gpl.lock
  135. col = layout.column(align=True)
  136. col.prop(gpl, "tint_color")
  137. col.prop(gpl, "tint_factor", text="Factor", slider=True)
  138. # Offsets - Thickness
  139. col = layout.row(align=True)
  140. col.prop(gpl, "line_change", text="Stroke Thickness")
  141. col = layout.row(align=True)
  142. col.prop(gpl, "pass_index")
  143. col = layout.row(align=True)
  144. col.prop_search(gpl, "viewlayer_render", scene, "view_layers", text="View Layer")
  145. col = layout.row(align=True)
  146. col.prop(gpl, "lock_material")
  147. class DATA_PT_gpencil_layer_relations(LayerDataButtonsPanel, Panel):
  148. bl_label = "Relations"
  149. bl_parent_id = 'DATA_PT_gpencil_layers'
  150. bl_options = {'DEFAULT_CLOSED'}
  151. def draw(self, context):
  152. layout = self.layout
  153. layout.use_property_split = True
  154. layout.use_property_decorate = False
  155. gpd = context.gpencil
  156. gpl = gpd.layers.active
  157. col = layout.column()
  158. col.active = not gpl.lock
  159. col.prop(gpl, "parent")
  160. col.prop(gpl, "parent_type", text="Type")
  161. parent = gpl.parent
  162. if parent and gpl.parent_type == 'BONE' and parent.type == 'ARMATURE':
  163. col.prop_search(gpl, "parent_bone", parent.data, "bones", text="Bone")
  164. class DATA_PT_gpencil_layer_display(LayerDataButtonsPanel, Panel):
  165. bl_label = "Display"
  166. bl_parent_id = 'DATA_PT_gpencil_layers'
  167. bl_options = {'DEFAULT_CLOSED'}
  168. def draw(self, context):
  169. layout = self.layout
  170. layout.use_property_split = True
  171. layout.use_property_decorate = False
  172. gpd = context.gpencil
  173. gpl = gpd.layers.active
  174. col = layout.row(align=True)
  175. col.prop(gpl, "channel_color")
  176. class DATA_PT_gpencil_onion_skinning(DataButtonsPanel, Panel):
  177. bl_label = "Onion Skinning"
  178. def draw(self, context):
  179. gpd = context.gpencil
  180. layout = self.layout
  181. layout.use_property_split = True
  182. layout.enabled = gpd.users <= 1
  183. if gpd.users > 1:
  184. layout.label(text="Multiuser datablock not supported", icon='ERROR')
  185. col = layout.column()
  186. col.prop(gpd, "onion_mode")
  187. col.prop(gpd, "onion_factor", text="Opacity", slider=True)
  188. col.prop(gpd, "onion_keyframe_type")
  189. if gpd.onion_mode == 'ABSOLUTE':
  190. col = layout.column(align=True)
  191. col.prop(gpd, "ghost_before_range", text="Frames Before")
  192. col.prop(gpd, "ghost_after_range", text="Frames After")
  193. elif gpd.onion_mode == 'RELATIVE':
  194. col = layout.column(align=True)
  195. col.prop(gpd, "ghost_before_range", text="Keyframes Before")
  196. col.prop(gpd, "ghost_after_range", text="Keyframes After")
  197. class DATA_PT_gpencil_onion_skinning_custom_colors(DataButtonsPanel, Panel):
  198. bl_parent_id = "DATA_PT_gpencil_onion_skinning"
  199. bl_label = "Custom Colors"
  200. bl_options = {'DEFAULT_CLOSED'}
  201. def draw_header(self, context):
  202. gpd = context.gpencil
  203. self.layout.prop(gpd, "use_ghost_custom_colors", text="")
  204. def draw(self, context):
  205. gpd = context.gpencil
  206. layout = self.layout
  207. layout.use_property_split = True
  208. layout.enabled = gpd.users <= 1 and gpd.use_ghost_custom_colors
  209. layout.prop(gpd, "before_color", text="Before")
  210. layout.prop(gpd, "after_color", text="After")
  211. class DATA_PT_gpencil_onion_skinning_display(DataButtonsPanel, Panel):
  212. bl_parent_id = "DATA_PT_gpencil_onion_skinning"
  213. bl_label = "Display"
  214. bl_options = {'DEFAULT_CLOSED'}
  215. def draw(self, context):
  216. gpd = context.gpencil
  217. layout = self.layout
  218. layout.use_property_split = True
  219. layout.enabled = gpd.users <= 1
  220. layout.prop(gpd, "use_ghosts_always", text="View In Render")
  221. col = layout.column(align=True)
  222. col.prop(gpd, "use_onion_fade", text="Fade")
  223. sub = layout.column()
  224. sub.active = gpd.onion_mode in {'RELATIVE', 'SELECTED'}
  225. sub.prop(gpd, "use_onion_loop", text="Loop")
  226. class GPENCIL_MT_gpencil_vertex_group(Menu):
  227. bl_label = "GP Vertex Groups"
  228. def draw(self, context):
  229. layout = self.layout
  230. layout.operator_context = 'EXEC_AREA'
  231. layout.operator("object.vertex_group_add")
  232. ob = context.active_object
  233. if ob.vertex_groups.active:
  234. layout.separator()
  235. layout.operator("gpencil.vertex_group_assign", text="Assign to Active Group")
  236. layout.operator("gpencil.vertex_group_remove_from", text="Remove from Active Group")
  237. layout.separator()
  238. layout.operator_menu_enum("object.vertex_group_set_active", "group", text="Set Active Group")
  239. layout.operator("object.vertex_group_remove", text="Remove Active Group").all = False
  240. layout.operator("object.vertex_group_remove", text="Remove All Groups").all = True
  241. layout.separator()
  242. layout.operator("gpencil.vertex_group_select", text="Select Points")
  243. layout.operator("gpencil.vertex_group_deselect", text="Deselect Points")
  244. class GPENCIL_UL_vgroups(UIList):
  245. def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
  246. vgroup = item
  247. if self.layout_type in {'DEFAULT', 'COMPACT'}:
  248. layout.prop(vgroup, "name", text="", emboss=False, icon_value=icon)
  249. icon = 'LOCKED' if vgroup.lock_weight else 'UNLOCKED'
  250. layout.prop(vgroup, "lock_weight", text="", icon=icon, emboss=False)
  251. elif self.layout_type == 'GRID':
  252. layout.alignment = 'CENTER'
  253. layout.label(text="", icon_value=icon)
  254. class DATA_PT_gpencil_vertex_groups(ObjectButtonsPanel, Panel):
  255. bl_label = "Vertex Groups"
  256. bl_options = {'DEFAULT_CLOSED'}
  257. def draw(self, context):
  258. layout = self.layout
  259. ob = context.object
  260. group = ob.vertex_groups.active
  261. rows = 2
  262. if group:
  263. rows = 4
  264. row = layout.row()
  265. row.template_list("GPENCIL_UL_vgroups", "", ob, "vertex_groups", ob.vertex_groups, "active_index", rows=rows)
  266. col = row.column(align=True)
  267. col.operator("object.vertex_group_add", icon='ADD', text="")
  268. col.operator("object.vertex_group_remove", icon='REMOVE', text="").all = False
  269. if ob.vertex_groups:
  270. row = layout.row()
  271. sub = row.row(align=True)
  272. sub.operator("gpencil.vertex_group_assign", text="Assign")
  273. sub.operator("gpencil.vertex_group_remove_from", text="Remove")
  274. sub = row.row(align=True)
  275. sub.operator("gpencil.vertex_group_select", text="Select")
  276. sub.operator("gpencil.vertex_group_deselect", text="Deselect")
  277. layout.prop(context.tool_settings, "vertex_group_weight", text="Weight")
  278. class DATA_PT_gpencil_strokes(DataButtonsPanel, Panel):
  279. bl_label = "Strokes"
  280. bl_options = {'DEFAULT_CLOSED'}
  281. def draw(self, context):
  282. layout = self.layout
  283. layout.use_property_split = True
  284. layout.use_property_decorate = False
  285. ob = context.object
  286. gpd = context.gpencil
  287. col = layout.column(align=True)
  288. col.prop(gpd, "stroke_depth_order")
  289. if ob:
  290. col.enabled = not ob.show_in_front
  291. col = layout.column(align=True)
  292. col.prop(gpd, "stroke_thickness_space")
  293. sub = col.column()
  294. sub.active = gpd.stroke_thickness_space == 'WORLDSPACE'
  295. sub.prop(gpd, "pixel_factor", text="Thickness Scale")
  296. layout.prop(gpd, "use_force_fill_recalc", text="Force Fill Update")
  297. layout.prop(gpd, "use_adaptive_uv", text="Adaptive UVs")
  298. class DATA_PT_gpencil_display(DataButtonsPanel, Panel):
  299. bl_label = "Viewport Display"
  300. bl_options = {'DEFAULT_CLOSED'}
  301. def draw(self, context):
  302. layout = self.layout
  303. layout.use_property_split = True
  304. layout.use_property_decorate = False
  305. gpd = context.gpencil
  306. gpl = gpd.layers.active
  307. layout.prop(gpd, "edit_line_color", text="Edit Line Color")
  308. if gpl:
  309. layout.prop(gpd, "show_stroke_direction", text="Show Stroke Directions")
  310. class DATA_PT_gpencil_canvas(DataButtonsPanel, Panel):
  311. bl_label = "Canvas"
  312. bl_parent_id = 'DATA_PT_gpencil_display'
  313. bl_options = {'DEFAULT_CLOSED'}
  314. def draw(self, context):
  315. layout = self.layout
  316. layout.use_property_split = True
  317. layout.use_property_decorate = False
  318. gpd = context.gpencil
  319. grid = gpd.grid
  320. row = layout.row(align=True)
  321. col = row.column()
  322. col.prop(grid, "color", text="Color")
  323. col.prop(grid, "scale", text="Scale")
  324. col.prop(grid, "offset")
  325. row = layout.row(align=True)
  326. col = row.column()
  327. col.prop(grid, "lines", text="Subdivisions")
  328. class DATA_PT_custom_props_gpencil(DataButtonsPanel, PropertyPanel, Panel):
  329. _context_path = "object.data"
  330. _property_type = bpy.types.GreasePencil
  331. ###############################
  332. classes = (
  333. DATA_PT_context_gpencil,
  334. DATA_PT_gpencil_layers,
  335. DATA_PT_gpencil_onion_skinning,
  336. DATA_PT_gpencil_onion_skinning_custom_colors,
  337. DATA_PT_gpencil_onion_skinning_display,
  338. DATA_PT_gpencil_layer_adjustments,
  339. DATA_PT_gpencil_layer_relations,
  340. DATA_PT_gpencil_layer_display,
  341. DATA_PT_gpencil_vertex_groups,
  342. DATA_PT_gpencil_strokes,
  343. DATA_PT_gpencil_display,
  344. DATA_PT_gpencil_canvas,
  345. DATA_PT_custom_props_gpencil,
  346. GPENCIL_UL_vgroups,
  347. GPENCIL_MT_layer_context_menu,
  348. GPENCIL_MT_gpencil_vertex_group,
  349. )
  350. if __name__ == "__main__": # only for live edit.
  351. from bpy.utils import register_class
  352. for cls in classes:
  353. register_class(cls)