poll() as a python '@staticmethod' was too limiting and didnt allow useful base class...
[blender.git] / release / scripts / ui / properties_particle.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 compliant>
20 import bpy
21 from rna_prop_ui import PropertyPanel
22
23 from properties_physics_common import point_cache_ui
24 from properties_physics_common import effector_weights_ui
25 from properties_physics_common import basic_force_field_settings_ui
26 from properties_physics_common import basic_force_field_falloff_ui
27
28
29 def particle_panel_enabled(context, psys):
30     return (psys.point_cache.baked is False) and (not psys.edited) and (not context.particle_system_editable)
31
32
33 def particle_panel_poll(cls, context):
34     psys = context.particle_system
35     engine = context.scene.render.engine
36     if psys is None:
37         return False
38     if psys.settings is None:
39         return False
40     return psys.settings.type in ('EMITTER', 'REACTOR', 'HAIR') and (engine in cls.COMPAT_ENGINES)
41
42
43 class ParticleButtonsPanel():
44     bl_space_type = 'PROPERTIES'
45     bl_region_type = 'WINDOW'
46     bl_context = "particle"
47
48     @classmethod
49     def poll(cls, context):
50         return particle_panel_poll(cls, context)
51
52
53 class PARTICLE_PT_context_particles(ParticleButtonsPanel, bpy.types.Panel):
54     bl_label = ""
55     bl_show_header = False
56     COMPAT_ENGINES = {'BLENDER_RENDER'}
57
58     @classmethod
59     def poll(cls, context):
60         engine = context.scene.render.engine
61         return (context.particle_system or context.object) and (engine in cls.COMPAT_ENGINES)
62
63     def draw(self, context):
64         layout = self.layout
65
66         ob = context.object
67         psys = context.particle_system
68
69         if ob:
70             row = layout.row()
71
72             row.template_list(ob, "particle_systems", ob, "active_particle_system_index", rows=2)
73
74             col = row.column(align=True)
75             col.operator("object.particle_system_add", icon='ZOOMIN', text="")
76             col.operator("object.particle_system_remove", icon='ZOOMOUT', text="")
77
78         if psys and not psys.settings:
79             split = layout.split(percentage=0.32)
80
81             col = split.column()
82             col.label(text="Name:")
83             col.label(text="Settings:")
84
85             col = split.column()
86             col.prop(psys, "name", text="")
87             col.template_ID(psys, "settings", new="particle.new")
88         elif psys:
89             part = psys.settings
90
91             split = layout.split(percentage=0.32)
92             col = split.column()
93             col.label(text="Name:")
94             if part.type in ('EMITTER', 'REACTOR', 'HAIR'):
95                 col.label(text="Settings:")
96                 col.label(text="Type:")
97
98             col = split.column()
99             col.prop(psys, "name", text="")
100             if part.type in ('EMITTER', 'REACTOR', 'HAIR'):
101                 col.template_ID(psys, "settings", new="particle.new")
102
103             #row = layout.row()
104             #row.label(text="Viewport")
105             #row.label(text="Render")
106
107             if part:
108                 if part.type not in ('EMITTER', 'REACTOR', 'HAIR'):
109                     layout.label(text="No settings for fluid particles")
110                     return
111
112                 row = col.row()
113                 row.enabled = particle_panel_enabled(context, psys)
114                 row.prop(part, "type", text="")
115                 row.prop(psys, "seed")
116
117                 split = layout.split(percentage=0.65)
118                 if part.type == 'HAIR':
119                     if psys.edited:
120                         split.operator("particle.edited_clear", text="Free Edit")
121                     else:
122                         split.label(text="")
123                     row = split.row()
124                     row.enabled = particle_panel_enabled(context, psys)
125                     row.prop(part, "hair_step")
126                     if psys.edited:
127                         if psys.global_hair:
128                             layout.operator("particle.connect_hair")
129                             layout.label(text="Hair is disconnected.")
130                         else:
131                             layout.operator("particle.disconnect_hair")
132                             layout.label(text="")
133                 elif part.type == 'REACTOR':
134                     split.enabled = particle_panel_enabled(context, psys)
135                     split.prop(psys, "reactor_target_object")
136                     split.prop(psys, "reactor_target_particle_system", text="Particle System")
137
138
139 class PARTICLE_PT_custom_props(ParticleButtonsPanel, PropertyPanel, bpy.types.Panel):
140     COMPAT_ENGINES = {'BLENDER_RENDER'}
141     _context_path = "particle_system.settings"
142
143
144 class PARTICLE_PT_emission(ParticleButtonsPanel, bpy.types.Panel):
145     bl_label = "Emission"
146     COMPAT_ENGINES = {'BLENDER_RENDER'}
147
148     @classmethod
149     def poll(cls, context):
150         if particle_panel_poll(PARTICLE_PT_emission, context):
151             return not context.particle_system.point_cache.external
152         else:
153             return False
154
155     def draw(self, context):
156         layout = self.layout
157
158         psys = context.particle_system
159         part = psys.settings
160
161         layout.enabled = particle_panel_enabled(context, psys) and not psys.multiple_caches
162
163         row = layout.row()
164         row.active = part.distribution != 'GRID'
165         row.prop(part, "amount")
166
167         if part.type != 'HAIR':
168             split = layout.split()
169
170             col = split.column(align=True)
171             col.prop(part, "frame_start")
172             col.prop(part, "frame_end")
173
174             col = split.column(align=True)
175             col.prop(part, "lifetime")
176             col.prop(part, "random_lifetime", slider=True)
177
178         layout.row().label(text="Emit From:")
179
180         row = layout.row()
181         row.prop(part, "emit_from", expand=True)
182
183         row = layout.row()
184         row.prop(part, "trand")
185         if part.distribution != 'GRID':
186             row.prop(part, "even_distribution")
187
188         if part.emit_from == 'FACE' or part.emit_from == 'VOLUME':
189             row = layout.row()
190
191             row.prop(part, "distribution", expand=True)
192
193             row = layout.row()
194
195             if part.distribution == 'JIT':
196                 row.prop(part, "userjit", text="Particles/Face")
197                 row.prop(part, "jitter_factor", text="Jittering Amount", slider=True)
198             elif part.distribution == 'GRID':
199                 row.prop(part, "grid_resolution")
200
201
202 class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel, bpy.types.Panel):
203     bl_label = "Hair dynamics"
204     bl_default_closed = True
205     COMPAT_ENGINES = {'BLENDER_RENDER'}
206
207     @classmethod
208     def poll(cls, context):
209         psys = context.particle_system
210         engine = context.scene.render.engine
211         if psys is None:
212             return False
213         if psys.settings is None:
214             return False
215         return psys.settings.type == 'HAIR' and (engine in cls.COMPAT_ENGINES)
216
217     def draw_header(self, context):
218         #cloth = context.cloth.collision_settings
219
220         #self.layout.active = cloth_panel_enabled(context.cloth)
221         #self.layout.prop(cloth, "enable_collision", text="")
222         psys = context.particle_system
223         self.layout.prop(psys, "hair_dynamics", text="")
224
225     def draw(self, context):
226         layout = self.layout
227
228         psys = context.particle_system
229
230         if not psys.cloth:
231             return
232
233         #part = psys.settings
234         cloth = psys.cloth.settings
235
236         layout.enabled = psys.hair_dynamics
237
238         split = layout.split()
239
240         col = split.column()
241         col.label(text="Material:")
242         sub = col.column(align=True)
243         sub.prop(cloth, "pin_stiffness", text="Stiffness")
244         sub.prop(cloth, "mass")
245         sub.prop(cloth, "bending_stiffness", text="Bending")
246         sub.prop(cloth, "internal_friction", slider=True)
247         sub.prop(cloth, "collider_friction", slider=True)
248
249         col = split.column()
250
251         col.label(text="Damping:")
252         sub = col.column(align=True)
253         sub.prop(cloth, "spring_damping", text="Spring")
254         sub.prop(cloth, "air_damping", text="Air")
255
256         col.label(text="Quality:")
257         col.prop(cloth, "quality", text="Steps", slider=True)
258
259
260 class PARTICLE_PT_cache(ParticleButtonsPanel, bpy.types.Panel):
261     bl_label = "Cache"
262     bl_default_closed = True
263     COMPAT_ENGINES = {'BLENDER_RENDER'}
264
265     @classmethod
266     def poll(cls, context):
267         psys = context.particle_system
268         engine = context.scene.render.engine
269         if psys is None:
270             return False
271         if psys.settings is None:
272             return False
273         phystype = psys.settings.physics_type
274         if phystype == 'NO' or phystype == 'KEYED':
275             return False
276         return (psys.settings.type in ('EMITTER', 'REACTOR') or (psys.settings.type == 'HAIR' and psys.hair_dynamics)) and engine in cls.COMPAT_ENGINES
277
278     def draw(self, context):
279         psys = context.particle_system
280
281         point_cache_ui(self, context, psys.point_cache, True, 'HAIR' if psys.hair_dynamics else 'PSYS')
282
283
284 class PARTICLE_PT_velocity(ParticleButtonsPanel, bpy.types.Panel):
285     bl_label = "Velocity"
286     COMPAT_ENGINES = {'BLENDER_RENDER'}
287
288     @classmethod
289     def poll(cls, context):
290         if particle_panel_poll(PARTICLE_PT_velocity, context):
291             psys = context.particle_system
292             return psys.settings.physics_type != 'BOIDS' and not psys.point_cache.external
293         else:
294             return False
295
296     def draw(self, context):
297         layout = self.layout
298
299         psys = context.particle_system
300         part = psys.settings
301
302         layout.enabled = particle_panel_enabled(context, psys)
303
304         split = layout.split()
305
306         sub = split.column()
307         sub.label(text="Emitter Geometry:")
308         sub.prop(part, "normal_factor")
309         subsub = sub.column(align=True)
310         subsub.prop(part, "tangent_factor")
311         subsub.prop(part, "tangent_phase", slider=True)
312
313         sub = split.column()
314         sub.label(text="Emitter Object")
315         sub.prop(part, "object_aligned_factor", text="")
316
317         layout.row().label(text="Other:")
318         split = layout.split()
319         sub = split.column()
320         if part.emit_from == 'PARTICLE':
321             sub.prop(part, "particle_factor")
322         else:
323             sub.prop(part, "object_factor", slider=True)
324         sub = split.column()
325         sub.prop(part, "random_factor")
326
327         #if part.type=='REACTOR':
328         #    sub.prop(part, "reactor_factor")
329         #    sub.prop(part, "reaction_shape", slider=True)
330
331
332 class PARTICLE_PT_rotation(ParticleButtonsPanel, bpy.types.Panel):
333     bl_label = "Rotation"
334     COMPAT_ENGINES = {'BLENDER_RENDER'}
335
336     @classmethod
337     def poll(cls, context):
338         if particle_panel_poll(PARTICLE_PT_rotation, context):
339             psys = context.particle_system
340             return psys.settings.physics_type != 'BOIDS' and not psys.point_cache.external
341         else:
342             return False
343
344     def draw(self, context):
345         layout = self.layout
346
347         psys = context.particle_system
348         part = psys.settings
349
350         layout.enabled = particle_panel_enabled(context, psys)
351
352         split = layout.split()
353         split.label(text="Initial Rotation:")
354         split.prop(part, "rotation_dynamic")
355         split = layout.split()
356
357         sub = split.column(align=True)
358         sub.prop(part, "rotation_mode", text="")
359         sub.prop(part, "random_rotation_factor", slider=True, text="Random")
360
361         sub = split.column(align=True)
362         sub.prop(part, "phase_factor", slider=True)
363         sub.prop(part, "random_phase_factor", text="Random", slider=True)
364
365         layout.row().label(text="Angular Velocity:")
366         layout.row().prop(part, "angular_velocity_mode", expand=True)
367         split = layout.split()
368
369         sub = split.column()
370
371         if part.angular_velocity_mode != 'NONE':
372             sub.prop(part, "angular_velocity_factor", text="")
373
374
375 class PARTICLE_PT_physics(ParticleButtonsPanel, bpy.types.Panel):
376     bl_label = "Physics"
377     COMPAT_ENGINES = {'BLENDER_RENDER'}
378
379     @classmethod
380     def poll(cls, context):
381         if particle_panel_poll(PARTICLE_PT_physics, context):
382             return not context.particle_system.point_cache.external
383         else:
384             return False
385
386     def draw(self, context):
387         layout = self.layout
388
389         psys = context.particle_system
390         part = psys.settings
391
392         layout.enabled = particle_panel_enabled(context, psys)
393
394         row = layout.row()
395         row.prop(part, "physics_type", expand=True)
396
397         row = layout.row()
398         col = row.column(align=True)
399         col.prop(part, "particle_size")
400         col.prop(part, "random_size", slider=True)
401
402         if part.physics_type != 'NO':
403             col = row.column(align=True)
404             col.prop(part, "mass")
405             col.prop(part, "sizemass", text="Multiply mass with size")
406
407         if part.physics_type == 'NEWTON':
408             split = layout.split()
409             sub = split.column()
410
411             sub.label(text="Forces:")
412             sub.prop(part, "brownian_factor")
413             sub.prop(part, "drag_factor", slider=True)
414             sub.prop(part, "damp_factor", slider=True)
415             sub = split.column()
416             sub.label(text="Integration:")
417             sub.prop(part, "integrator", text="")
418             sub.prop(part, "time_tweak")
419             sub.prop(part, "subframes")
420             sub = layout.row()
421             sub.prop(part, "size_deflect")
422             sub.prop(part, "die_on_collision")
423
424         elif part.physics_type == 'FLUID':
425             fluid = part.fluid
426             split = layout.split()
427             sub = split.column()
428
429             sub.label(text="Forces:")
430             sub.prop(part, "brownian_factor")
431             sub.prop(part, "drag_factor", slider=True)
432             sub.prop(part, "damp_factor", slider=True)
433             sub = split.column()
434             sub.label(text="Integration:")
435             sub.prop(part, "integrator", text="")
436             sub.prop(part, "time_tweak")
437             sub.prop(part, "subframes")
438             sub = layout.row()
439             sub.prop(part, "size_deflect")
440             sub.prop(part, "die_on_collision")
441
442             split = layout.split()
443             sub = split.column()
444             sub.label(text="Fluid Interaction:")
445             sub.prop(fluid, "fluid_radius", slider=True)
446             sub.prop(fluid, "stiffness_k")
447             sub.prop(fluid, "stiffness_knear")
448             sub.prop(fluid, "rest_density")
449
450             sub.label(text="Viscosity:")
451             sub.prop(fluid, "viscosity_omega", text="Linear")
452             sub.prop(fluid, "viscosity_beta", text="Square")
453
454             sub = split.column()
455
456             sub.label(text="Springs:")
457             sub.prop(fluid, "spring_k", text="Force", slider=True)
458             sub.prop(fluid, "rest_length", slider=True)
459             layout.label(text="Multiple fluids interactions:")
460
461             sub.label(text="Buoyancy:")
462             sub.prop(fluid, "buoyancy", slider=True)
463
464         elif part.physics_type == 'KEYED':
465             split = layout.split()
466             sub = split.column()
467
468             row = layout.row()
469             col = row.column()
470             col.active = not psys.keyed_timing
471             col.prop(part, "keyed_loops", text="Loops")
472             row.prop(psys, "keyed_timing", text="Use Timing")
473
474             layout.label(text="Keys:")
475         elif part.physics_type == 'BOIDS':
476             boids = part.boids
477
478
479             row = layout.row()
480             row.prop(boids, "allow_flight")
481             row.prop(boids, "allow_land")
482             row.prop(boids, "allow_climb")
483
484             split = layout.split()
485
486             sub = split.column()
487             col = sub.column(align=True)
488             col.active = boids.allow_flight
489             col.prop(boids, "air_max_speed")
490             col.prop(boids, "air_min_speed", slider=True)
491             col.prop(boids, "air_max_acc", slider=True)
492             col.prop(boids, "air_max_ave", slider=True)
493             col.prop(boids, "air_personal_space")
494             row = col.row()
495             row.active = (boids.allow_land or boids.allow_climb) and boids.allow_flight
496             row.prop(boids, "landing_smoothness")
497
498             sub = split.column()
499             col = sub.column(align=True)
500             col.active = boids.allow_land or boids.allow_climb
501             col.prop(boids, "land_max_speed")
502             col.prop(boids, "land_jump_speed")
503             col.prop(boids, "land_max_acc", slider=True)
504             col.prop(boids, "land_max_ave", slider=True)
505             col.prop(boids, "land_personal_space")
506             col.prop(boids, "land_stick_force")
507
508             row = layout.row()
509
510             col = row.column(align=True)
511             col.label(text="Battle:")
512             col.prop(boids, "health")
513             col.prop(boids, "strength")
514             col.prop(boids, "aggression")
515             col.prop(boids, "accuracy")
516             col.prop(boids, "range")
517
518             col = row.column()
519             col.label(text="Misc:")
520             col.prop(boids, "banking", slider=True)
521             col.prop(boids, "height", slider=True)
522
523         if part.physics_type == 'KEYED' or part.physics_type == 'BOIDS' or part.physics_type == 'FLUID':
524             if part.physics_type == 'BOIDS':
525                 layout.label(text="Relations:")
526
527             row = layout.row()
528             row.template_list(psys, "targets", psys, "active_particle_target_index")
529
530             col = row.column()
531             sub = col.row()
532             subsub = sub.column(align=True)
533             subsub.operator("particle.new_target", icon='ZOOMIN', text="")
534             subsub.operator("particle.target_remove", icon='ZOOMOUT', text="")
535             sub = col.row()
536             subsub = sub.column(align=True)
537             subsub.operator("particle.target_move_up", icon='MOVE_UP_VEC', text="")
538             subsub.operator("particle.target_move_down", icon='MOVE_DOWN_VEC', text="")
539
540             key = psys.active_particle_target
541             if key:
542                 row = layout.row()
543                 if part.physics_type == 'KEYED':
544                     col = row.column()
545                     #doesn't work yet
546                     #col.red_alert = key.valid
547                     col.prop(key, "object", text="")
548                     col.prop(key, "system", text="System")
549                     col = row.column()
550                     col.active = psys.keyed_timing
551                     col.prop(key, "time")
552                     col.prop(key, "duration")
553                 elif part.physics_type == 'BOIDS':
554                     sub = row.row()
555                     #doesn't work yet
556                     #sub.red_alert = key.valid
557                     sub.prop(key, "object", text="")
558                     sub.prop(key, "system", text="System")
559
560                     layout.prop(key, "mode", expand=True)
561                 elif part.physics_type == 'FLUID':
562                     sub = row.row()
563                     #doesn't work yet
564                     #sub.red_alert = key.valid
565                     sub.prop(key, "object", text="")
566                     sub.prop(key, "system", text="System")
567
568
569 class PARTICLE_PT_boidbrain(ParticleButtonsPanel, bpy.types.Panel):
570     bl_label = "Boid Brain"
571     COMPAT_ENGINES = {'BLENDER_RENDER'}
572
573     @classmethod
574     def poll(cls, context):
575         psys = context.particle_system
576         engine = context.scene.render.engine
577         if psys is None:
578             return False
579         if psys.settings is None:
580             return False
581         if psys.point_cache.external:
582             return False
583         return psys.settings.physics_type == 'BOIDS' and engine in cls.COMPAT_ENGINES
584
585     def draw(self, context):
586         layout = self.layout
587
588         boids = context.particle_system.settings.boids
589
590         layout.enabled = particle_panel_enabled(context, context.particle_system)
591
592         # Currently boids can only use the first state so these are commented out for now.
593         #row = layout.row()
594         #row.template_list(boids, "states", boids, "active_boid_state_index", compact="True")
595         #col = row.row()
596         #sub = col.row(align=True)
597         #sub.operator("boid.state_add", icon='ZOOMIN', text="")
598         #sub.operator("boid.state_del", icon='ZOOMOUT', text="")
599         #sub = row.row(align=True)
600         #sub.operator("boid.state_move_up", icon='MOVE_UP_VEC', text="")
601         #sub.operator("boid.state_move_down", icon='MOVE_DOWN_VEC', text="")
602
603         state = boids.active_boid_state
604
605         #layout.prop(state, "name", text="State name")
606
607         row = layout.row()
608         row.prop(state, "ruleset_type")
609         if state.ruleset_type == 'FUZZY':
610             row.prop(state, "rule_fuzziness", slider=True)
611         else:
612             row.label(text="")
613
614         row = layout.row()
615         row.template_list(state, "rules", state, "active_boid_rule_index")
616
617         col = row.column()
618         sub = col.row()
619         subsub = sub.column(align=True)
620         subsub.operator_menu_enum("boid.rule_add", "type", icon='ZOOMIN', text="")
621         subsub.operator("boid.rule_del", icon='ZOOMOUT', text="")
622         sub = col.row()
623         subsub = sub.column(align=True)
624         subsub.operator("boid.rule_move_up", icon='MOVE_UP_VEC', text="")
625         subsub.operator("boid.rule_move_down", icon='MOVE_DOWN_VEC', text="")
626
627         rule = state.active_boid_rule
628
629         if rule:
630             row = layout.row()
631             row.prop(rule, "name", text="")
632             #somebody make nice icons for boids here please! -jahka
633             row.prop(rule, "in_air", icon='MOVE_UP_VEC', text="")
634             row.prop(rule, "on_land", icon='MOVE_DOWN_VEC', text="")
635
636             row = layout.row()
637
638             if rule.type == 'GOAL':
639                 row.prop(rule, "object")
640                 row = layout.row()
641                 row.prop(rule, "predict")
642             elif rule.type == 'AVOID':
643                 row.prop(rule, "object")
644                 row = layout.row()
645                 row.prop(rule, "predict")
646                 row.prop(rule, "fear_factor")
647             elif rule.type == 'FOLLOW_PATH':
648                 row.label(text="Not yet functional.")
649             elif rule.type == 'AVOID_COLLISION':
650                 row.prop(rule, "boids")
651                 row.prop(rule, "deflectors")
652                 row.prop(rule, "look_ahead")
653             elif rule.type == 'FOLLOW_LEADER':
654                 row.prop(rule, "object", text="")
655                 row.prop(rule, "distance")
656                 row = layout.row()
657                 row.prop(rule, "line")
658                 sub = row.row()
659                 sub.active = rule.line
660                 sub.prop(rule, "queue_size")
661             elif rule.type == 'AVERAGE_SPEED':
662                 row.prop(rule, "speed", slider=True)
663                 row.prop(rule, "wander", slider=True)
664                 row.prop(rule, "level", slider=True)
665             elif rule.type == 'FIGHT':
666                 row.prop(rule, "distance")
667                 row.prop(rule, "flee_distance")
668
669
670 class PARTICLE_PT_render(ParticleButtonsPanel, bpy.types.Panel):
671     bl_label = "Render"
672     COMPAT_ENGINES = {'BLENDER_RENDER'}
673
674     @classmethod
675     def poll(cls, context):
676         psys = context.particle_system
677         engine = context.scene.render.engine
678         if psys is None:
679             return False
680         if psys.settings is None:
681             return False
682         return engine in cls.COMPAT_ENGINES
683
684     def draw(self, context):
685         layout = self.layout
686
687         psys = context.particle_system
688         part = psys.settings
689
690         row = layout.row()
691         row.prop(part, "material")
692         row.prop(psys, "parent")
693
694         split = layout.split()
695
696         sub = split.column()
697         sub.prop(part, "emitter")
698         sub.prop(part, "parent")
699         sub = split.column()
700         sub.prop(part, "unborn")
701         sub.prop(part, "died")
702
703         row = layout.row()
704         row.prop(part, "ren_as", expand=True)
705
706         split = layout.split()
707
708         sub = split.column()
709
710         if part.ren_as == 'LINE':
711             sub.prop(part, "line_length_tail")
712             sub.prop(part, "line_length_head")
713             sub = split.column()
714             sub.prop(part, "velocity_length")
715         elif part.ren_as == 'PATH':
716             sub.prop(part, "render_strand")
717             subsub = sub.column()
718             subsub.active = (part.render_strand is False)
719             subsub.prop(part, "render_adaptive")
720             subsub = sub.column()
721             subsub.active = part.render_adaptive or part.render_strand == True
722             subsub.prop(part, "adaptive_angle")
723             subsub = sub.column()
724             subsub.active = (part.render_adaptive is True and part.render_strand is False)
725             subsub.prop(part, "adaptive_pix")
726             sub.prop(part, "hair_bspline")
727             sub.prop(part, "render_step", text="Steps")
728
729             sub = split.column()
730             sub.label(text="Timing:")
731             sub.prop(part, "abs_path_time")
732             sub.prop(part, "path_start", text="Start", slider=not part.abs_path_time)
733             sub.prop(part, "path_end", text="End", slider=not part.abs_path_time)
734             sub.prop(part, "random_length", text="Random", slider=True)
735
736             row = layout.row()
737             col = row.column()
738
739             if part.type == 'HAIR' and part.render_strand == True and part.child_type == 'FACES':
740                 layout.prop(part, "enable_simplify")
741                 if part.enable_simplify == True:
742                     row = layout.row()
743                     row.prop(part, "simplify_refsize")
744                     row.prop(part, "simplify_rate")
745                     row.prop(part, "simplify_transition")
746                     row = layout.row()
747                     row.prop(part, "viewport")
748                     sub = row.row()
749                     sub.active = part.viewport == True
750                     sub.prop(part, "simplify_viewport")
751
752         elif part.ren_as == 'OBJECT':
753             sub.prop(part, "dupli_object")
754             sub.prop(part, "use_global_dupli")
755         elif part.ren_as == 'GROUP':
756             sub.prop(part, "dupli_group")
757             split = layout.split()
758             sub = split.column()
759             sub.prop(part, "whole_group")
760             subsub = sub.column()
761             subsub.active = (part.whole_group is False)
762             subsub.prop(part, "use_group_count")
763
764             sub = split.column()
765             subsub = sub.column()
766             subsub.active = (part.whole_group is False)
767             subsub.prop(part, "use_global_dupli")
768             subsub.prop(part, "rand_group")
769
770             if part.use_group_count and not part.whole_group:
771                 row = layout.row()
772                 row.template_list(part, "dupliweights", part, "active_dupliweight_index")
773
774                 col = row.column()
775                 sub = col.row()
776                 subsub = sub.column(align=True)
777                 subsub.operator("particle.dupliob_copy", icon='ZOOMIN', text="")
778                 subsub.operator("particle.dupliob_remove", icon='ZOOMOUT', text="")
779                 subsub.operator("particle.dupliob_move_up", icon='MOVE_UP_VEC', text="")
780                 subsub.operator("particle.dupliob_move_down", icon='MOVE_DOWN_VEC', text="")
781
782                 weight = part.active_dupliweight
783                 if weight:
784                     row = layout.row()
785                     row.prop(weight, "count")
786
787         elif part.ren_as == 'BILLBOARD':
788             sub.label(text="Align:")
789
790             row = layout.row()
791             row.prop(part, "billboard_align", expand=True)
792             row.prop(part, "billboard_lock", text="Lock")
793             row = layout.row()
794             row.prop(part, "billboard_object")
795
796             row = layout.row()
797             col = row.column(align=True)
798             col.label(text="Tilt:")
799             col.prop(part, "billboard_tilt", text="Angle", slider=True)
800             col.prop(part, "billboard_random_tilt", slider=True)
801             col = row.column()
802             col.prop(part, "billboard_offset")
803
804             row = layout.row()
805             row.prop(psys, "billboard_normal_uv")
806             row = layout.row()
807             row.prop(psys, "billboard_time_index_uv")
808
809             row = layout.row()
810             row.label(text="Split uv's:")
811             row.prop(part, "billboard_uv_split", text="Number of splits")
812             row = layout.row()
813             row.prop(psys, "billboard_split_uv")
814             row = layout.row()
815             row.label(text="Animate:")
816             row.prop(part, "billboard_animation", text="")
817             row.label(text="Offset:")
818             row.prop(part, "billboard_split_offset", text="")
819
820         if part.ren_as == 'HALO' or part.ren_as == 'LINE' or part.ren_as == 'BILLBOARD':
821             row = layout.row()
822             col = row.column()
823             col.prop(part, "trail_count")
824             if part.trail_count > 1:
825                 col.prop(part, "abs_path_time", text="Length in frames")
826                 col = row.column()
827                 col.prop(part, "path_end", text="Length", slider=not part.abs_path_time)
828                 col.prop(part, "random_length", text="Random", slider=True)
829             else:
830                 col = row.column()
831                 col.label(text="")
832
833
834 class PARTICLE_PT_draw(ParticleButtonsPanel, bpy.types.Panel):
835     bl_label = "Display"
836     bl_default_closed = True
837     COMPAT_ENGINES = {'BLENDER_RENDER'}
838
839     @classmethod
840     def poll(cls, context):
841         psys = context.particle_system
842         engine = context.scene.render.engine
843         if psys is None:
844             return False
845         if psys.settings is None:
846             return False
847         return engine in cls.COMPAT_ENGINES
848
849     def draw(self, context):
850         layout = self.layout
851
852         psys = context.particle_system
853         part = psys.settings
854
855         row = layout.row()
856         row.prop(part, "draw_as", expand=True)
857
858         if part.draw_as == 'NONE' or (part.ren_as == 'NONE' and part.draw_as == 'RENDER'):
859             return
860
861         path = (part.ren_as == 'PATH' and part.draw_as == 'RENDER') or part.draw_as == 'PATH'
862
863         row = layout.row()
864         row.prop(part, "display", slider=True)
865         if part.draw_as != 'RENDER' or part.ren_as == 'HALO':
866             row.prop(part, "draw_size")
867         else:
868             row.label(text="")
869
870         row = layout.row()
871         col = row.column()
872         col.prop(part, "show_size")
873         col.prop(part, "velocity")
874         col.prop(part, "num")
875         if part.physics_type == 'BOIDS':
876             col.prop(part, "draw_health")
877
878         col = row.column()
879         col.prop(part, "material_color", text="Use material color")
880
881         if (path):
882             col.prop(part, "draw_step")
883         else:
884             sub = col.column()
885             sub.active = (part.material_color is False)
886             #sub.label(text="color")
887             #sub.label(text="Override material color")
888
889
890 class PARTICLE_PT_children(ParticleButtonsPanel, bpy.types.Panel):
891     bl_label = "Children"
892     bl_default_closed = True
893     COMPAT_ENGINES = {'BLENDER_RENDER'}
894
895     @classmethod
896     def poll(cls, context):
897         return particle_panel_poll(cls, context)
898
899     def draw(self, context):
900         layout = self.layout
901
902         psys = context.particle_system
903         part = psys.settings
904
905         layout.row().prop(part, "child_type", expand=True)
906
907         if part.child_type == 'NONE':
908             return
909
910         row = layout.row()
911
912         col = row.column(align=True)
913         col.prop(part, "child_nbr", text="Display")
914         col.prop(part, "rendered_child_nbr", text="Render")
915
916         col = row.column(align=True)
917
918         if part.child_type == 'FACES':
919             col.prop(part, "virtual_parents", slider=True)
920         else:
921             col.prop(part, "child_radius", text="Radius")
922             col.prop(part, "child_roundness", text="Roundness", slider=True)
923
924             col = row.column(align=True)
925             col.prop(part, "child_size", text="Size")
926             col.prop(part, "child_random_size", text="Random")
927
928         layout.row().label(text="Effects:")
929
930         row = layout.row()
931
932         col = row.column(align=True)
933         col.prop(part, "clump_factor", slider=True)
934         col.prop(part, "clumppow", slider=True)
935
936         col = row.column(align=True)
937         col.prop(part, "rough_endpoint")
938         col.prop(part, "rough_end_shape")
939
940         row = layout.row()
941
942         col = row.column(align=True)
943         col.prop(part, "rough1")
944         col.prop(part, "rough1_size")
945
946         col = row.column(align=True)
947         col.prop(part, "rough2")
948         col.prop(part, "rough2_size")
949         col.prop(part, "rough2_thres", slider=True)
950
951         row = layout.row()
952         col = row.column(align=True)
953         col.prop(part, "child_length", slider=True)
954         col.prop(part, "child_length_thres", slider=True)
955
956         col = row.column(align=True)
957         col.label(text="Space reserved for")
958         col.label(text="hair parting controls")
959
960         layout.row().label(text="Kink:")
961         layout.row().prop(part, "kink", expand=True)
962
963         split = layout.split()
964
965         col = split.column()
966         col.prop(part, "kink_amplitude")
967         col.prop(part, "kink_frequency")
968         col = split.column()
969         col.prop(part, "kink_shape", slider=True)
970
971
972 class PARTICLE_PT_field_weights(ParticleButtonsPanel, bpy.types.Panel):
973     bl_label = "Field Weights"
974     bl_default_closed = True
975     COMPAT_ENGINES = {'BLENDER_RENDER'}
976
977     def draw(self, context):
978         part = context.particle_system.settings
979         effector_weights_ui(self, context, part.effector_weights)
980
981         if part.type == 'HAIR':
982             self.layout.prop(part.effector_weights, "do_growing_hair")
983
984
985 class PARTICLE_PT_force_fields(ParticleButtonsPanel, bpy.types.Panel):
986     bl_label = "Force Field Settings"
987     bl_default_closed = True
988     COMPAT_ENGINES = {'BLENDER_RENDER'}
989
990     def draw(self, context):
991         layout = self.layout
992
993         part = context.particle_system.settings
994
995         layout.prop(part, "self_effect")
996
997         split = layout.split(percentage=0.2)
998         split.label(text="Type 1:")
999         split.prop(part.force_field_1, "type", text="")
1000         basic_force_field_settings_ui(self, context, part.force_field_1)
1001         basic_force_field_falloff_ui(self, context, part.force_field_1)
1002
1003         if part.force_field_1.type != 'NONE':
1004             layout.label(text="")
1005
1006         split = layout.split(percentage=0.2)
1007         split.label(text="Type 2:")
1008         split.prop(part.force_field_2, "type", text="")
1009         basic_force_field_settings_ui(self, context, part.force_field_2)
1010         basic_force_field_falloff_ui(self, context, part.force_field_2)
1011
1012
1013 class PARTICLE_PT_vertexgroups(ParticleButtonsPanel, bpy.types.Panel):
1014     bl_label = "Vertexgroups"
1015     bl_default_closed = True
1016     COMPAT_ENGINES = {'BLENDER_RENDER'}
1017
1018     def draw(self, context):
1019         layout = self.layout
1020
1021         ob = context.object
1022         psys = context.particle_system
1023         # part = psys.settings
1024
1025         # layout.label(text="Nothing here yet.")
1026
1027         row = layout.row()
1028         row.label(text="Vertex Group")
1029         row.label(text="Negate")
1030
1031
1032         row = layout.row()
1033         row.prop_object(psys, "vertex_group_density", ob, "vertex_groups", text="Density")
1034         row.prop(psys, "vertex_group_density_negate", text="")
1035
1036         row = layout.row()
1037         row.prop_object(psys, "vertex_group_velocity", ob, "vertex_groups", text="Velocity")
1038         row.prop(psys, "vertex_group_velocity_negate", text="")
1039
1040         row = layout.row()
1041         row.prop_object(psys, "vertex_group_length", ob, "vertex_groups", text="Length")
1042         row.prop(psys, "vertex_group_length_negate", text="")
1043
1044         row = layout.row()
1045         row.prop_object(psys, "vertex_group_clump", ob, "vertex_groups", text="Clump")
1046         row.prop(psys, "vertex_group_clump_negate", text="")
1047
1048         row = layout.row()
1049         row.prop_object(psys, "vertex_group_kink", ob, "vertex_groups", text="Kink")
1050         row.prop(psys, "vertex_group_kink_negate", text="")
1051
1052         row = layout.row()
1053         row.prop_object(psys, "vertex_group_roughness1", ob, "vertex_groups", text="Roughness 1")
1054         row.prop(psys, "vertex_group_roughness1_negate", text="")
1055
1056         row = layout.row()
1057         row.prop_object(psys, "vertex_group_roughness2", ob, "vertex_groups", text="Roughness 2")
1058         row.prop(psys, "vertex_group_roughness2_negate", text="")
1059
1060         row = layout.row()
1061         row.prop_object(psys, "vertex_group_roughness_end", ob, "vertex_groups", text="Roughness End")
1062         row.prop(psys, "vertex_group_roughness_end_negate", text="")
1063
1064         row = layout.row()
1065         row.prop_object(psys, "vertex_group_size", ob, "vertex_groups", text="Size")
1066         row.prop(psys, "vertex_group_size_negate", text="")
1067
1068         row = layout.row()
1069         row.prop_object(psys, "vertex_group_tangent", ob, "vertex_groups", text="Tangent")
1070         row.prop(psys, "vertex_group_tangent_negate", text="")
1071
1072         row = layout.row()
1073         row.prop_object(psys, "vertex_group_rotation", ob, "vertex_groups", text="Rotation")
1074         row.prop(psys, "vertex_group_rotation_negate", text="")
1075
1076         row = layout.row()
1077         row.prop_object(psys, "vertex_group_field", ob, "vertex_groups", text="Field")
1078         row.prop(psys, "vertex_group_field_negate", text="")
1079
1080
1081 def register():
1082     pass
1083
1084
1085 def unregister():
1086     pass
1087
1088 if __name__ == "__main__":
1089     register()