properties_object.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  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. from bl_ui.properties_animviz import (
  20. MotionPathButtonsPanel,
  21. MotionPathButtonsPanel_display,
  22. )
  23. import bpy
  24. from bpy.types import Panel, Menu
  25. from rna_prop_ui import PropertyPanel
  26. class ObjectButtonsPanel:
  27. bl_space_type = 'PROPERTIES'
  28. bl_region_type = 'WINDOW'
  29. bl_context = "object"
  30. class OBJECT_PT_context_object(ObjectButtonsPanel, Panel):
  31. bl_label = ""
  32. bl_options = {'HIDE_HEADER'}
  33. def draw(self, context):
  34. layout = self.layout
  35. space = context.space_data
  36. if space.use_pin_id:
  37. layout.template_ID(space, "pin_id")
  38. else:
  39. row = layout.row()
  40. row.template_ID(context.view_layer.objects, "active", filter='AVAILABLE')
  41. class OBJECT_PT_transform(ObjectButtonsPanel, Panel):
  42. bl_label = "Transform"
  43. def draw(self, context):
  44. layout = self.layout
  45. layout.use_property_split = True
  46. flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
  47. ob = context.object
  48. col = flow.column()
  49. row = col.row(align=True)
  50. row.prop(ob, "location")
  51. row.use_property_decorate = False
  52. row.prop(ob, "lock_location", text="", emboss=False, icon='DECORATE_UNLOCKED')
  53. rotation_mode = ob.rotation_mode
  54. if rotation_mode == 'QUATERNION':
  55. col = flow.column()
  56. row = col.row(align=True)
  57. row.prop(ob, "rotation_quaternion", text="Rotation")
  58. sub = row.column(align=True)
  59. sub.use_property_decorate = False
  60. sub.prop(ob, "lock_rotation_w", text="", emboss=False, icon='DECORATE_UNLOCKED')
  61. sub.prop(ob, "lock_rotation", text="", emboss=False, icon='DECORATE_UNLOCKED')
  62. elif rotation_mode == 'AXIS_ANGLE':
  63. col = flow.column()
  64. row = col.row(align=True)
  65. row.prop(ob, "rotation_axis_angle", text="Rotation")
  66. sub = row.column(align=True)
  67. sub.use_property_decorate = False
  68. sub.prop(ob, "lock_rotation_w", text="", emboss=False, icon='DECORATE_UNLOCKED')
  69. sub.prop(ob, "lock_rotation", text="", emboss=False, icon='DECORATE_UNLOCKED')
  70. else:
  71. col = flow.column()
  72. row = col.row(align=True)
  73. row.prop(ob, "rotation_euler", text="Rotation")
  74. row.use_property_decorate = False
  75. row.prop(ob, "lock_rotation", text="", emboss=False, icon='DECORATE_UNLOCKED')
  76. col = flow.column()
  77. row = col.row(align=True)
  78. row.prop(ob, "scale")
  79. row.use_property_decorate = False
  80. row.prop(ob, "lock_scale", text="", emboss=False, icon='DECORATE_UNLOCKED')
  81. row = layout.row(align=True)
  82. row.prop(ob, "rotation_mode")
  83. row.label(text="", icon='BLANK1')
  84. class OBJECT_PT_delta_transform(ObjectButtonsPanel, Panel):
  85. bl_label = "Delta Transform"
  86. bl_parent_id = "OBJECT_PT_transform"
  87. bl_options = {'DEFAULT_CLOSED'}
  88. def draw(self, context):
  89. layout = self.layout
  90. layout.use_property_split = True
  91. flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=True, align=False)
  92. ob = context.object
  93. col = flow.column()
  94. col.prop(ob, "delta_location")
  95. col = flow.column()
  96. rotation_mode = ob.rotation_mode
  97. if rotation_mode == 'QUATERNION':
  98. col.prop(ob, "delta_rotation_quaternion", text="Rotation")
  99. elif rotation_mode == 'AXIS_ANGLE':
  100. col.label(text="Not for Axis-Angle")
  101. else:
  102. col.prop(ob, "delta_rotation_euler", text="Delta Rotation")
  103. col = flow.column()
  104. col.prop(ob, "delta_scale")
  105. class OBJECT_PT_relations(ObjectButtonsPanel, Panel):
  106. bl_label = "Relations"
  107. bl_options = {'DEFAULT_CLOSED'}
  108. def draw(self, context):
  109. layout = self.layout
  110. layout.use_property_split = True
  111. flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
  112. ob = context.object
  113. col = flow.column()
  114. col.prop(ob, "parent")
  115. sub = col.column()
  116. sub.prop(ob, "parent_type")
  117. parent = ob.parent
  118. if parent and ob.parent_type == 'BONE' and parent.type == 'ARMATURE':
  119. sub.prop_search(ob, "parent_bone", parent.data, "bones")
  120. sub.active = (parent is not None)
  121. col.separator()
  122. col = flow.column()
  123. col.prop(ob, "track_axis", text="Tracking Axis")
  124. col.prop(ob, "up_axis", text="Up Axis")
  125. col.separator()
  126. col = flow.column()
  127. col.prop(ob, "pass_index")
  128. class COLLECTION_MT_context_menu(Menu):
  129. bl_label = "Collection Specials"
  130. def draw(self, _context):
  131. layout = self.layout
  132. layout.operator("object.collection_unlink", icon='X')
  133. layout.operator("object.collection_objects_select")
  134. layout.operator("object.instance_offset_from_cursor")
  135. class OBJECT_PT_collections(ObjectButtonsPanel, Panel):
  136. bl_label = "Collections"
  137. bl_options = {'DEFAULT_CLOSED'}
  138. def draw(self, context):
  139. layout = self.layout
  140. obj = context.object
  141. row = layout.row(align=True)
  142. if bpy.data.collections:
  143. row.operator("object.collection_link", text="Add to Collection")
  144. else:
  145. row.operator("object.collection_add", text="Add to Collection")
  146. row.operator("object.collection_add", text="", icon='ADD')
  147. obj_name = obj.name
  148. for collection in bpy.data.collections:
  149. # XXX this is slow and stupid!, we need 2 checks, one that's fast
  150. # and another that we can be sure its not a name collision
  151. # from linked library data
  152. collection_objects = collection.objects
  153. if obj_name in collection.objects and obj in collection_objects[:]:
  154. col = layout.column(align=True)
  155. col.context_pointer_set("collection", collection)
  156. row = col.box().row()
  157. row.prop(collection, "name", text="")
  158. row.operator("object.collection_remove", text="", icon='X', emboss=False)
  159. row.menu("COLLECTION_MT_context_menu", icon='DOWNARROW_HLT', text="")
  160. row = col.box().row()
  161. row.prop(collection, "instance_offset", text="")
  162. class OBJECT_PT_display(ObjectButtonsPanel, Panel):
  163. bl_label = "Viewport Display"
  164. bl_options = {'DEFAULT_CLOSED'}
  165. bl_order = 10
  166. def draw(self, context):
  167. layout = self.layout
  168. layout.use_property_split = True
  169. flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
  170. obj = context.object
  171. obj_type = obj.type
  172. is_geometry = (obj_type in {'MESH', 'CURVE', 'SURFACE', 'META', 'FONT'})
  173. is_wire = (obj_type in {'CAMERA', 'EMPTY'})
  174. is_empty_image = (obj_type == 'EMPTY' and obj.empty_display_type == 'IMAGE')
  175. is_dupli = (obj.instance_type != 'NONE')
  176. is_gpencil = (obj_type == 'GPENCIL')
  177. col = flow.column()
  178. col.prop(obj, "show_name", text="Name")
  179. col = flow.column()
  180. col.prop(obj, "show_axis", text="Axis")
  181. # Makes no sense for cameras, armatures, etc.!
  182. # but these settings do apply to dupli instances
  183. if is_geometry or is_dupli:
  184. col = flow.column()
  185. col.prop(obj, "show_wire", text="Wireframe")
  186. if obj_type == 'MESH' or is_dupli:
  187. col = flow.column()
  188. col.prop(obj, "show_all_edges", text="All Edges")
  189. col = flow.column()
  190. if is_geometry:
  191. col.prop(obj, "show_texture_space", text="Texture Space")
  192. col = flow.column()
  193. col.prop(obj.display, "show_shadows", text="Shadow")
  194. col = flow.column()
  195. col.prop(obj, "show_in_front", text="In Front")
  196. # if obj_type == 'MESH' or is_empty_image:
  197. # col.prop(obj, "show_transparent", text="Transparency")
  198. flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
  199. col = flow.column()
  200. if is_wire:
  201. # wire objects only use the max. display type for duplis
  202. col.active = is_dupli
  203. col.prop(obj, "display_type", text="Display As")
  204. if is_geometry or is_dupli or is_empty_image or is_gpencil:
  205. # Only useful with object having faces/materials...
  206. col = flow.column()
  207. col.prop(obj, "color")
  208. class OBJECT_PT_display_bounds(ObjectButtonsPanel, Panel):
  209. bl_label = "Bounds"
  210. bl_parent_id = "OBJECT_PT_display"
  211. bl_options = {'DEFAULT_CLOSED'}
  212. def draw_header(self, context):
  213. obj = context.object
  214. self.layout.prop(obj, "show_bounds", text="")
  215. def draw(self, context):
  216. layout = self.layout
  217. obj = context.object
  218. layout.use_property_split = True
  219. layout.active = obj.show_bounds or (obj.display_type == 'BOUNDS')
  220. layout.prop(obj, "display_bounds_type", text="Shape")
  221. class OBJECT_PT_instancing(ObjectButtonsPanel, Panel):
  222. bl_label = "Instancing"
  223. bl_options = {'DEFAULT_CLOSED'}
  224. def draw(self, context):
  225. layout = self.layout
  226. ob = context.object
  227. row = layout.row()
  228. row.prop(ob, "instance_type", expand=True)
  229. layout.use_property_split = True
  230. flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
  231. if ob.instance_type == 'VERTS':
  232. layout.prop(ob, "use_instance_vertices_rotation", text="Align to Vertex Normal")
  233. elif ob.instance_type == 'COLLECTION':
  234. col = layout.column()
  235. col.prop(ob, "instance_collection", text="Collection")
  236. if ob.instance_type != 'NONE' or ob.particle_systems:
  237. col = flow.column(align=True)
  238. col.prop(ob, "show_instancer_for_viewport")
  239. col.prop(ob, "show_instancer_for_render")
  240. class OBJECT_PT_instancing_size(ObjectButtonsPanel, Panel):
  241. bl_label = "Scale by Face Size"
  242. bl_parent_id = "OBJECT_PT_instancing"
  243. @classmethod
  244. def poll(cls, context):
  245. ob = context.object
  246. return ob.instance_type == 'FACES'
  247. def draw_header(self, context):
  248. ob = context.object
  249. self.layout.prop(ob, "use_instance_faces_scale", text="")
  250. def draw(self, context):
  251. layout = self.layout
  252. ob = context.object
  253. layout.use_property_split = True
  254. layout.active = ob.use_instance_faces_scale
  255. layout.prop(ob, "instance_faces_scale", text="Factor")
  256. class OBJECT_PT_motion_paths(MotionPathButtonsPanel, Panel):
  257. #bl_label = "Object Motion Paths"
  258. bl_context = "object"
  259. bl_options = {'DEFAULT_CLOSED'}
  260. @classmethod
  261. def poll(cls, context):
  262. return (context.object)
  263. def draw(self, context):
  264. # layout = self.layout
  265. ob = context.object
  266. avs = ob.animation_visualization
  267. mpath = ob.motion_path
  268. self.draw_settings(context, avs, mpath)
  269. class OBJECT_PT_motion_paths_display(MotionPathButtonsPanel_display, Panel):
  270. #bl_label = "Object Motion Paths"
  271. bl_context = "object"
  272. bl_parent_id = "OBJECT_PT_motion_paths"
  273. bl_options = {'DEFAULT_CLOSED'}
  274. @classmethod
  275. def poll(cls, context):
  276. return (context.object)
  277. def draw(self, context):
  278. # layout = self.layout
  279. ob = context.object
  280. avs = ob.animation_visualization
  281. mpath = ob.motion_path
  282. self.draw_settings(context, avs, mpath)
  283. class OBJECT_PT_visibility(ObjectButtonsPanel, Panel):
  284. bl_label = "Visibility"
  285. bl_options = {'DEFAULT_CLOSED'}
  286. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
  287. @classmethod
  288. def poll(cls, context):
  289. return (context.object) and (context.engine in cls.COMPAT_ENGINES)
  290. def draw(self, context):
  291. layout = self.layout
  292. layout.use_property_split = True
  293. flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
  294. layout = self.layout
  295. ob = context.object
  296. col = flow.column()
  297. col.prop(ob, "hide_viewport", text="Show in Viewports", toggle=False, invert_checkbox=True)
  298. col = flow.column()
  299. col.prop(ob, "hide_render", text="Show in Renders", toggle=False, invert_checkbox=True)
  300. col = flow.column()
  301. col.prop(ob, "hide_select", text="Selectable", toggle=False, invert_checkbox=True)
  302. class OBJECT_PT_custom_props(ObjectButtonsPanel, PropertyPanel, Panel):
  303. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
  304. _context_path = "object"
  305. _property_type = bpy.types.Object
  306. classes = (
  307. OBJECT_PT_context_object,
  308. OBJECT_PT_transform,
  309. OBJECT_PT_delta_transform,
  310. OBJECT_PT_relations,
  311. COLLECTION_MT_context_menu,
  312. OBJECT_PT_collections,
  313. OBJECT_PT_instancing,
  314. OBJECT_PT_instancing_size,
  315. OBJECT_PT_motion_paths,
  316. OBJECT_PT_motion_paths_display,
  317. OBJECT_PT_display,
  318. OBJECT_PT_display_bounds,
  319. OBJECT_PT_visibility,
  320. OBJECT_PT_custom_props,
  321. )
  322. if __name__ == "__main__": # only for live edit.
  323. from bpy.utils import register_class
  324. for cls in classes:
  325. register_class(cls)