properties_constraint.py 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023
  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 bpy.types import Panel
  20. class ConstraintButtonsPanel:
  21. bl_space_type = 'PROPERTIES'
  22. bl_region_type = 'WINDOW'
  23. bl_context = "constraint"
  24. def draw_constraint(self, context, con):
  25. layout = self.layout
  26. box = layout.template_constraint(con)
  27. if box:
  28. # match enum type to our functions, avoids a lookup table.
  29. getattr(self, con.type)(context, box, con)
  30. if con.type in {'RIGID_BODY_JOINT', 'NULL'}:
  31. return
  32. if con.type in {'IK', 'SPLINE_IK'}:
  33. # constraint.disable_keep_transform doesn't work well
  34. # for these constraints.
  35. box.prop(con, "influence")
  36. else:
  37. row = box.row(align=True)
  38. row.prop(con, "influence")
  39. row.operator("constraint.disable_keep_transform", text="", icon='CANCEL')
  40. @staticmethod
  41. def space_template(layout, con, target=True, owner=True):
  42. if target or owner:
  43. split = layout.split(factor=0.2)
  44. split.label(text="Space:")
  45. row = split.row()
  46. if target:
  47. row.prop(con, "target_space", text="")
  48. if target and owner:
  49. row.label(icon='ARROW_LEFTRIGHT')
  50. if owner:
  51. row.prop(con, "owner_space", text="")
  52. @staticmethod
  53. def target_template(layout, con, subtargets=True):
  54. layout.prop(con, "target") # XXX limiting settings for only 'curves' or some type of object
  55. if con.target and subtargets:
  56. if con.target.type == 'ARMATURE':
  57. layout.prop_search(con, "subtarget", con.target.data, "bones", text="Bone")
  58. if hasattr(con, "head_tail"):
  59. row = layout.row(align=True)
  60. row.label(text="Head/Tail:")
  61. row.prop(con, "head_tail", text="")
  62. # XXX icon, and only when bone has segments?
  63. row.prop(con, "use_bbone_shape", text="", icon='IPO_BEZIER')
  64. elif con.target.type in {'MESH', 'LATTICE'}:
  65. layout.prop_search(con, "subtarget", con.target, "vertex_groups", text="Vertex Group")
  66. @staticmethod
  67. def ik_template(layout, con):
  68. # only used for iTaSC
  69. layout.prop(con, "pole_target")
  70. if con.pole_target and con.pole_target.type == 'ARMATURE':
  71. layout.prop_search(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
  72. if con.pole_target:
  73. row = layout.row()
  74. row.label()
  75. row.prop(con, "pole_angle")
  76. split = layout.split(factor=0.33)
  77. col = split.column()
  78. col.prop(con, "use_tail")
  79. col.prop(con, "use_stretch")
  80. col = split.column()
  81. col.prop(con, "chain_count")
  82. def CHILD_OF(self, _context, layout, con):
  83. self.target_template(layout, con)
  84. split = layout.split()
  85. col = split.column()
  86. col.label(text="Location:")
  87. col.prop(con, "use_location_x", text="X")
  88. col.prop(con, "use_location_y", text="Y")
  89. col.prop(con, "use_location_z", text="Z")
  90. col = split.column()
  91. col.label(text="Rotation:")
  92. col.prop(con, "use_rotation_x", text="X")
  93. col.prop(con, "use_rotation_y", text="Y")
  94. col.prop(con, "use_rotation_z", text="Z")
  95. col = split.column()
  96. col.label(text="Scale:")
  97. col.prop(con, "use_scale_x", text="X")
  98. col.prop(con, "use_scale_y", text="Y")
  99. col.prop(con, "use_scale_z", text="Z")
  100. row = layout.row()
  101. row.operator("constraint.childof_set_inverse")
  102. row.operator("constraint.childof_clear_inverse")
  103. def TRACK_TO(self, _context, layout, con):
  104. self.target_template(layout, con)
  105. row = layout.row()
  106. row.label(text="To:")
  107. row.prop(con, "track_axis", expand=True)
  108. row = layout.row()
  109. row.prop(con, "up_axis", text="Up")
  110. row.prop(con, "use_target_z")
  111. self.space_template(layout, con)
  112. def IK(self, context, layout, con):
  113. if context.object.pose.ik_solver == 'ITASC':
  114. layout.prop(con, "ik_type")
  115. getattr(self, 'IK_' + con.ik_type)(context, layout, con)
  116. else:
  117. # Standard IK constraint
  118. self.target_template(layout, con)
  119. layout.prop(con, "pole_target")
  120. if con.pole_target and con.pole_target.type == 'ARMATURE':
  121. layout.prop_search(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
  122. if con.pole_target:
  123. row = layout.row()
  124. row.prop(con, "pole_angle")
  125. row.label()
  126. split = layout.split()
  127. col = split.column()
  128. col.prop(con, "iterations")
  129. col.prop(con, "chain_count")
  130. col = split.column()
  131. col.prop(con, "use_tail")
  132. col.prop(con, "use_stretch")
  133. layout.label(text="Weight:")
  134. split = layout.split()
  135. col = split.column()
  136. row = col.row(align=True)
  137. row.prop(con, "use_location", text="")
  138. sub = row.row(align=True)
  139. sub.active = con.use_location
  140. sub.prop(con, "weight", text="Position", slider=True)
  141. col = split.column()
  142. row = col.row(align=True)
  143. row.prop(con, "use_rotation", text="")
  144. sub = row.row(align=True)
  145. sub.active = con.use_rotation
  146. sub.prop(con, "orient_weight", text="Rotation", slider=True)
  147. def IK_COPY_POSE(self, _context, layout, con):
  148. self.target_template(layout, con)
  149. self.ik_template(layout, con)
  150. row = layout.row()
  151. row.label(text="Axis Ref:")
  152. row.prop(con, "reference_axis", expand=True)
  153. split = layout.split(factor=0.33)
  154. split.row().prop(con, "use_location")
  155. row = split.row()
  156. row.prop(con, "weight", text="Weight", slider=True)
  157. row.active = con.use_location
  158. split = layout.split(factor=0.33)
  159. row = split.row()
  160. row.label(text="Lock:")
  161. row = split.row()
  162. row.prop(con, "lock_location_x", text="X")
  163. row.prop(con, "lock_location_y", text="Y")
  164. row.prop(con, "lock_location_z", text="Z")
  165. split.active = con.use_location
  166. split = layout.split(factor=0.33)
  167. split.row().prop(con, "use_rotation")
  168. row = split.row()
  169. row.prop(con, "orient_weight", text="Weight", slider=True)
  170. row.active = con.use_rotation
  171. split = layout.split(factor=0.33)
  172. row = split.row()
  173. row.label(text="Lock:")
  174. row = split.row()
  175. row.prop(con, "lock_rotation_x", text="X")
  176. row.prop(con, "lock_rotation_y", text="Y")
  177. row.prop(con, "lock_rotation_z", text="Z")
  178. split.active = con.use_rotation
  179. def IK_DISTANCE(self, _context, layout, con):
  180. self.target_template(layout, con)
  181. self.ik_template(layout, con)
  182. layout.prop(con, "limit_mode")
  183. row = layout.row()
  184. row.prop(con, "weight", text="Weight", slider=True)
  185. row.prop(con, "distance", text="Distance", slider=True)
  186. def FOLLOW_PATH(self, _context, layout, con):
  187. self.target_template(layout, con)
  188. layout.operator("constraint.followpath_path_animate", text="Animate Path", icon='ANIM_DATA')
  189. split = layout.split()
  190. col = split.column()
  191. col.prop(con, "use_curve_follow")
  192. col.prop(con, "use_curve_radius")
  193. col = split.column()
  194. col.prop(con, "use_fixed_location")
  195. if con.use_fixed_location:
  196. col.prop(con, "offset_factor", text="Offset")
  197. else:
  198. col.prop(con, "offset")
  199. row = layout.row()
  200. row.label(text="Forward:")
  201. row.prop(con, "forward_axis", expand=True)
  202. row = layout.row()
  203. row.prop(con, "up_axis", text="Up")
  204. row.label()
  205. def LIMIT_ROTATION(self, _context, layout, con):
  206. split = layout.split()
  207. col = split.column(align=True)
  208. col.prop(con, "use_limit_x")
  209. sub = col.column(align=True)
  210. sub.active = con.use_limit_x
  211. sub.prop(con, "min_x", text="Min")
  212. sub.prop(con, "max_x", text="Max")
  213. col = split.column(align=True)
  214. col.prop(con, "use_limit_y")
  215. sub = col.column(align=True)
  216. sub.active = con.use_limit_y
  217. sub.prop(con, "min_y", text="Min")
  218. sub.prop(con, "max_y", text="Max")
  219. col = split.column(align=True)
  220. col.prop(con, "use_limit_z")
  221. sub = col.column(align=True)
  222. sub.active = con.use_limit_z
  223. sub.prop(con, "min_z", text="Min")
  224. sub.prop(con, "max_z", text="Max")
  225. layout.prop(con, "use_transform_limit")
  226. row = layout.row()
  227. row.label(text="Convert:")
  228. row.prop(con, "owner_space", text="")
  229. def LIMIT_LOCATION(self, _context, layout, con):
  230. split = layout.split()
  231. col = split.column()
  232. col.prop(con, "use_min_x")
  233. sub = col.column()
  234. sub.active = con.use_min_x
  235. sub.prop(con, "min_x", text="")
  236. col.prop(con, "use_max_x")
  237. sub = col.column()
  238. sub.active = con.use_max_x
  239. sub.prop(con, "max_x", text="")
  240. col = split.column()
  241. col.prop(con, "use_min_y")
  242. sub = col.column()
  243. sub.active = con.use_min_y
  244. sub.prop(con, "min_y", text="")
  245. col.prop(con, "use_max_y")
  246. sub = col.column()
  247. sub.active = con.use_max_y
  248. sub.prop(con, "max_y", text="")
  249. col = split.column()
  250. col.prop(con, "use_min_z")
  251. sub = col.column()
  252. sub.active = con.use_min_z
  253. sub.prop(con, "min_z", text="")
  254. col.prop(con, "use_max_z")
  255. sub = col.column()
  256. sub.active = con.use_max_z
  257. sub.prop(con, "max_z", text="")
  258. row = layout.row()
  259. row.prop(con, "use_transform_limit")
  260. row.label()
  261. row = layout.row()
  262. row.label(text="Convert:")
  263. row.prop(con, "owner_space", text="")
  264. def LIMIT_SCALE(self, _context, layout, con):
  265. split = layout.split()
  266. col = split.column()
  267. col.prop(con, "use_min_x")
  268. sub = col.column()
  269. sub.active = con.use_min_x
  270. sub.prop(con, "min_x", text="")
  271. col.prop(con, "use_max_x")
  272. sub = col.column()
  273. sub.active = con.use_max_x
  274. sub.prop(con, "max_x", text="")
  275. col = split.column()
  276. col.prop(con, "use_min_y")
  277. sub = col.column()
  278. sub.active = con.use_min_y
  279. sub.prop(con, "min_y", text="")
  280. col.prop(con, "use_max_y")
  281. sub = col.column()
  282. sub.active = con.use_max_y
  283. sub.prop(con, "max_y", text="")
  284. col = split.column()
  285. col.prop(con, "use_min_z")
  286. sub = col.column()
  287. sub.active = con.use_min_z
  288. sub.prop(con, "min_z", text="")
  289. col.prop(con, "use_max_z")
  290. sub = col.column()
  291. sub.active = con.use_max_z
  292. sub.prop(con, "max_z", text="")
  293. row = layout.row()
  294. row.prop(con, "use_transform_limit")
  295. row.label()
  296. row = layout.row()
  297. row.label(text="Convert:")
  298. row.prop(con, "owner_space", text="")
  299. def COPY_ROTATION(self, _context, layout, con):
  300. self.target_template(layout, con)
  301. split = layout.split()
  302. col = split.column()
  303. col.prop(con, "use_x", text="X")
  304. sub = col.column()
  305. sub.active = con.use_x
  306. sub.prop(con, "invert_x", text="Invert")
  307. col = split.column()
  308. col.prop(con, "use_y", text="Y")
  309. sub = col.column()
  310. sub.active = con.use_y
  311. sub.prop(con, "invert_y", text="Invert")
  312. col = split.column()
  313. col.prop(con, "use_z", text="Z")
  314. sub = col.column()
  315. sub.active = con.use_z
  316. sub.prop(con, "invert_z", text="Invert")
  317. layout.prop(con, "use_offset")
  318. self.space_template(layout, con)
  319. def COPY_LOCATION(self, _context, layout, con):
  320. self.target_template(layout, con)
  321. split = layout.split()
  322. col = split.column()
  323. col.prop(con, "use_x", text="X")
  324. sub = col.column()
  325. sub.active = con.use_x
  326. sub.prop(con, "invert_x", text="Invert")
  327. col = split.column()
  328. col.prop(con, "use_y", text="Y")
  329. sub = col.column()
  330. sub.active = con.use_y
  331. sub.prop(con, "invert_y", text="Invert")
  332. col = split.column()
  333. col.prop(con, "use_z", text="Z")
  334. sub = col.column()
  335. sub.active = con.use_z
  336. sub.prop(con, "invert_z", text="Invert")
  337. layout.prop(con, "use_offset")
  338. self.space_template(layout, con)
  339. def COPY_SCALE(self, _context, layout, con):
  340. self.target_template(layout, con)
  341. row = layout.row(align=True)
  342. row.prop(con, "use_x", text="X")
  343. row.prop(con, "use_y", text="Y")
  344. row.prop(con, "use_z", text="Z")
  345. layout.prop(con, "power")
  346. row = layout.row()
  347. row.prop(con, "use_offset")
  348. row = row.row()
  349. row.active = con.use_offset
  350. row.prop(con, "use_add")
  351. self.space_template(layout, con)
  352. def MAINTAIN_VOLUME(self, _context, layout, con):
  353. layout.prop(con, "mode")
  354. row = layout.row()
  355. row.label(text="Free:")
  356. row.prop(con, "free_axis", expand=True)
  357. layout.prop(con, "volume")
  358. row = layout.row()
  359. row.label(text="Convert:")
  360. row.prop(con, "owner_space", text="")
  361. def COPY_TRANSFORMS(self, _context, layout, con):
  362. self.target_template(layout, con)
  363. self.space_template(layout, con)
  364. # def SCRIPT(self, context, layout, con):
  365. def ACTION(self, _context, layout, con):
  366. self.target_template(layout, con)
  367. split = layout.split()
  368. col = split.column()
  369. col.label(text="From Target:")
  370. col.prop(con, "transform_channel", text="")
  371. col.prop(con, "target_space", text="")
  372. col = split.column()
  373. col.label(text="To Action:")
  374. col.prop(con, "action", text="")
  375. col.prop(con, "use_bone_object_action")
  376. split = layout.split()
  377. col = split.column(align=True)
  378. col.label(text="Target Range:")
  379. col.prop(con, "min", text="Min")
  380. col.prop(con, "max", text="Max")
  381. col = split.column(align=True)
  382. col.label(text="Action Range:")
  383. col.prop(con, "frame_start", text="Start")
  384. col.prop(con, "frame_end", text="End")
  385. def LOCKED_TRACK(self, _context, layout, con):
  386. self.target_template(layout, con)
  387. row = layout.row()
  388. row.label(text="To:")
  389. row.prop(con, "track_axis", expand=True)
  390. row = layout.row()
  391. row.label(text="Lock:")
  392. row.prop(con, "lock_axis", expand=True)
  393. def LIMIT_DISTANCE(self, _context, layout, con):
  394. self.target_template(layout, con)
  395. col = layout.column(align=True)
  396. col.prop(con, "distance")
  397. col.operator("constraint.limitdistance_reset")
  398. row = layout.row()
  399. row.label(text="Clamp Region:")
  400. row.prop(con, "limit_mode", text="")
  401. row = layout.row()
  402. row.prop(con, "use_transform_limit")
  403. row.label()
  404. self.space_template(layout, con)
  405. def STRETCH_TO(self, _context, layout, con):
  406. self.target_template(layout, con)
  407. row = layout.row()
  408. row.prop(con, "rest_length", text="Rest Length")
  409. row.operator("constraint.stretchto_reset", text="Reset")
  410. layout.prop(con, "bulge", text="Volume Variation")
  411. split = layout.split()
  412. col = split.column(align=True)
  413. col.prop(con, "use_bulge_min", text="Volume Min")
  414. sub = col.column()
  415. sub.active = con.use_bulge_min
  416. sub.prop(con, "bulge_min", text="")
  417. col = split.column(align=True)
  418. col.prop(con, "use_bulge_max", text="Volume Max")
  419. sub = col.column()
  420. sub.active = con.use_bulge_max
  421. sub.prop(con, "bulge_max", text="")
  422. col = layout.column()
  423. col.active = con.use_bulge_min or con.use_bulge_max
  424. col.prop(con, "bulge_smooth", text="Smooth")
  425. row = layout.row()
  426. row.label(text="Volume:")
  427. row.prop(con, "volume", expand=True)
  428. row.label(text="Plane:")
  429. row.prop(con, "keep_axis", expand=True)
  430. def FLOOR(self, _context, layout, con):
  431. self.target_template(layout, con)
  432. layout.prop(con, "use_rotation")
  433. layout.prop(con, "offset")
  434. row = layout.row()
  435. row.label(text="Min/Max:")
  436. row.prop(con, "floor_location", expand=True)
  437. self.space_template(layout, con)
  438. def RIGID_BODY_JOINT(self, _context, layout, con):
  439. self.target_template(layout, con, subtargets=False)
  440. layout.prop(con, "pivot_type")
  441. layout.prop(con, "child")
  442. row = layout.row()
  443. row.prop(con, "use_linked_collision", text="Linked Collision")
  444. row.prop(con, "show_pivot", text="Display Pivot")
  445. split = layout.split()
  446. col = split.column(align=True)
  447. col.label(text="Pivot:")
  448. col.prop(con, "pivot_x", text="X")
  449. col.prop(con, "pivot_y", text="Y")
  450. col.prop(con, "pivot_z", text="Z")
  451. col = split.column(align=True)
  452. col.label(text="Axis:")
  453. col.prop(con, "axis_x", text="X")
  454. col.prop(con, "axis_y", text="Y")
  455. col.prop(con, "axis_z", text="Z")
  456. if con.pivot_type == 'CONE_TWIST':
  457. layout.label(text="Limits:")
  458. split = layout.split()
  459. col = split.column()
  460. col.prop(con, "use_angular_limit_x", text="Angle X")
  461. sub = col.column()
  462. sub.active = con.use_angular_limit_x
  463. sub.prop(con, "limit_angle_max_x", text="")
  464. col = split.column()
  465. col.prop(con, "use_angular_limit_y", text="Angle Y")
  466. sub = col.column()
  467. sub.active = con.use_angular_limit_y
  468. sub.prop(con, "limit_angle_max_y", text="")
  469. col = split.column()
  470. col.prop(con, "use_angular_limit_z", text="Angle Z")
  471. sub = col.column()
  472. sub.active = con.use_angular_limit_z
  473. sub.prop(con, "limit_angle_max_z", text="")
  474. elif con.pivot_type == 'GENERIC_6_DOF':
  475. layout.label(text="Limits:")
  476. split = layout.split()
  477. col = split.column(align=True)
  478. col.prop(con, "use_limit_x", text="X")
  479. sub = col.column(align=True)
  480. sub.active = con.use_limit_x
  481. sub.prop(con, "limit_min_x", text="Min")
  482. sub.prop(con, "limit_max_x", text="Max")
  483. col = split.column(align=True)
  484. col.prop(con, "use_limit_y", text="Y")
  485. sub = col.column(align=True)
  486. sub.active = con.use_limit_y
  487. sub.prop(con, "limit_min_y", text="Min")
  488. sub.prop(con, "limit_max_y", text="Max")
  489. col = split.column(align=True)
  490. col.prop(con, "use_limit_z", text="Z")
  491. sub = col.column(align=True)
  492. sub.active = con.use_limit_z
  493. sub.prop(con, "limit_min_z", text="Min")
  494. sub.prop(con, "limit_max_z", text="Max")
  495. split = layout.split()
  496. col = split.column(align=True)
  497. col.prop(con, "use_angular_limit_x", text="Angle X")
  498. sub = col.column(align=True)
  499. sub.active = con.use_angular_limit_x
  500. sub.prop(con, "limit_angle_min_x", text="Min")
  501. sub.prop(con, "limit_angle_max_x", text="Max")
  502. col = split.column(align=True)
  503. col.prop(con, "use_angular_limit_y", text="Angle Y")
  504. sub = col.column(align=True)
  505. sub.active = con.use_angular_limit_y
  506. sub.prop(con, "limit_angle_min_y", text="Min")
  507. sub.prop(con, "limit_angle_max_y", text="Max")
  508. col = split.column(align=True)
  509. col.prop(con, "use_angular_limit_z", text="Angle Z")
  510. sub = col.column(align=True)
  511. sub.active = con.use_angular_limit_z
  512. sub.prop(con, "limit_angle_min_z", text="Min")
  513. sub.prop(con, "limit_angle_max_z", text="Max")
  514. elif con.pivot_type == 'HINGE':
  515. layout.label(text="Limits:")
  516. split = layout.split()
  517. row = split.row(align=True)
  518. col = row.column()
  519. col.prop(con, "use_angular_limit_x", text="Angle X")
  520. col = row.column()
  521. col.active = con.use_angular_limit_x
  522. col.prop(con, "limit_angle_min_x", text="Min")
  523. col = row.column()
  524. col.active = con.use_angular_limit_x
  525. col.prop(con, "limit_angle_max_x", text="Max")
  526. def CLAMP_TO(self, _context, layout, con):
  527. self.target_template(layout, con)
  528. row = layout.row()
  529. row.label(text="Main Axis:")
  530. row.prop(con, "main_axis", expand=True)
  531. layout.prop(con, "use_cyclic")
  532. def TRANSFORM(self, _context, layout, con):
  533. self.target_template(layout, con)
  534. layout.prop(con, "use_motion_extrapolate", text="Extrapolate")
  535. col = layout.column()
  536. col.row().label(text="Source:")
  537. col.row().prop(con, "map_from", expand=True)
  538. split = layout.split()
  539. ext = "" if con.map_from == 'LOCATION' else "_rot" if con.map_from == 'ROTATION' else "_scale"
  540. sub = split.column(align=True)
  541. sub.label(text="X:")
  542. sub.prop(con, "from_min_x" + ext, text="Min")
  543. sub.prop(con, "from_max_x" + ext, text="Max")
  544. sub = split.column(align=True)
  545. sub.label(text="Y:")
  546. sub.prop(con, "from_min_y" + ext, text="Min")
  547. sub.prop(con, "from_max_y" + ext, text="Max")
  548. sub = split.column(align=True)
  549. sub.label(text="Z:")
  550. sub.prop(con, "from_min_z" + ext, text="Min")
  551. sub.prop(con, "from_max_z" + ext, text="Max")
  552. col = layout.column()
  553. row = col.row()
  554. row.label(text="Source to Destination Mapping:")
  555. # note: chr(187) is the ASCII arrow ( >> ). Blender Text Editor can't
  556. # open it. Thus we are using the hard-coded value instead.
  557. row = col.row()
  558. row.prop(con, "map_to_x_from", expand=False, text="")
  559. row.label(text=" %s X" % chr(187))
  560. row = col.row()
  561. row.prop(con, "map_to_y_from", expand=False, text="")
  562. row.label(text=" %s Y" % chr(187))
  563. row = col.row()
  564. row.prop(con, "map_to_z_from", expand=False, text="")
  565. row.label(text=" %s Z" % chr(187))
  566. split = layout.split()
  567. col = split.column()
  568. col.label(text="Destination:")
  569. col.row().prop(con, "map_to", expand=True)
  570. split = layout.split()
  571. ext = "" if con.map_to == 'LOCATION' else "_rot" if con.map_to == 'ROTATION' else "_scale"
  572. col = split.column()
  573. col.label(text="X:")
  574. sub = col.column(align=True)
  575. sub.prop(con, "to_min_x" + ext, text="Min")
  576. sub.prop(con, "to_max_x" + ext, text="Max")
  577. col = split.column()
  578. col.label(text="Y:")
  579. sub = col.column(align=True)
  580. sub.prop(con, "to_min_y" + ext, text="Min")
  581. sub.prop(con, "to_max_y" + ext, text="Max")
  582. col = split.column()
  583. col.label(text="Z:")
  584. sub = col.column(align=True)
  585. sub.prop(con, "to_min_z" + ext, text="Min")
  586. sub.prop(con, "to_max_z" + ext, text="Max")
  587. self.space_template(layout, con)
  588. def SHRINKWRAP(self, _context, layout, con):
  589. self.target_template(layout, con, False)
  590. layout.prop(con, "distance")
  591. layout.prop(con, "shrinkwrap_type")
  592. if con.shrinkwrap_type in {'PROJECT', 'NEAREST_SURFACE', 'TARGET_PROJECT'}:
  593. layout.prop(con, "wrap_mode", text="Snap Mode")
  594. if con.shrinkwrap_type == 'PROJECT':
  595. row = layout.row(align=True)
  596. row.prop(con, "project_axis", expand=True)
  597. split = layout.split(factor=0.4)
  598. split.label(text="Axis Space:")
  599. rowsub = split.row()
  600. rowsub.prop(con, "project_axis_space", text="")
  601. split = layout.split(factor=0.4)
  602. split.label(text="Face Culling:")
  603. rowsub = split.row()
  604. rowsub.prop(con, "cull_face", expand=True)
  605. row = layout.row()
  606. row.prop(con, "use_project_opposite")
  607. rowsub = row.row()
  608. rowsub.active = con.use_project_opposite and con.cull_face != 'OFF'
  609. rowsub.prop(con, "use_invert_cull")
  610. layout.prop(con, "project_limit")
  611. if con.shrinkwrap_type in {'PROJECT', 'NEAREST_SURFACE', 'TARGET_PROJECT'}:
  612. layout.prop(con, "use_track_normal")
  613. row = layout.row(align=True)
  614. row.active = con.use_track_normal
  615. row.prop(con, "track_axis", expand=True)
  616. def DAMPED_TRACK(self, _context, layout, con):
  617. self.target_template(layout, con)
  618. row = layout.row()
  619. row.label(text="To:")
  620. row.prop(con, "track_axis", expand=True)
  621. def SPLINE_IK(self, _context, layout, con):
  622. self.target_template(layout, con)
  623. col = layout.column()
  624. col.label(text="Spline Fitting:")
  625. col.prop(con, "chain_count")
  626. col.prop(con, "use_even_divisions")
  627. col.prop(con, "use_chain_offset")
  628. col = layout.column()
  629. col.label(text="Chain Scaling:")
  630. col.prop(con, "use_curve_radius")
  631. layout.prop(con, "y_scale_mode")
  632. layout.prop(con, "xz_scale_mode")
  633. if con.xz_scale_mode in {'INVERSE_PRESERVE', 'VOLUME_PRESERVE'}:
  634. layout.prop(con, "use_original_scale")
  635. if con.xz_scale_mode == 'VOLUME_PRESERVE':
  636. layout.prop(con, "bulge", text="Volume Variation")
  637. split = layout.split()
  638. col = split.column(align=True)
  639. col.prop(con, "use_bulge_min", text="Volume Min")
  640. sub = col.column()
  641. sub.active = con.use_bulge_min
  642. sub.prop(con, "bulge_min", text="")
  643. col = split.column(align=True)
  644. col.prop(con, "use_bulge_max", text="Volume Max")
  645. sub = col.column()
  646. sub.active = con.use_bulge_max
  647. sub.prop(con, "bulge_max", text="")
  648. col = layout.column()
  649. col.active = con.use_bulge_min or con.use_bulge_max
  650. col.prop(con, "bulge_smooth", text="Smooth")
  651. def PIVOT(self, _context, layout, con):
  652. self.target_template(layout, con)
  653. if con.target:
  654. col = layout.column()
  655. col.prop(con, "offset", text="Pivot Offset")
  656. else:
  657. col = layout.column()
  658. col.prop(con, "use_relative_location")
  659. if con.use_relative_location:
  660. col.prop(con, "offset", text="Relative Pivot Point")
  661. else:
  662. col.prop(con, "offset", text="Absolute Pivot Point")
  663. col = layout.column()
  664. col.prop(con, "rotation_range", text="Pivot When")
  665. @staticmethod
  666. def _getConstraintClip(context, con):
  667. if not con.use_active_clip:
  668. return con.clip
  669. else:
  670. return context.scene.active_clip
  671. def FOLLOW_TRACK(self, context, layout, con):
  672. clip = self._getConstraintClip(context, con)
  673. row = layout.row()
  674. row.prop(con, "use_active_clip")
  675. row.prop(con, "use_3d_position")
  676. sub = row.column()
  677. sub.active = not con.use_3d_position
  678. sub.prop(con, "use_undistorted_position")
  679. col = layout.column()
  680. if not con.use_active_clip:
  681. col.prop(con, "clip")
  682. row = col.row()
  683. row.prop(con, "frame_method", expand=True)
  684. if clip:
  685. tracking = clip.tracking
  686. col.prop_search(con, "object", tracking, "objects", icon='OBJECT_DATA')
  687. tracking_object = tracking.objects.get(con.object, tracking.objects[0])
  688. col.prop_search(con, "track", tracking_object, "tracks", icon='ANIM_DATA')
  689. col.prop(con, "camera")
  690. row = col.row()
  691. row.active = not con.use_3d_position
  692. row.prop(con, "depth_object")
  693. layout.operator("clip.constraint_to_fcurve")
  694. def CAMERA_SOLVER(self, _context, layout, con):
  695. layout.prop(con, "use_active_clip")
  696. if not con.use_active_clip:
  697. layout.prop(con, "clip")
  698. layout.operator("clip.constraint_to_fcurve")
  699. def OBJECT_SOLVER(self, context, layout, con):
  700. clip = self._getConstraintClip(context, con)
  701. layout.prop(con, "use_active_clip")
  702. if not con.use_active_clip:
  703. layout.prop(con, "clip")
  704. if clip:
  705. layout.prop_search(con, "object", clip.tracking, "objects", icon='OBJECT_DATA')
  706. layout.prop(con, "camera")
  707. row = layout.row()
  708. row.operator("constraint.objectsolver_set_inverse")
  709. row.operator("constraint.objectsolver_clear_inverse")
  710. layout.operator("clip.constraint_to_fcurve")
  711. def TRANSFORM_CACHE(self, _context, layout, con):
  712. layout.label(text="Cache File Properties:")
  713. box = layout.box()
  714. box.template_cache_file(con, "cache_file")
  715. cache_file = con.cache_file
  716. layout.label(text="Constraint Properties:")
  717. box = layout.box()
  718. if cache_file is not None:
  719. box.prop_search(con, "object_path", cache_file, "object_paths")
  720. def SCRIPT(self, _context, layout, _con):
  721. layout.label(text="Blender 2.6 doesn't support python constraints yet")
  722. def ARMATURE(self, context, layout, con):
  723. topcol = layout.column()
  724. topcol.use_property_split = True
  725. topcol.operator("constraint.add_target", text="Add Target Bone")
  726. if not con.targets:
  727. box = topcol.box()
  728. box.label(text="No target bones were added", icon='ERROR')
  729. for i, tgt in enumerate(con.targets):
  730. box = topcol.box()
  731. has_target = tgt.target is not None
  732. header = box.row()
  733. header.use_property_split = False
  734. split = header.split(factor=0.45, align=True)
  735. split.prop(tgt, "target", text="")
  736. row = split.row(align=True)
  737. row.active = has_target
  738. if has_target:
  739. row.prop_search(tgt, "subtarget", tgt.target.data, "bones", text="")
  740. else:
  741. row.prop(tgt, "subtarget", text="", icon='BONE_DATA')
  742. header.operator("constraint.remove_target", text="", icon='REMOVE').index = i
  743. col = box.column()
  744. col.active = has_target and tgt.subtarget != ""
  745. col.prop(tgt, "weight", slider=True)
  746. topcol.operator("constraint.normalize_target_weights")
  747. topcol.prop(con, "use_deform_preserve_volume")
  748. topcol.prop(con, "use_bone_envelopes")
  749. if context.pose_bone:
  750. topcol.prop(con, "use_current_location")
  751. class OBJECT_PT_constraints(ConstraintButtonsPanel, Panel):
  752. bl_label = "Object Constraints"
  753. bl_context = "constraint"
  754. bl_options = {'HIDE_HEADER'}
  755. @classmethod
  756. def poll(cls, context):
  757. return (context.object)
  758. def draw(self, context):
  759. layout = self.layout
  760. obj = context.object
  761. layout.operator_menu_enum("object.constraint_add", "type", text="Add Object Constraint")
  762. for con in obj.constraints:
  763. self.draw_constraint(context, con)
  764. class BONE_PT_constraints(ConstraintButtonsPanel, Panel):
  765. bl_label = "Bone Constraints"
  766. bl_context = "bone_constraint"
  767. bl_options = {'HIDE_HEADER'}
  768. @classmethod
  769. def poll(cls, context):
  770. return (context.pose_bone)
  771. def draw(self, context):
  772. layout = self.layout
  773. layout.operator_menu_enum("pose.constraint_add", "type", text="Add Bone Constraint")
  774. for con in context.pose_bone.constraints:
  775. self.draw_constraint(context, con)
  776. classes = (
  777. OBJECT_PT_constraints,
  778. BONE_PT_constraints,
  779. )
  780. if __name__ == "__main__": # only for live edit.
  781. from bpy.utils import register_class
  782. for cls in classes:
  783. register_class(cls)