2.5: Objects
[blender-staging.git] / source / blender / editors / space_buttons / buttons_ops.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2009 Blender Foundation.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "DNA_curve_types.h"
34 #include "DNA_group_types.h"
35 #include "DNA_object_types.h"
36 #include "DNA_material_types.h"
37 #include "DNA_node_types.h"
38 #include "DNA_texture_types.h"
39 #include "DNA_scene_types.h"
40 #include "DNA_world_types.h"
41
42 #include "BKE_context.h"
43 #include "BKE_depsgraph.h"
44 #include "BKE_group.h"
45 #include "BKE_font.h"
46 #include "BKE_library.h"
47 #include "BKE_main.h"
48 #include "BKE_material.h"
49 #include "BKE_node.h"
50 #include "BKE_particle.h"
51 #include "BKE_scene.h"
52 #include "BKE_texture.h"
53 #include "BKE_utildefines.h"
54 #include "BKE_world.h"
55
56 #include "BLI_editVert.h"
57 #include "BLI_listbase.h"
58
59 #include "RNA_access.h"
60
61 #include "WM_api.h"
62 #include "WM_types.h"
63
64 #include "ED_curve.h"
65 #include "ED_mesh.h"
66
67 #include "RNA_access.h"
68 #include "RNA_define.h"
69
70 #include "buttons_intern.h"     // own include
71
72
73 /********************** group operators *********************/
74
75 static int group_add_exec(bContext *C, wmOperator *op)
76 {
77         Main *bmain= CTX_data_main(C);
78         Scene *scene= CTX_data_scene(C);
79         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
80         Base *base;
81         Group *group;
82         int value= RNA_enum_get(op->ptr, "group");
83
84         if(!ob)
85                 return OPERATOR_CANCELLED;
86         
87         base= object_in_scene(ob, scene);
88         if(!base)
89                 return OPERATOR_CANCELLED;
90         
91         if(value == -1)
92                 group= add_group( "Group" );
93         else
94                 group= BLI_findlink(&bmain->group, value);
95
96         if(group) {
97                 add_to_group(group, ob);
98                 ob->flag |= OB_FROMGROUP;
99                 base->flag |= OB_FROMGROUP;
100         }
101
102         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
103         
104         return OPERATOR_FINISHED;
105 }
106
107 static EnumPropertyItem group_items[]= {
108         {-1, "ADD_NEW", 0, "Add New Group", ""},
109         {0, NULL, 0, NULL, NULL}};
110
111 static EnumPropertyItem *group_itemf(bContext *C, PointerRNA *ptr, int *free)
112 {       
113         EnumPropertyItem tmp = {0, "", 0, "", ""};
114         EnumPropertyItem *item= NULL;
115         Main *bmain;
116         Group *group;
117         int a, totitem= 0;
118         
119         if(!C) /* needed for docs */
120                 return group_items;
121         
122         RNA_enum_items_add_value(&item, &totitem, group_items, -1);
123
124         bmain= CTX_data_main(C);
125         if(bmain->group.first)
126                 RNA_enum_item_add_separator(&item, &totitem);
127
128         for(a=0, group=bmain->group.first; group; group=group->id.next, a++) {
129                 tmp.value= a;
130                 tmp.identifier= group->id.name+2;
131                 tmp.name= group->id.name+2;
132                 RNA_enum_item_add(&item, &totitem, &tmp);
133         }
134
135         RNA_enum_item_end(&item, &totitem);
136
137         *free= 1;
138
139         return item;
140 }
141
142 void OBJECT_OT_group_add(wmOperatorType *ot)
143 {
144         PropertyRNA *prop;
145
146         /* identifiers */
147         ot->name= "Add Group";
148         ot->idname= "OBJECT_OT_group_add";
149         
150         /* api callbacks */
151         ot->exec= group_add_exec;
152
153         /* flags */
154         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
155
156         /* properties */
157         prop= RNA_def_enum(ot->srna, "group", group_items, -1, "Group", "Group to add object to.");
158         RNA_def_enum_funcs(prop, group_itemf);
159 }
160
161 static int group_remove_exec(bContext *C, wmOperator *op)
162 {
163         Scene *scene= CTX_data_scene(C);
164         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
165         Group *group= CTX_data_pointer_get_type(C, "group", &RNA_Group).data;
166         Base *base;
167
168         if(!ob || !group)
169                 return OPERATOR_CANCELLED;
170
171         base= object_in_scene(ob, scene);
172         if(!base)
173                 return OPERATOR_CANCELLED;
174
175         rem_from_group(group, ob);
176
177         if(find_group(ob, NULL) == NULL) {
178                 ob->flag &= ~OB_FROMGROUP;
179                 base->flag &= ~OB_FROMGROUP;
180         }
181
182         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
183         
184         return OPERATOR_FINISHED;
185 }
186
187 void OBJECT_OT_group_remove(wmOperatorType *ot)
188 {
189         /* identifiers */
190         ot->name= "Remove Group";
191         ot->idname= "OBJECT_OT_group_remove";
192         
193         /* api callbacks */
194         ot->exec= group_remove_exec;
195
196         /* flags */
197         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
198 }
199
200 /********************** material slot operators *********************/
201
202 static int material_slot_add_exec(bContext *C, wmOperator *op)
203 {
204         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
205
206         if(!ob)
207                 return OPERATOR_CANCELLED;
208
209         object_add_material_slot(ob);
210         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
211         
212         return OPERATOR_FINISHED;
213 }
214
215 void OBJECT_OT_material_slot_add(wmOperatorType *ot)
216 {
217         /* identifiers */
218         ot->name= "Add Material Slot";
219         ot->idname= "OBJECT_OT_material_slot_add";
220         
221         /* api callbacks */
222         ot->exec= material_slot_add_exec;
223
224         /* flags */
225         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
226 }
227
228 static int material_slot_remove_exec(bContext *C, wmOperator *op)
229 {
230         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
231
232         if(!ob)
233                 return OPERATOR_CANCELLED;
234
235         object_remove_material_slot(ob);
236         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
237         
238         return OPERATOR_FINISHED;
239 }
240
241 void OBJECT_OT_material_slot_remove(wmOperatorType *ot)
242 {
243         /* identifiers */
244         ot->name= "Remove Material Slot";
245         ot->idname= "OBJECT_OT_material_slot_remove";
246         
247         /* api callbacks */
248         ot->exec= material_slot_remove_exec;
249
250         /* flags */
251         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
252 }
253
254 static int material_slot_assign_exec(bContext *C, wmOperator *op)
255 {
256         Scene *scene= CTX_data_scene(C);
257         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
258
259         if(!ob)
260                 return OPERATOR_CANCELLED;
261
262         if(ob && ob->actcol>0) {
263                 if(ob->type == OB_MESH) {
264                         EditMesh *em= ((Mesh*)ob->data)->edit_mesh;
265                         EditFace *efa;
266
267                         if(em) {
268                                 for(efa= em->faces.first; efa; efa=efa->next)
269                                         if(efa->f & SELECT)
270                                                 efa->mat_nr= ob->actcol-1;
271                         }
272                 }
273                 else if(ELEM(ob->type, OB_CURVE, OB_SURF)) {
274                         ListBase *editnurb= ((Curve*)ob->data)->editnurb;
275                         Nurb *nu;
276
277                         if(editnurb) {
278                                 for(nu= editnurb->first; nu; nu= nu->next)
279                                         if(isNurbsel(nu))
280                                                 nu->mat_nr= nu->charidx= ob->actcol-1;
281                         }
282                 }
283                 else if(ob->type == OB_FONT) {
284                         EditFont *ef= ((Curve*)ob->data)->editfont;
285                 int i, selstart, selend;
286
287                         if(ef && BKE_font_getselection(ob, &selstart, &selend)) {
288                                 for(i=selstart; i<=selend; i++)
289                                         ef->textbufinfo[i].mat_nr = ob->actcol-1;
290                         }
291                 }
292         }
293
294     DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
295     WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob);
296         
297         return OPERATOR_FINISHED;
298 }
299
300 void OBJECT_OT_material_slot_assign(wmOperatorType *ot)
301 {
302         /* identifiers */
303         ot->name= "Assign Material Slot";
304         ot->idname= "OBJECT_OT_material_slot_assign";
305         
306         /* api callbacks */
307         ot->exec= material_slot_assign_exec;
308
309         /* flags */
310         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
311 }
312
313 static int material_slot_de_select(bContext *C, int select)
314 {
315         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
316
317         if(!ob)
318                 return OPERATOR_CANCELLED;
319
320         if(ob->type == OB_MESH) {
321                 EditMesh *em= ((Mesh*)ob->data)->edit_mesh;
322
323                 if(em) {
324                         if(select)
325                                 EM_select_by_material(em, ob->actcol-1);
326                         else
327                                 EM_deselect_by_material(em, ob->actcol-1);
328                 }
329         }
330         else if ELEM(ob->type, OB_CURVE, OB_SURF) {
331                 ListBase *editnurb= ((Curve*)ob->data)->editnurb;
332                 Nurb *nu;
333                 BPoint *bp;
334                 BezTriple *bezt;
335                 int a;
336
337                 for(nu= editnurb->first; nu; nu=nu->next) {
338                         if(nu->mat_nr==ob->actcol-1) {
339                                 if(nu->bezt) {
340                                         a= nu->pntsu;
341                                         bezt= nu->bezt;
342                                         while(a--) {
343                                                 if(bezt->hide==0) {
344                                                         if(select) {
345                                                                 bezt->f1 |= SELECT;
346                                                                 bezt->f2 |= SELECT;
347                                                                 bezt->f3 |= SELECT;
348                                                         }
349                                                         else {
350                                                                 bezt->f1 &= ~SELECT;
351                                                                 bezt->f2 &= ~SELECT;
352                                                                 bezt->f3 &= ~SELECT;
353                                                         }
354                                                 }
355                                                 bezt++;
356                                         }
357                                 }
358                                 else if(nu->bp) {
359                                         a= nu->pntsu*nu->pntsv;
360                                         bp= nu->bp;
361                                         while(a--) {
362                                                 if(bp->hide==0) {
363                                                         if(select) bp->f1 |= SELECT;
364                                                         else bp->f1 &= ~SELECT;
365                                                 }
366                                                 bp++;
367                                         }
368                                 }
369                         }
370                 }
371         }
372
373     WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
374
375         return OPERATOR_FINISHED;
376 }
377
378 static int material_slot_select_exec(bContext *C, wmOperator *op)
379 {
380         return material_slot_de_select(C, 1);
381 }
382
383 void OBJECT_OT_material_slot_select(wmOperatorType *ot)
384 {
385         /* identifiers */
386         ot->name= "Select Material Slot";
387         ot->idname= "OBJECT_OT_material_slot_select";
388         
389         /* api callbacks */
390         ot->exec= material_slot_select_exec;
391
392         /* flags */
393         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
394 }
395
396 static int material_slot_deselect_exec(bContext *C, wmOperator *op)
397 {
398         return material_slot_de_select(C, 0);
399 }
400
401 void OBJECT_OT_material_slot_deselect(wmOperatorType *ot)
402 {
403         /* identifiers */
404         ot->name= "Deselect Material Slot";
405         ot->idname= "OBJECT_OT_material_slot_deselect";
406         
407         /* api callbacks */
408         ot->exec= material_slot_deselect_exec;
409
410         /* flags */
411         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
412 }
413
414 /********************** new material operator *********************/
415
416 static int new_material_exec(bContext *C, wmOperator *op)
417 {
418         Material *ma= CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
419         Object *ob;
420         PointerRNA ptr;
421         int index;
422
423         /* add or copy material */
424         if(ma)
425                 ma= copy_material(ma);
426         else
427                 ma= add_material("Material");
428
429         ma->id.us--; /* compensating for us++ in assign_material */
430
431         /* attempt to assign to material slot */
432         ptr= CTX_data_pointer_get_type(C, "material_slot", &RNA_MaterialSlot);
433
434         if(ptr.data) {
435                 ob= ptr.id.data;
436                 index= (Material**)ptr.data - ob->mat;
437
438                 assign_material(ob, ma, index+1);
439
440                 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
441         }
442
443         WM_event_add_notifier(C, NC_MATERIAL|NA_ADDED, ma);
444         
445         return OPERATOR_FINISHED;
446 }
447
448 void MATERIAL_OT_new(wmOperatorType *ot)
449 {
450         /* identifiers */
451         ot->name= "New Material";
452         ot->idname= "MATERIAL_OT_new";
453         
454         /* api callbacks */
455         ot->exec= new_material_exec;
456
457         /* flags */
458         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
459 }
460
461 /********************** new texture operator *********************/
462
463 static int new_texture_exec(bContext *C, wmOperator *op)
464 {
465         Tex *tex= CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
466         ID *id;
467         MTex *mtex;
468         PointerRNA ptr;
469
470         /* add or copy texture */
471         if(tex)
472                 tex= copy_texture(tex);
473         else
474                 tex= add_texture("Texture");
475
476         id_us_min(&tex->id);
477
478         /* attempt to assign to texture slot */
479         ptr= CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot);
480
481         if(ptr.data) {
482                 id= ptr.id.data;
483                 mtex= ptr.data;
484
485                 if(mtex) {
486                         if(mtex->tex)
487                                 id_us_min(&mtex->tex->id);
488                         mtex->tex= tex;
489                         id_us_plus(&tex->id);
490                 }
491
492                 /* XXX nodes, notifier .. */
493         }
494
495         WM_event_add_notifier(C, NC_TEXTURE|NA_ADDED, tex);
496         
497         return OPERATOR_FINISHED;
498 }
499
500 void TEXTURE_OT_new(wmOperatorType *ot)
501 {
502         /* identifiers */
503         ot->name= "New Texture";
504         ot->idname= "TEXTURE_OT_new";
505         
506         /* api callbacks */
507         ot->exec= new_texture_exec;
508
509         /* flags */
510         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
511 }
512
513 /********************** new world operator *********************/
514
515 static int new_world_exec(bContext *C, wmOperator *op)
516 {
517         Scene *scene= CTX_data_scene(C);
518         World *wo= CTX_data_pointer_get_type(C, "world", &RNA_World).data;
519
520         /* add or copy world */
521         if(wo)
522                 wo= copy_world(wo);
523         else
524                 wo= add_world("World");
525
526         /* assign to scene */
527         if(scene->world)
528                 id_us_min(&scene->world->id);
529         scene->world= wo;
530
531         WM_event_add_notifier(C, NC_WORLD|NA_ADDED, wo);
532         
533         return OPERATOR_FINISHED;
534 }
535
536 void WORLD_OT_new(wmOperatorType *ot)
537 {
538         /* identifiers */
539         ot->name= "New World";
540         ot->idname= "WORLD_OT_new";
541         
542         /* api callbacks */
543         ot->exec= new_world_exec;
544
545         /* flags */
546         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
547 }
548
549
550
551 /********************** particle system slot operators *********************/
552
553 static int particle_system_add_exec(bContext *C, wmOperator *op)
554 {
555         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
556         Scene *scene = CTX_data_scene(C);
557
558         if(!scene || !ob)
559                 return OPERATOR_CANCELLED;
560
561         object_add_particle_system(scene, ob);
562         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
563         
564         return OPERATOR_FINISHED;
565 }
566
567 void OBJECT_OT_particle_system_add(wmOperatorType *ot)
568 {
569         /* identifiers */
570         ot->name= "Add Particle System Slot";
571         ot->idname= "OBJECT_OT_particle_system_add";
572         
573         /* api callbacks */
574         ot->exec= particle_system_add_exec;
575
576         /* flags */
577         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
578 }
579
580 static int particle_system_remove_exec(bContext *C, wmOperator *op)
581 {
582         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
583         Scene *scene = CTX_data_scene(C);
584
585         if(!scene || !ob)
586                 return OPERATOR_CANCELLED;
587
588         object_remove_particle_system(scene, ob);
589         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
590         
591         return OPERATOR_FINISHED;
592 }
593
594 void OBJECT_OT_particle_system_remove(wmOperatorType *ot)
595 {
596         /* identifiers */
597         ot->name= "Remove Particle System Slot";
598         ot->idname= "OBJECT_OT_particle_system_remove";
599         
600         /* api callbacks */
601         ot->exec= particle_system_remove_exec;
602
603         /* flags */
604         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
605 }
606
607 /********************** new particle settings operator *********************/
608
609 static int new_particle_settings_exec(bContext *C, wmOperator *op)
610 {
611         Scene *scene = CTX_data_scene(C);
612         Main *bmain= CTX_data_main(C);
613         ParticleSystem *psys;
614         ParticleSettings *part = NULL;
615         Object *ob;
616         PointerRNA ptr;
617
618         ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
619
620         psys = ptr.data;
621
622         /* add or copy particle setting */
623         if(psys->part)
624                 part= psys_copy_settings(psys->part);
625         else
626                 part= psys_new_settings("PSys", bmain);
627
628         ob= ptr.id.data;
629
630         if(psys->part)
631                 psys->part->id.us--;
632
633         psys->part = part;
634
635         DAG_scene_sort(scene);
636         DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
637
638         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
639         
640         return OPERATOR_FINISHED;
641 }
642
643 void PARTICLE_OT_new(wmOperatorType *ot)
644 {
645         /* identifiers */
646         ot->name= "New Particle Settings";
647         ot->idname= "PARTICLE_OT_new";
648         
649         /* api callbacks */
650         ot->exec= new_particle_settings_exec;
651
652         /* flags */
653         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
654 }
655
656 /********************** keyed particle target operators *********************/
657
658 static int new_keyed_particle_target_exec(bContext *C, wmOperator *op)
659 {
660         Scene *scene = CTX_data_scene(C);
661         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
662         ParticleSystem *psys= ptr.data;
663         Object *ob = ptr.id.data;
664
665         KeyedParticleTarget *kpt;
666
667         if(!psys)
668                 return OPERATOR_CANCELLED;
669
670         kpt = psys->keyed_targets.first;
671         for(; kpt; kpt=kpt->next)
672                 kpt->flag &= ~KEYED_TARGET_CURRENT;
673
674         kpt = MEM_callocN(sizeof(KeyedParticleTarget), "keyed particle target");
675
676         kpt->flag |= KEYED_TARGET_CURRENT;
677         kpt->psys = 1;
678
679         BLI_addtail(&psys->keyed_targets, kpt);
680
681         DAG_scene_sort(scene);
682         DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
683
684         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
685         
686         return OPERATOR_FINISHED;
687 }
688
689 void PARTICLE_OT_new_keyed_target(wmOperatorType *ot)
690 {
691         /* identifiers */
692         ot->name= "New Keyed Particle Target";
693         ot->idname= "PARTICLE_OT_new_keyed_target";
694         
695         /* api callbacks */
696         ot->exec= new_keyed_particle_target_exec;
697
698         /* flags */
699         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
700 }
701
702 static int remove_keyed_particle_target_exec(bContext *C, wmOperator *op)
703 {
704         Scene *scene = CTX_data_scene(C);
705         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
706         ParticleSystem *psys= ptr.data;
707         Object *ob = ptr.id.data;
708
709         KeyedParticleTarget *kpt;
710
711         if(!psys)
712                 return OPERATOR_CANCELLED;
713
714         kpt = psys->keyed_targets.first;
715         for(; kpt; kpt=kpt->next) {
716                 if(kpt->flag & KEYED_TARGET_CURRENT) {
717                         BLI_remlink(&psys->keyed_targets, kpt);
718                         MEM_freeN(kpt);
719                         break;
720                 }
721
722         }
723         kpt = psys->keyed_targets.last;
724
725         if(kpt)
726                 kpt->flag |= KEYED_TARGET_CURRENT;
727
728         DAG_scene_sort(scene);
729         DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
730
731         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
732         
733         return OPERATOR_FINISHED;
734 }
735
736 void PARTICLE_OT_remove_keyed_target(wmOperatorType *ot)
737 {
738         /* identifiers */
739         ot->name= "Remove Keyed Particle Target";
740         ot->idname= "PARTICLE_OT_remove_keyed_target";
741         
742         /* api callbacks */
743         ot->exec= remove_keyed_particle_target_exec;
744
745         /* flags */
746         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
747 }
748
749 /************************ move up modifier operator *********************/
750
751 static int keyed_target_move_up_exec(bContext *C, wmOperator *op)
752 {
753         Scene *scene= CTX_data_scene(C);
754         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
755         ParticleSystem *psys= ptr.data;
756         Object *ob = ptr.id.data;
757         KeyedParticleTarget *kpt;
758
759         if(!psys)
760                 return OPERATOR_CANCELLED;
761         
762         kpt = psys->keyed_targets.first;
763         for(; kpt; kpt=kpt->next) {
764                 if(kpt->flag & KEYED_TARGET_CURRENT && kpt->prev) {
765                         BLI_remlink(&psys->keyed_targets, kpt);
766                         BLI_insertlink(&psys->keyed_targets, kpt->prev->prev, kpt);
767
768                         DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
769                         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
770                         break;
771                 }
772         }
773         
774         return OPERATOR_FINISHED;
775 }
776
777 void PARTICLE_OT_keyed_target_move_up(wmOperatorType *ot)
778 {
779         ot->name= "Move Up Keyed Target";
780         ot->description= "Move keyed particle target up in the list.";
781         ot->idname= "PARTICLE_OT_keyed_target_move_up";
782
783         ot->exec= keyed_target_move_up_exec;
784         
785         /* flags */
786         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
787 }
788
789 /************************ move down modifier operator *********************/
790
791 static int keyed_target_move_down_exec(bContext *C, wmOperator *op)
792 {
793         Scene *scene= CTX_data_scene(C);
794         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
795         ParticleSystem *psys= ptr.data;
796         Object *ob = ptr.id.data;
797         KeyedParticleTarget *kpt;
798
799         if(!psys)
800                 return OPERATOR_CANCELLED;
801         kpt = psys->keyed_targets.first;
802         for(; kpt; kpt=kpt->next) {
803                 if(kpt->flag & KEYED_TARGET_CURRENT && kpt->next) {
804                         BLI_remlink(&psys->keyed_targets, kpt);
805                         BLI_insertlink(&psys->keyed_targets, kpt->next, kpt);
806
807                         DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
808                         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
809                         break;
810                 }
811         }
812         
813         return OPERATOR_FINISHED;
814 }
815
816 void PARTICLE_OT_keyed_target_move_down(wmOperatorType *ot)
817 {
818         ot->name= "Move Down Keyed Target";
819         ot->description= "Move keyed particle target down in the list.";
820         ot->idname= "PARTICLE_OT_keyed_target_move_down";
821
822         ot->exec= keyed_target_move_down_exec;
823         
824         /* flags */
825         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
826 }
827
828 /********************** render layer operators *********************/
829
830 static int render_layer_add_exec(bContext *C, wmOperator *op)
831 {
832         Scene *scene= CTX_data_scene(C);
833
834         scene_add_render_layer(scene);
835         scene->r.actlay= BLI_countlist(&scene->r.layers) - 1;
836
837         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS, scene);
838         
839         return OPERATOR_FINISHED;
840 }
841
842 void SCENE_OT_render_layer_add(wmOperatorType *ot)
843 {
844         /* identifiers */
845         ot->name= "Add Render Layer";
846         ot->idname= "SCENE_OT_render_layer_add";
847         
848         /* api callbacks */
849         ot->exec= render_layer_add_exec;
850
851         /* flags */
852         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
853 }
854
855 static int render_layer_remove_exec(bContext *C, wmOperator *op)
856 {
857         Scene *scene= CTX_data_scene(C);
858         SceneRenderLayer *rl;
859         int act= scene->r.actlay;
860
861         if(BLI_countlist(&scene->r.layers) <= 1)
862                 return OPERATOR_CANCELLED;
863         
864         rl= BLI_findlink(&scene->r.layers, scene->r.actlay);
865         BLI_remlink(&scene->r.layers, rl);
866         MEM_freeN(rl);
867
868         scene->r.actlay= 0;
869         
870         if(scene->nodetree) {
871                 bNode *node;
872                 for(node= scene->nodetree->nodes.first; node; node= node->next) {
873                         if(node->type==CMP_NODE_R_LAYERS && node->id==NULL) {
874                                 if(node->custom1==act)
875                                         node->custom1= 0;
876                                 else if(node->custom1>act)
877                                         node->custom1--;
878                         }
879                 }
880         }
881
882         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS, scene);
883         
884         return OPERATOR_FINISHED;
885 }
886
887 void SCENE_OT_render_layer_remove(wmOperatorType *ot)
888 {
889         /* identifiers */
890         ot->name= "Remove Render Layer";
891         ot->idname= "SCENE_OT_render_layer_remove";
892         
893         /* api callbacks */
894         ot->exec= render_layer_remove_exec;
895
896         /* flags */
897         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
898 }