Undo revision 23130 which was a merge with 2.5, a messy one because I did something...
[blender.git] / source / blender / editors / physics / editparticle.c
index 89d4466..b92632b 100644 (file)
@@ -1,7 +1,5 @@
-/* editparticle.c
- *
- *
- * $Id: editparticle.c $
+/*
+ * $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
@@ -46,6 +44,7 @@
 #include "DNA_view3d_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_space_types.h"
+#include "DNA_windowmanager_types.h"
 
 #include "BKE_DerivedMesh.h"
 #include "BKE_depsgraph.h"
@@ -56,6 +55,7 @@
 #include "BKE_mesh.h"
 #include "BKE_modifier.h"
 #include "BKE_particle.h"
+#include "BKE_report.h"
 #include "BKE_scene.h"
 #include "BKE_utildefines.h" 
 
 #include "BIF_gl.h"
 #include "BIF_glutil.h"
 
-#include "ED_editparticle.h"
+#include "ED_mesh.h"
+#include "ED_particle.h"
 #include "ED_view3d.h"
 
+#include "UI_interface.h"
 #include "UI_resources.h"
 
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
 #include "physics_intern.h"
 
+static void PE_create_particle_edit(Scene *scene, Object *ob, ParticleSystem *psys);
 static void ParticleUndo_clear(ParticleSystem *psys);
 
-#define LOOP_PARTICLES(i,pa) for(i=0, pa=psys->particles; i<totpart; i++, pa++)
-#define LOOP_KEYS(k,key) if(psys->edit)for(k=0, key=psys->edit->keys[i]; k<pa->totkey; k++, key++)
+#define LOOP_PARTICLES(i, pa) for(i=0, pa=psys->particles; i<totpart; i++, pa++)
+#define LOOP_KEYS(k, key) if(psys->edit)for(k=0, key=psys->edit->keys[i]; k<pa->totkey; k++, key++)
+
+/**************************** utilities *******************************/
+
+static int PE_poll(bContext *C)
+{
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       ParticleSystem *psys;
+
+       if(!scene || !ob)
+               return 0;
+       
+       psys= PE_get_current(scene, ob);
+
+       return (psys && psys->edit && (ob && ob->mode & OB_MODE_PARTICLE_EDIT));
+}
 
-/* XXX */
-static void BIF_undo_push() {}
-static void error() {}
-static int pupmenu() {return 0;}
-static int lasso_inside() {return 0;}
-static void *mesh_get_x_mirror_faces() {return NULL;}
-#define LEFTMOUSE 0
-#define RADIALCONTROL_SIZE             0
-#define RADIALCONTROL_STRENGTH 0
-#define RADIALCONTROL_NONE             0
-/* XXX */
+static int PE_poll_3dview(bContext *C)
+{
+       return PE_poll(C) && CTX_wm_area(C)->spacetype == SPACE_VIEW3D &&
+               CTX_wm_region(C)->regiontype == RGN_TYPE_WINDOW;
+}
 
-void PE_free_particle_edit(ParticleSystem *psys)
+static void PE_free_particle_edit(ParticleSystem *psys)
 {
-       ParticleEdit *edit=psys->edit;
-       int i, totpart=psys->totpart;
+       ParticleEdit *edit= psys->edit;
+       int i, totpart= psys->totpart;
 
        if(edit==0) return;
 
        ParticleUndo_clear(psys);
 
-       if(edit->keys){
-               for(i=0; i<totpart; i++){
+       if(edit->keys) {
+               for(i=0; i<totpart; i++) {
                        if(edit->keys[i])
                                MEM_freeN(edit->keys[i]);
                }
+
                MEM_freeN(edit->keys);
        }
 
        if(edit->mirror_cache)
                MEM_freeN(edit->mirror_cache);
 
-       if(edit->emitter_cosnos){
+       if(edit->emitter_cosnos) {
                MEM_freeN(edit->emitter_cosnos);
-               edit->emitter_cosnos=0;
+               edit->emitter_cosnos= 0;
        }
 
-       if(edit->emitter_field){
+       if(edit->emitter_field) {
                BLI_kdtree_free(edit->emitter_field);
-               edit->emitter_field=0;
+               edit->emitter_field= 0;
        }
 
        MEM_freeN(edit);
 
-       psys->edit=NULL;
+       psys->edit= NULL;
+       psys->free_edit= NULL;
 }
+
 /************************************************/
 /*                     Edit Mode Helpers                                       */
 /************************************************/
+
 int PE_can_edit(ParticleSystem *psys)
 {
-       return (psys && psys->edit && (G.f & G_PARTICLEEDIT));
+       return (psys && psys->edit);
 }
 
 ParticleEditSettings *PE_settings(Scene *scene)
@@ -141,46 +164,8 @@ ParticleEditSettings *PE_settings(Scene *scene)
        return &scene->toolsettings->particle;
 }
 
-void PE_change_act(void *ob_v, void *act_v)
-{
-       Object *ob = ob_v;
-       ParticleSystem *psys;
-       short act = *((short*)act_v) - 1;
-
-       if((psys=psys_get_current(ob)))
-               psys->flag &= ~PSYS_CURRENT;
-
-       if(act>=0){
-               if((psys=BLI_findlink(&ob->particlesystem,act))) {
-                       psys->flag |= PSYS_CURRENT;
-
-                       if(psys_check_enabled(ob, psys)) {
-                               if(G.f & G_PARTICLEEDIT && !psys->edit)
-                                       PE_create_particle_edit(ob, psys);
-                               PE_recalc_world_cos(ob, psys);
-                       }
-               }
-       }
-}
-
-void PE_change_act_psys(Object *ob, ParticleSystem *psys)
-{
-       ParticleSystem *p;
-       
-       if((p=psys_get_current(ob)))
-               p->flag &= ~PSYS_CURRENT;
-       
-       psys->flag |= PSYS_CURRENT;
-       
-       if(psys_check_enabled(ob, psys)) {
-               if(G.f & G_PARTICLEEDIT && !psys->edit)
-                       PE_create_particle_edit(ob, psys);
-               PE_recalc_world_cos(ob, psys);
-       }
-}
-
 /* always gets atleast the first particlesystem even if PSYS_CURRENT flag is not set */
-ParticleSystem *PE_get_current(Object *ob)
+ParticleSystem *PE_get_current(Scene *scene, Object *ob)
 {
        ParticleSystem *psys;
 
@@ -188,7 +173,7 @@ ParticleSystem *PE_get_current(Object *ob)
                return NULL;
 
        psys= ob->particlesystem.first;
-       while(psys){
+       while(psys) {
                if(psys->flag & PSYS_CURRENT)
                        break;
                psys=psys->next;
@@ -199,10 +184,12 @@ ParticleSystem *PE_get_current(Object *ob)
                psys->flag |= PSYS_CURRENT;
        }
 
-       if(psys && psys_check_enabled(ob, psys)) // XXX && ob == OBACT && (G.f & G_PARTICLEEDIT))
+       /* this happens when Blender is started with particle
+        * edit mode enabled XXX there's a draw error then? */
+       if(psys && psys_check_enabled(ob, psys) && (ob == OBACT) && (ob->mode & OB_MODE_PARTICLE_EDIT))
                if(psys->part->type == PART_HAIR && psys->flag & PSYS_EDITED)
                        if(psys->edit == NULL)
-                               PE_create_particle_edit(ob, psys);
+                               PE_create_particle_edit(scene, ob, psys);
 
        return psys;
 }
@@ -211,9 +198,9 @@ ParticleSystem *PE_get_current(Object *ob)
 short PE_get_current_num(Object *ob)
 {
        short num=0;
-       ParticleSystem *psys = ob->particlesystem.first;
+       ParticleSystem *psys= ob->particlesystem.first;
 
-       while(psys){
+       while(psys) {
                if(psys->flag & PSYS_CURRENT)
                        return num;
                num++;
@@ -228,100 +215,118 @@ void PE_hide_keys_time(Scene *scene, ParticleSystem *psys, float cfra)
        ParticleData *pa;
        ParticleEditKey *key;
        ParticleEditSettings *pset=PE_settings(scene);
-       int i,k,totpart=psys->totpart;
+       int i, k, totpart= psys->totpart;
 
-       if(pset->draw_timed && scene->selectmode==SCE_SELECT_POINT){
-               LOOP_PARTICLES(i,pa){
-                       LOOP_KEYS(k,key){
+       if(pset->draw_timed && pset->selectmode==SCE_SELECT_POINT) {
+               LOOP_PARTICLES(i, pa) {
+                       LOOP_KEYS(k, key) {
                                if(fabs(cfra-*key->time) < pset->draw_timed)
                                        key->flag &= ~PEK_HIDE;
-                               else{
+                               else {
                                        key->flag |= PEK_HIDE;
                                        key->flag &= ~PEK_SELECT;
                                }
                        }
                }
        }
-       else{
-               LOOP_PARTICLES(i,pa){
-                       LOOP_KEYS(k,key){
+       else {
+               LOOP_PARTICLES(i, pa) {
+                       LOOP_KEYS(k, key) {
                                key->flag &= ~PEK_HIDE;
                        }
                }
        }
 }
 
-static int key_inside_circle(short mco[2], float rad, float co[3], float *distance)
-{
-       ARegion *ar= NULL; // XXX
-       float dx,dy,dist;
-       short vertco[2];
+/****************** common struct passed to callbacks ******************/
 
-       project_short(ar, co, vertco);
-       
-       if (vertco[0]==IS_CLIPPED)
-               return 0;
+typedef struct PEData {
+       ViewContext vc;
+       bglMats mats;
        
-       dx=(float)(mco[0]-vertco[0]);
-       dy=(float)(mco[1]-vertco[1]);
-       dist=(float)sqrt((double)(dx*dx + dy*dy));
+       Scene *scene;
+       Object *ob;
+       DerivedMesh *dm;
+       ParticleSystem *psys;
 
-       if(dist<=rad){
-               if(distance) *distance=dist;
-               return 1;
-       }
-       else
-               return 0;
+       short *mval;
+       rcti *rect;
+       float rad;
+       float dist;
+       float dval;
+       int select;
+
+       float *dvec;
+       float combfac;
+       float pufffac;
+       float cutfac;
+       float smoothfac;
+       float weightfac;
+       float growfac;
+       int totrekey;
+
+       int invert;
+       int tot;
+       float vec[3];
+} PEData;
+
+static void PE_set_data(bContext *C, PEData *data)
+{
+       memset(data, 0, sizeof(*data));
+
+       data->scene= CTX_data_scene(C);
+       data->ob= CTX_data_active_object(C);
+       data->psys= PE_get_current(data->scene, data->ob);
 }
-static int key_inside_rect(rcti *rect, float co[3])
+
+static void PE_set_view3d_data(bContext *C, PEData *data)
 {
-       ARegion *ar= NULL; // XXX
-       short vertco[2];
+       PE_set_data(C, data);
 
-       project_short(ar, co,vertco);
+       view3d_set_viewcontext(C, &data->vc);
+       view3d_get_transformation(&data->vc, data->ob, &data->mats);
 
-       if (vertco[0]==IS_CLIPPED)
-               return 0;
-       
-       if(vertco[0] > rect->xmin && vertco[0] < rect->xmax &&
-                       vertco[1] > rect->ymin && vertco[1] < rect->ymax)
-               return 1;
-       else
-               return 0;
+       if((data->vc.v3d->drawtype>OB_WIRE) && (data->vc.v3d->flag & V3D_ZBUF_SELECT))
+               view3d_validate_backbuf(&data->vc);
 }
 
-static int test_key_depth(float *co, bglMats *mats)
+/*************************** selection utilities *******************************/
+
+static int key_test_depth(PEData *data, float co[3])
 {
-       ARegion *ar= NULL; // XXX
-       View3D *v3d= NULL;
-       RegionView3D *rv3d= ar->regiondata;
+       View3D *v3d= data->vc.v3d;
+       RegionView3D *rv3d= data->vc.rv3d;
        double ux, uy, uz;
        float depth;
        short wco[3], x,y;
 
-       if((v3d->drawtype<=OB_WIRE) || (v3d->flag & V3D_ZBUF_SELECT)==0) return 1;
-
-       gluProject(co[0],co[1],co[2], mats->modelview, mats->projection,
-                       (GLint *)mats->viewport, &ux, &uy, &uz );
+       /* nothing to do */
+       if((v3d->drawtype<=OB_WIRE) || (v3d->flag & V3D_ZBUF_SELECT)==0)
+               return 1;
 
-       project_short(ar, co, wco);
+       project_short(data->vc.ar, co, wco);
        
-       if (wco[0]==IS_CLIPPED)
+       if(wco[0] == IS_CLIPPED)
                return 0;
-       
+
+       gluProject(co[0],co[1],co[2], data->mats.modelview, data->mats.projection,
+               (GLint *)data->mats.viewport, &ux, &uy, &uz);
+
        x=wco[0];
        y=wco[1];
 
-       if(rv3d->depths && x<rv3d->depths->w && y<rv3d->depths->h){
+       // XXX verify ..
+
+       if(rv3d->depths && x<rv3d->depths->w && y<rv3d->depths->h) {
                /* the 0.0001 is an experimental threshold to make selecting keys right next to a surface work better */
                if((float)uz - 0.0001 > rv3d->depths->depths[y*rv3d->depths->w+x])
                        return 0;
                else
                        return 1;
        }
-       else{
-               x+= (short)ar->winrct.xmin;
-               y+= (short)ar->winrct.ymin;
+       else {
+               x+= (short)data->vc.ar->winrct.xmin;
+               y+= (short)data->vc.ar->winrct.ymin;
 
                glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
 
@@ -332,241 +337,298 @@ static int test_key_depth(float *co, bglMats *mats)
        }
 }
 
+static int key_inside_circle(PEData *data, float rad, float co[3], float *distance)
+{
+       float dx, dy, dist;
+       short sco[2];
+
+       project_short(data->vc.ar, co, sco);
+       
+       if(sco[0] == IS_CLIPPED)
+               return 0;
+       
+       dx= data->mval[0] - sco[0];
+       dy= data->mval[1] - sco[1];
+       dist= sqrt(dx*dx + dy*dy);
+
+       if(dist > rad)
+               return 0;
+
+       if(key_test_depth(data, co)) {
+               if(distance)
+                       *distance=dist;
+
+               return 1;
+       }
+       
+       return 0;
+}
+
+static int key_inside_rect(PEData *data, float co[3])
+{
+       short sco[2];
+
+       project_short(data->vc.ar, co,sco);
+
+       if(sco[0] == IS_CLIPPED)
+               return 0;
+       
+       if(sco[0] > data->rect->xmin && sco[0] < data->rect->xmax &&
+          sco[1] > data->rect->ymin && sco[1] < data->rect->ymax)
+               return key_test_depth(data, co);
+
+       return 0;
+}
+
+static int key_inside_test(PEData *data, float co[3])
+{
+       if(data->mval)
+               return key_inside_circle(data, data->rad, co, NULL);
+       else
+               return key_inside_rect(data, co);
+}
+
 static int particle_is_selected(ParticleSystem *psys, ParticleData *pa)
 {
        ParticleEditKey *key;
        int sel, i, k;
 
-       if(pa->flag&PARS_HIDE) return 0;
+       if(pa->flag & PARS_HIDE)
+               return 0;
 
-       sel=0;
+       sel= 0;
        i= pa - psys->particles;
-       LOOP_KEYS(k,key)
-               if(key->flag&PEK_SELECT)
+
+       LOOP_KEYS(k, key)
+               if(key->flag & PEK_SELECT)
                        return 1;
        
        return 0;
 }
 
-/*-----iterators over editable particles-----*/
-static void for_mouse_hit_keys(int nearest, ParticleSystem *psys, void (*func)(ParticleSystem *psys, 
-                                                                                                       int pa_index, int key_index, void *userData), void *userData)
+/*************************** iterators *******************************/
+
+typedef void (*ForParticleFunc)(PEData *data, int pa_index);
+typedef void (*ForKeyFunc)(PEData *data, int pa_index, int key_index);
+typedef void (*ForKeyMatFunc)(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index);
+
+static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, int nearest)
 {
-       /* these are allways the first in this userData */
-       struct {Scene *scene; short *mval; float rad; rcti *rect;} *data = userData;
+       ParticleSystem *psys= data->psys;
+       ParticleEdit *edit= psys->edit;
        ParticleData *pa;
        ParticleEditKey *key;
-       bglMats mats;
-       int i,k, totpart, nearest_pa=-1, nearest_key=-1;
-       float dist=data->rad;
-
-       if(psys==0 || data->scene->selectmode==SCE_SELECT_PATH) return;
+       ParticleEditSettings *pset= PE_settings(data->scene);
+       int i, k, totpart, nearest_pa, nearest_key;
+       float dist= data->rad;
 
-       totpart=psys->totpart;
+       /* in path select mode we have no keys */
+       if(pset->selectmode==SCE_SELECT_PATH)
+               return;
 
-       bgl_get_mats(&mats);
+       totpart= psys->totpart;
+       nearest_pa= -1;
+       nearest_key= -1;
 
-       LOOP_PARTICLES(i,pa){
+       LOOP_PARTICLES(i, pa) {
                if(pa->flag & PARS_HIDE) continue;
 
-               if(data->scene->selectmode==SCE_SELECT_END){
-                       key=psys->edit->keys[i]+pa->totkey-1;
+               if(pset->selectmode == SCE_SELECT_END) {
+                       /* only do end keys */
+                       key= edit->keys[i] + pa->totkey-1;
 
-                       if(nearest){
-                               if(key_inside_circle(data->mval,dist,key->world_co,&dist) && test_key_depth(key->world_co,&mats)){
-                                       nearest_pa=i;
-                                       nearest_key=pa->totkey-1;
+                       if(nearest) {
+                               if(key_inside_circle(data, dist, key->world_co, &dist)) {
+                                       nearest_pa= i;
+                                       nearest_key= pa->totkey-1;
                                }
                        }
-                       else if(((data->mval)?
-                                               key_inside_circle(data->mval,data->rad,key->world_co,0):
-                                               key_inside_rect(data->rect,key->world_co)) && test_key_depth(key->world_co,&mats))
-                               func(psys,i,pa->totkey-1,userData);
+                       else if(key_inside_test(data, key->world_co))
+                               func(data, i, pa->totkey-1);
                }
-               else{
-                       key=psys->edit->keys[i];
+               else {
+                       /* do all keys */
+                       key= edit->keys[i];
 
-                       LOOP_KEYS(k,key){
-                               if(key->flag&PEK_HIDE) continue;
+                       LOOP_KEYS(k, key) {
+                               if(key->flag & PEK_HIDE) continue;
 
-                               if(nearest){
-                                       if(key_inside_circle(data->mval,dist,key->world_co,&dist) && test_key_depth(key->world_co,&mats)){
-                                               nearest_pa=i;
-                                               nearest_key=k;
+                               if(nearest) {
+                                       if(key_inside_circle(data, dist, key->world_co, &dist)) {
+                                               nearest_pa= i;
+                                               nearest_key= k;
                                        }
                                }
-                               else if(((data->mval)?
-                                                       key_inside_circle(data->mval,data->rad,key->world_co,0):
-                                                       key_inside_rect(data->rect,key->world_co)) && test_key_depth(key->world_co,&mats))
-                                       func(psys,i,k,userData);
+                               else if(key_inside_test(data, key->world_co))
+                                       func(data, i, k);
                        }
                }
        }
-       if(nearest && nearest_pa>-1){
-               func(psys,nearest_pa,nearest_key,userData);
-       }
+
+       /* do nearest only */
+       if(nearest && nearest_pa > -1)
+               func(data, nearest_pa, nearest_key);
 }
 
-static void foreach_mouse_hit_element(int selected, ParticleSystem *psys,void (*func)(ParticleSystem *psys, int index, void *userData), void *userData)
+static void foreach_mouse_hit_particle(PEData *data, ForParticleFunc func, int selected)
 {
-       /* these are allways the first in this userData */
-       struct {Scene *scene; short *mval; float rad; rcti* rect; float dist;} *data = userData;
+       ParticleSystem *psys= data->psys;
        ParticleData *pa;
        ParticleEditKey *key;
-       bglMats mats;
-       int i,k, totpart;
-
-       if(psys==0) return;
-
-       totpart=psys->totpart;
+       ParticleEditSettings *pset= PE_settings(data->scene);
+       int i, k, totpart;
 
-       bgl_get_mats(&mats);
+       totpart= psys->totpart;
 
-       if(data->scene->selectmode==SCE_SELECT_PATH)
+       /* all is selected in path mode */
+       if(pset->selectmode==SCE_SELECT_PATH)
                selected=0;
 
-       LOOP_PARTICLES(i,pa){
+       LOOP_PARTICLES(i, pa) {
                if(pa->flag & PARS_HIDE) continue;
 
-               if(data->scene->selectmode==SCE_SELECT_END){
-                       key=psys->edit->keys[i]+pa->totkey-1;
-                       if(key_inside_circle(data->mval,data->rad,key->world_co,&data->dist) && (selected==0 || key->flag&PEK_SELECT) && test_key_depth(key->world_co,&mats))
-                               func(psys,i,userData);
+               if(pset->selectmode==SCE_SELECT_END) {
+                       /* only do end keys */
+                       key= psys->edit->keys[i] + pa->totkey-1;
+
+                       if(selected==0 || key->flag & PEK_SELECT)
+                               if(key_inside_circle(data, data->rad, key->world_co, &data->dist))
+                                       func(data, i);
                }
-               else{
-                       LOOP_KEYS(k,key){
-                               if(key->flag&PEK_HIDE) continue;
+               else {
+                       /* do all keys */
+                       LOOP_KEYS(k, key) {
+                               if(key->flag & PEK_HIDE) continue;
 
-                               if(key_inside_circle(data->mval,data->rad,key->world_co,&data->dist) && (selected==0 || key->flag&PEK_SELECT) && test_key_depth(key->world_co,&mats)){
-                                       func(psys,i,userData);
-                                       break;
+                               if(selected==0 || key->flag & PEK_SELECT) {
+                                       if(key_inside_circle(data, data->rad, key->world_co, &data->dist)) {
+                                               func(data, i);
+                                               break;
+                                       }
                                }
                        }
                }
        }
 }
 
-static void foreach_mouse_hit_key(int selected, ParticleSystem *psys,void (*func)(ParticleSystem *psys, float mat[][4], float imat[][4], int bel_index, int key_index, void *userData), void *userData)
+static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected)
 {
-       /* these are allways the first in this userData */
-       struct {Scene *scene; Object *ob; short *mval; float rad; rcti* rect; float dist;} *data = userData;
+       ParticleSystem *psys= data->psys;
        ParticleData *pa;
        ParticleEditKey *key;
        ParticleSystemModifierData *psmd=0;
-       bglMats mats;
-       int i,k, totpart;
+       ParticleEditSettings *pset= PE_settings(data->scene);
+       int i, k, totpart;
        float mat[4][4], imat[4][4];
 
-       if(psys==0) return;
-
-       psmd=psys_get_modifier(data->ob,psys);
-
-       totpart=psys->totpart;
-
-       bgl_get_mats(&mats);
+       psmd= psys_get_modifier(data->ob,psys);
+       totpart= psys->totpart;
 
-       if(data->scene->selectmode==SCE_SELECT_PATH)
-               selected=0;
+       /* all is selected in path mode */
+       if(pset->selectmode==SCE_SELECT_PATH)
+               selected= 0;
 
        Mat4One(imat);
        Mat4One(mat);
 
-       LOOP_PARTICLES(i,pa){
+       LOOP_PARTICLES(i, pa) {
                if(pa->flag & PARS_HIDE) continue;
 
                psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, pa, mat);
-               //psys_geometry_mat(psmd->dm,pa,tmat);
-               //Mat4MulMat4(mat,tmat,data->ob->obmat);
                Mat4Invert(imat,mat);
 
-               if(data->scene->selectmode==SCE_SELECT_END){
-                       key=psys->edit->keys[i]+pa->totkey-1;
-                       if(key_inside_circle(data->mval,data->rad,key->world_co,&data->dist) && (selected==0 || key->flag&PEK_SELECT) && test_key_depth(key->world_co,&mats))
-                               func(psys,mat,imat,i,pa->totkey-1,userData);
+               if(pset->selectmode==SCE_SELECT_END) {
+                       /* only do end keys */
+                       key= psys->edit->keys[i] + pa->totkey-1;
+
+                       if(selected==0 || key->flag & PEK_SELECT)
+                               if(key_inside_circle(data, data->rad, key->world_co, &data->dist))
+                                       func(data, mat, imat, i, pa->totkey-1);
                }
-               else{
-                       LOOP_KEYS(k,key){
+               else {
+                       /* do all keys */
+                       LOOP_KEYS(k, key) {
                                if(key->flag&PEK_HIDE) continue;
 
-                               if(key_inside_circle(data->mval,data->rad,key->world_co,&data->dist) && (selected==0 || key->flag&PEK_SELECT) && test_key_depth(key->world_co,&mats)){
-                                       func(psys,mat,imat,i,k,userData);
-                               }
+                               if(selected==0 || key->flag & PEK_SELECT)
+                                       if(key_inside_circle(data, data->rad, key->world_co, &data->dist))
+                                               func(data, mat, imat, i, k);
                        }
                }
        }
 }
 
-static void foreach_selected_element(ParticleSystem *psys, void (*func)(ParticleSystem *psys, int index, void *userData), void *userData)
+static void foreach_selected_particle(PEData *data, ForParticleFunc func)
 {
+       ParticleSystem *psys= data->psys;
        ParticleData *pa;
-       int i,totpart;
-
-       if(psys==0) return;
+       int i, totpart;
 
-       totpart=psys->totpart;
+       totpart= psys->totpart;
 
-       LOOP_PARTICLES(i,pa)
+       LOOP_PARTICLES(i, pa)
                if(particle_is_selected(psys, pa))
-                       func(psys,i,userData);
+                       func(data, i);
 }
 
-static void foreach_selected_key(ParticleSystem *psys, void (*func)(ParticleSystem *psys, int pa_index, int key_index, void *userData), void *userData)
+static void foreach_selected_key(PEData *data, ForKeyFunc func)
 {
+       ParticleSystem *psys= data->psys;
        ParticleData *pa;
        ParticleEditKey *key;
-       int i,k,totpart;
+       int i, k, totpart;
 
-       if(psys==0) return;
+       totpart= psys->totpart;
 
-       totpart=psys->totpart;
+       LOOP_PARTICLES(i, pa) {
+               if(pa->flag & PARS_HIDE) continue;
 
-       LOOP_PARTICLES(i,pa){
-               if(pa->flag&PARS_HIDE) continue;
+               key= psys->edit->keys[i];
 
-               key=psys->edit->keys[i];
-               LOOP_KEYS(k,key){
-                       if(key->flag&PEK_SELECT)
-                               func(psys,i,k,userData);
-               }
+               LOOP_KEYS(k, key)
+                       if(key->flag & PEK_SELECT)
+                               func(data, i, k);
        }
 }
-void PE_foreach_element(ParticleSystem *psys, void (*func)(ParticleSystem *psys, int index, void *userData), void *userData)
-{
-       int i,totpart;
 
-       if(psys==0) return;
+void PE_foreach_particle(PEData *data, ForParticleFunc func)
+{
+       ParticleSystem *psys= data->psys;
+       int i, totpart;
 
-       totpart=psys->totpart;
+       totpart= psys->totpart;
 
        for(i=0; i<totpart; i++)
-               func(psys,i,userData);
+               func(data, i);
 }
+
 static int count_selected_keys(Scene *scene, ParticleSystem *psys)
 {
        ParticleData *pa;
        ParticleEditKey *key;
-       int i,k,totpart,sel=0;
+       ParticleEditSettings *pset= PE_settings(scene);
+       int i, k, totpart, sel= 0;
 
-       if(psys==0) return 0;
+       totpart= psys->totpart;
 
-       totpart=psys->totpart;
+       LOOP_PARTICLES(i, pa) {
+               if(pa->flag & PARS_HIDE) continue;
 
-       LOOP_PARTICLES(i,pa){
-               if(pa->flag&PARS_HIDE) continue;
+               key= psys->edit->keys[i];
 
-               key=psys->edit->keys[i];
-               if(scene->selectmode==SCE_SELECT_POINT){
-                       for(k=0; k<pa->totkey; k++,key++){
-                               if(key->flag&PEK_SELECT)
+               if(pset->selectmode==SCE_SELECT_POINT) {
+                       for(k=0; k<pa->totkey; k++,key++)
+                               if(key->flag & PEK_SELECT)
                                        sel++;
-                       }
                }
-               else if(scene->selectmode==SCE_SELECT_END){
-                       key+=pa->totkey-1;
-                       if(key->flag&PEK_SELECT)
+               else if(pset->selectmode==SCE_SELECT_END) {
+                       key += pa->totkey-1;
+
+                       if(key->flag & PEK_SELECT)
                                sel++;
                }
        }
+
        return sel;
 }
 
@@ -591,7 +653,7 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
        tree= BLI_kdtree_new(totpart);
 
        /* insert particles into kd tree */
-       LOOP_PARTICLES(i,pa) {
+       LOOP_PARTICLES(i, pa) {
                psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat);
                VECCOPY(co, pa->hair[0].co);
                Mat4MulVecfl(mat, co);
@@ -604,7 +666,7 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
        if(!edit->mirror_cache)
                edit->mirror_cache= MEM_callocN(sizeof(int)*totpart, "PE mirror cache");
        
-       LOOP_PARTICLES(i,pa) {
+       LOOP_PARTICLES(i, pa) {
                psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat);
                VECCOPY(co, pa->hair[0].co);
                Mat4MulVecfl(mat, co);
@@ -620,7 +682,7 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
        }
 
        /* make sure mirrors are in two directions */
-       LOOP_PARTICLES(i,pa) {
+       LOOP_PARTICLES(i, pa) {
                if(edit->mirror_cache[i]) {
                        index= edit->mirror_cache[i];
                        if(edit->mirror_cache[index] != i)
@@ -711,7 +773,7 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
 
        /* we delay settings the PARS_EDIT_RECALC for mirrored particles
         * to avoid doing mirror twice */
-       LOOP_PARTICLES(i,pa) {
+       LOOP_PARTICLES(i, pa) {
                if(pa->flag & PARS_EDIT_RECALC) {
                        PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
 
@@ -720,7 +782,7 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
                }
        }
 
-       LOOP_PARTICLES(i,pa)
+       LOOP_PARTICLES(i, pa)
                if(pa->flag & PARS_EDIT_RECALC)
                        if(edit->mirror_cache[i] != -1)
                                psys->particles[edit->mirror_cache[i]].flag |= PARS_EDIT_RECALC;
@@ -737,9 +799,9 @@ static void pe_deflect_emitter(Scene *scene, Object *ob, ParticleSystem *psys)
        ParticleEdit *edit;
        ParticleData *pa;
        ParticleEditKey *key;
-       ParticleEditSettings *pset = PE_settings(scene);
-       ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys);
-       int i,k,totpart,index;
+       ParticleEditSettings *pset= PE_settings(scene);
+       ParticleSystemModifierData *psmd= psys_get_modifier(ob,psys);
+       int i, k, totpart,index;
        float *vec, *nor, dvec[3], dot, dist_1st;
        float hairimat[4][4], hairmat[4][4];
 
@@ -749,27 +811,27 @@ static void pe_deflect_emitter(Scene *scene, Object *ob, ParticleSystem *psys)
        if((pset->flag & PE_DEFLECT_EMITTER)==0)
                return;
 
-       edit=psys->edit;
-       totpart=psys->totpart;
+       edit= psys->edit;
+       totpart= psys->totpart;
 
-       LOOP_PARTICLES(i,pa){
+       LOOP_PARTICLES(i, pa) {
                if(!(pa->flag & PARS_EDIT_RECALC))
                        continue;
                
                psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, hairmat);
                
-               LOOP_KEYS(k,key){
+               LOOP_KEYS(k, key) {
                        Mat4MulVecfl(hairmat, key->co);
                }
        //}
 
-       //LOOP_PARTICLES(i,pa){
+       //LOOP_PARTICLES(i, pa) {
                key=psys->edit->keys[i]+1;
 
                dist_1st=VecLenf((key-1)->co,key->co);
                dist_1st*=0.75f*pset->emitterdist;
 
-               for(k=1; k<pa->totkey; k++, key++){
+               for(k=1; k<pa->totkey; k++, key++) {
                        index= BLI_kdtree_find_nearest(edit->emitter_field,key->co,NULL,NULL);
                        
                        vec=edit->emitter_cosnos +index*6;
@@ -780,14 +842,14 @@ static void pe_deflect_emitter(Scene *scene, Object *ob, ParticleSystem *psys)
                        dot=Inpf(dvec,nor);
                        VECCOPY(dvec,nor);
 
-                       if(dot>0.0f){
-                               if(dot<dist_1st){
+                       if(dot>0.0f) {
+                               if(dot<dist_1st) {
                                        Normalize(dvec);
                                        VecMulf(dvec,dist_1st-dot);
                                        VecAddf(key->co,key->co,dvec);
                                }
                        }
-                       else{
+                       else {
                                Normalize(dvec);
                                VecMulf(dvec,dist_1st-dot);
                                VecAddf(key->co,key->co,dvec);
@@ -797,11 +859,11 @@ static void pe_deflect_emitter(Scene *scene, Object *ob, ParticleSystem *psys)
                }
        //}
 
-       //LOOP_PARTICLES(i,pa){
+       //LOOP_PARTICLES(i, pa) {
                
                Mat4Invert(hairimat,hairmat);
 
-               LOOP_KEYS(k,key){
+               LOOP_KEYS(k, key) {
                        Mat4MulVecfl(hairimat, key->co);
                }
        }
@@ -813,7 +875,7 @@ void PE_apply_lengths(Scene *scene, ParticleSystem *psys)
        ParticleData *pa;
        ParticleEditKey *key;
        ParticleEditSettings *pset=PE_settings(scene);
-       int i,k,totpart;
+       int i, k, totpart;
        float dv1[3];
 
        if(psys==0)
@@ -822,14 +884,14 @@ void PE_apply_lengths(Scene *scene, ParticleSystem *psys)
        if((pset->flag & PE_KEEP_LENGTHS)==0)
                return;
 
-       edit=psys->edit;
-       totpart=psys->totpart;
+       edit= psys->edit;
+       totpart= psys->totpart;
 
-       LOOP_PARTICLES(i,pa){
+       LOOP_PARTICLES(i, pa) {
                if(!(pa->flag & PARS_EDIT_RECALC))
                        continue;
                
-               for(k=1, key=edit->keys[i] + 1; k<pa->totkey; k++, key++){
+               for(k=1, key=edit->keys[i] + 1; k<pa->totkey; k++, key++) {
                        VecSubf(dv1, key->co, (key - 1)->co);
                        Normalize(dv1);
                        VecMulf(dv1, (key - 1)->length);
@@ -844,11 +906,11 @@ static void pe_iterate_lengths(Scene *scene, ParticleSystem *psys)
        ParticleData *pa;
        ParticleEditKey *key;
        ParticleEditSettings *pset=PE_settings(scene);
-       int i, j, k,totpart;
+       int i, j, k, totpart;
        float tlen;
-       float dv0[3] = {0.0f, 0.0f, 0.0f};
-       float dv1[3] = {0.0f, 0.0f, 0.0f};
-       float dv2[3] = {0.0f, 0.0f, 0.0f};
+       float dv0[3]= {0.0f, 0.0f, 0.0f};
+       float dv1[3]= {0.0f, 0.0f, 0.0f};
+       float dv2[3]= {0.0f, 0.0f, 0.0f};
 
        if(psys==0)
                return;
@@ -856,41 +918,41 @@ static void pe_iterate_lengths(Scene *scene, ParticleSystem *psys)
        if((pset->flag & PE_KEEP_LENGTHS)==0)
                return;
 
-       edit=psys->edit;
-       totpart=psys->totpart;
+       edit= psys->edit;
+       totpart= psys->totpart;
 
-       LOOP_PARTICLES(i,pa){
+       LOOP_PARTICLES(i, pa) {
                if(!(pa->flag & PARS_EDIT_RECALC))
                        continue;
 
-               for(j=1; j<pa->totkey; j++){
-                       float mul = 1.0f / (float)pa->totkey;
+               for(j=1; j<pa->totkey; j++) {
+                       float mul= 1.0f / (float)pa->totkey;
 
-                       if(pset->flag & PE_LOCK_FIRST){
-                               key = edit->keys[i] + 1;
-                               k = 1;
-                               dv1[0] = dv1[1] = dv1[2] = 0.0;
+                       if(pset->flag & PE_LOCK_FIRST) {
+                               key= edit->keys[i] + 1;
+                               k= 1;
+                               dv1[0]= dv1[1]= dv1[2]= 0.0;
                        }
-                       else{
-                               key = edit->keys[i];
-                               k = 0;
-                               dv0[0] = dv0[1] = dv0[2] = 0.0;
+                       else {
+                               key= edit->keys[i];
+                               k= 0;
+                               dv0[0]= dv0[1]= dv0[2]= 0.0;
                        }
 
-                       for(; k<pa->totkey; k++, key++){
-                               if(k){
+                       for(; k<pa->totkey; k++, key++) {
+                               if(k) {
                                        VecSubf(dv0, (key - 1)->co, key->co);
-                                       tlen = Normalize(dv0);
+                                       tlen= Normalize(dv0);
                                        VecMulf(dv0, (mul * (tlen - (key - 1)->length)));
                                }
 
-                               if(k < pa->totkey - 1){
+                               if(k < pa->totkey - 1) {
                                        VecSubf(dv2, (key + 1)->co, key->co);
-                                       tlen = Normalize(dv2);
+                                       tlen= Normalize(dv2);
                                        VecMulf(dv2, mul * (tlen - key->length));
                                }
 
-                               if(k){
+                               if(k) {
                                        VecAddf((key-1)->co,(key-1)->co,dv1);
                                }
 
@@ -909,43 +971,21 @@ static void recalc_lengths(ParticleSystem *psys)
        if(psys==0)
                return;
 
-       totpart = psys->totpart;
+       totpart= psys->totpart;
 
-       LOOP_PARTICLES(i,pa){
-               key = psys->edit->keys[i];
-               for(k=0; k<pa->totkey-1; k++, key++){
-                       key->length = VecLenf(key->co, (key + 1)->co);
+       LOOP_PARTICLES(i, pa) {
+               key= psys->edit->keys[i];
+               for(k=0; k<pa->totkey-1; k++, key++) {
+                       key->length= VecLenf(key->co, (key + 1)->co);
                }
        }
 }
-/* calculate and store key locations in world coordinates */
-void PE_recalc_world_cos(Object *ob, ParticleSystem *psys)
-{
-       ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
-       ParticleData *pa;
-       ParticleEditKey *key;
-       int i, k, totpart;
-       float hairmat[4][4];
 
-       if(psys==0)
-               return;
-
-       totpart = psys->totpart;
-
-       LOOP_PARTICLES(i,pa){
-               psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
-
-               LOOP_KEYS(k,key){
-                       VECCOPY(key->world_co,key->co);
-                       Mat4MulVecfl(hairmat, key->world_co);
-               }
-       }
-}
 /* calculate a tree for finding nearest emitter's vertice */
 static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
 {
        DerivedMesh *dm=psys_get_modifier(ob,psys)->dm;
-       ParticleEdit *edit = psys->edit;
+       ParticleEdit *edit= psys->edit;
        MFace *mface;
        MVert *mvert;
        float *vec, *nor;
@@ -967,7 +1007,7 @@ static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
        nor=vec+3;
 
        mvert=dm->getVertDataArray(dm,CD_MVERT);
-       for(i=0; i<totface; i++, vec+=6, nor+=6){
+       for(i=0; i<totface; i++, vec+=6, nor+=6) {
                mface=dm->getFaceData(dm,i,CD_MFACE);
 
                mvert=dm->getVertData(dm,mface->v1,CD_MVERT);
@@ -982,7 +1022,7 @@ static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
                VECADD(vec,vec,mvert->co);
                VECADD(nor,nor,mvert->no);
 
-               if (mface->v4){
+               if(mface->v4) {
                        mvert=dm->getVertData(dm,mface->v4,CD_MVERT);
                        VECADD(vec,vec,mvert->co);
                        VECADD(nor,nor,mvert->no);
@@ -1000,9 +1040,9 @@ static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
        BLI_kdtree_balance(edit->emitter_field);
 }
 
-void PE_update_selection(Scene *scene, Object *ob, int useflag)
+static void PE_update_selection(Scene *scene, Object *ob, int useflag)
 {
-       ParticleSystem *psys= PE_get_current(ob);
+       ParticleSystem *psys= PE_get_current(scene, ob);
        ParticleEdit *edit= psys->edit;
        ParticleEditSettings *pset= PE_settings(scene);
        ParticleSettings *part= psys->part;
@@ -1016,13 +1056,13 @@ void PE_update_selection(Scene *scene, Object *ob, int useflag)
 
        /* flag all particles to be updated if not using flag */
        if(!useflag)
-               LOOP_PARTICLES(i,pa)
+               LOOP_PARTICLES(i, pa)
                        pa->flag |= PARS_EDIT_RECALC;
 
        /* flush edit key flag to hair key flag to preserve selection 
         * on save */
-       LOOP_PARTICLES(i,pa) {
-               key = edit->keys[i];
+       LOOP_PARTICLES(i, pa) {
+               key= edit->keys[i];
 
                for(k=0, hkey=pa->hair; k<pa->totkey; k++, hkey++, key++)
                        hkey->editflag= key->flag;
@@ -1034,13 +1074,13 @@ void PE_update_selection(Scene *scene, Object *ob, int useflag)
                psys_cache_child_paths(scene, ob, psys, cfra, 1);
 
        /* disable update flag */
-       LOOP_PARTICLES(i,pa)
+       LOOP_PARTICLES(i, pa)
                pa->flag &= ~PARS_EDIT_RECALC;
 }
 
 void PE_update_object(Scene *scene, Object *ob, int useflag)
 {
-       ParticleSystem *psys= PE_get_current(ob);
+       ParticleSystem *psys= PE_get_current(scene, ob);
        ParticleEditSettings *pset= PE_settings(scene);
        ParticleSettings *part= psys->part;
        ParticleData *pa;
@@ -1049,7 +1089,7 @@ void PE_update_object(Scene *scene, Object *ob, int useflag)
 
        /* flag all particles to be updated if not using flag */
        if(!useflag)
-               LOOP_PARTICLES(i,pa)
+               LOOP_PARTICLES(i, pa)
                        pa->flag |= PARS_EDIT_RECALC;
 
        /* do post process on particle edit keys */
@@ -1058,7 +1098,7 @@ void PE_update_object(Scene *scene, Object *ob, int useflag)
        PE_apply_lengths(scene, psys);
        if(pset->flag & PE_X_MIRROR)
                PE_apply_mirror(ob,psys);
-       PE_recalc_world_cos(ob,psys);
+       psys_update_world_cos(ob,psys);
        PE_hide_keys_time(scene, psys, cfra);
 
        /* regenerate path caches */
@@ -1068,252 +1108,90 @@ void PE_update_object(Scene *scene, Object *ob, int useflag)
                psys_cache_child_paths(scene, ob, psys, cfra, 1);
 
        /* disable update flag */
-       LOOP_PARTICLES(i,pa)
+       LOOP_PARTICLES(i, pa)
                pa->flag &= ~PARS_EDIT_RECALC;
 }
 
-/* initialize needed data for bake edit */
-void PE_create_particle_edit(Object *ob, ParticleSystem *psys)
-{
-       Scene *scene= NULL; // XXX
-       ParticleEdit *edit=psys->edit;
-       ParticleData *pa;
-       ParticleEditKey *key;
-       HairKey *hkey;
-       int i,k, totpart=psys->totpart, alloc=1;
-
-       if((psys->flag & PSYS_EDITED)==0)
-               return;
-
-       if(edit){
-               int newtotkeys = psys_count_keys(psys);
-               if(newtotkeys == edit->totkeys)
-                       alloc=0;
-       }
-
-       if(alloc){
-               if(edit){
-                       error("ParticleEdit exists allready! Poke jahka!");
-                       PE_free_particle_edit(psys);
-               }
-
-               edit=psys->edit=MEM_callocN(sizeof(ParticleEdit), "PE_create_particle_edit");
-
-               edit->keys=MEM_callocN(totpart*sizeof(ParticleEditKey*),"ParticleEditKey array");
-
-               LOOP_PARTICLES(i,pa){
-                       key = edit->keys[i] = MEM_callocN(pa->totkey*sizeof(ParticleEditKey),"ParticleEditKeys");
-                       for(k=0, hkey=pa->hair; k<pa->totkey; k++, hkey++, key++){
-                               key->co = hkey->co;
-                               key->time = &hkey->time;
-                               key->flag= hkey->editflag;
-                       }
-               }
-
-               edit->totkeys = psys_count_keys(psys);
-       }
-
-       recalc_lengths(psys);
-       recalc_emitter_field(ob, psys);
-       PE_recalc_world_cos(ob, psys);
-
-       if(alloc) {
-               ParticleUndo_clear(psys);
-               PE_undo_push(scene, "Original");
-       }
-}
-
-/* toggle particle mode on & off */
-void PE_set_particle_edit(Scene *scene)
-{
-       Object *ob= OBACT;
-       ParticleSystem *psys = PE_get_current(ob);
-
-       
-       //if(!ob || ob->id.lib) return; /* is the id.lib test needed? -jahka*/
-       if(ob==0 || psys==0) return;
-       
-       if(psys==0){
-               if(ob->particlesystem.first){
-                       psys=ob->particlesystem.first;
-                       psys->flag |= PSYS_CURRENT;
-               }
-               else
-                       return;
-       }
-
-       if((G.f & G_PARTICLEEDIT)==0){
-               if(psys && psys->part->type == PART_HAIR && psys->flag & PSYS_EDITED) {
-                       if(psys_check_enabled(ob, psys)) {
-                               if(psys->edit==0)
-                                       PE_create_particle_edit(ob, psys);
-                               PE_recalc_world_cos(ob, psys);
-                       }
-               }
-
-               G.f |= G_PARTICLEEDIT;
-       }
-       else{
-               G.f &= ~G_PARTICLEEDIT;
-       }
-
-       DAG_object_flush_update(scene, OBACT, OB_RECALC_DATA);
-
-}
-
 /************************************************/
 /*                     Edit Selections                                         */
 /************************************************/
+
 /*-----selection callbacks-----*/
-static void select_key(ParticleSystem *psys, int pa_index, int key_index, void *userData)
+
+static void select_key(PEData *data, int pa_index, int key_index)
 {
-       struct {Scene *scene; short *mval; float rad; rcti* rect; int select; } *data = userData;
-       ParticleData *pa = psys->particles + pa_index;
-       ParticleEditKey *key = psys->edit->keys[pa_index] + key_index;
+       ParticleSystem *psys= data->psys;
+       ParticleData *pa= psys->particles + pa_index;
+       ParticleEditKey *key= psys->edit->keys[pa_index] + key_index;
 
        if(data->select)
-               key->flag|=PEK_SELECT;
+               key->flag |= PEK_SELECT;
        else
-               key->flag&=~PEK_SELECT;
+               key->flag &= ~PEK_SELECT;
 
        pa->flag |= PARS_EDIT_RECALC;
 }
 
-static void select_keys(ParticleSystem *psys, int pa_index, int key_index, void *userData)
+static void select_keys(PEData *data, int pa_index, int key_index)
 {
-       struct {Scene *scene; short *mval; float rad; rcti* rect; int select; } *data = userData;
-       ParticleData *pa = psys->particles + pa_index;
-       ParticleEditKey *key = psys->edit->keys[pa_index];
+       ParticleSystem *psys= data->psys;
+       ParticleData *pa= psys->particles + pa_index;
+       ParticleEditKey *key= psys->edit->keys[pa_index];
        int k;
 
-       for(k=0; k<pa->totkey; k++,key++){
+       for(k=0; k<pa->totkey; k++,key++) {
                if(data->select)
-                       key->flag|=PEK_SELECT;
+                       key->flag |= PEK_SELECT;
                else
-                       key->flag&=~PEK_SELECT;
+                       key->flag &= ~PEK_SELECT;
        }
 
        pa->flag |= PARS_EDIT_RECALC;
 }
 
-static void toggle_key_select(ParticleSystem *psys, int pa_index, int key_index, void *userData)
+static void toggle_key_select(PEData *data, int pa_index, int key_index)
 {
-       ParticleData *pa = psys->particles + pa_index;
+       ParticleSystem *psys= data->psys;
+       ParticleData *pa= psys->particles + pa_index;
 
        if(psys->edit->keys[pa_index][key_index].flag&PEK_SELECT)
-               psys->edit->keys[pa_index][key_index].flag&=~PEK_SELECT;
+               psys->edit->keys[pa_index][key_index].flag &= ~PEK_SELECT;
        else
-               psys->edit->keys[pa_index][key_index].flag|=PEK_SELECT;
+               psys->edit->keys[pa_index][key_index].flag |= PEK_SELECT;
        
        pa->flag |= PARS_EDIT_RECALC;
 }
 
-static void select_root(ParticleSystem *psys, int index, void *userData)
-{
-       psys->edit->keys[index]->flag |= PEK_SELECT;
-}
+/************************ de select all operator ************************/
 
-static void select_tip(ParticleSystem *psys, int index, void *userData)
+static int de_select_all_exec(bContext *C, wmOperator *op)
 {
-       ParticleData *pa = psys->particles + index;
-       ParticleEditKey *key = psys->edit->keys[index] + pa->totkey-1;
-
-       key->flag |= PEK_SELECT;
-}
-static void select_more_keys(ParticleSystem *psys, int index, void *userData)
-{
-       ParticleEdit *edit = psys->edit;
-       ParticleData *pa = psys->particles+index;
-       ParticleEditKey *key;
-       int k;
-
-       for(k=0,key=edit->keys[index]; k<pa->totkey; k++,key++){
-               if(key->flag&PEK_SELECT) continue;
-
-               if(k==0){
-                       if((key+1)->flag&PEK_SELECT)
-                               key->flag |= PEK_TO_SELECT;
-               }
-               else if(k==pa->totkey-1){
-                       if((key-1)->flag&PEK_SELECT)
-                               key->flag |= PEK_TO_SELECT;
-               }
-               else{
-                       if(((key-1)->flag | (key+1)->flag) & PEK_SELECT)
-                               key->flag |= PEK_TO_SELECT;
-               }
-       }
-
-       for(k=0,key=edit->keys[index]; k<pa->totkey; k++,key++){
-               if(key->flag&PEK_TO_SELECT){
-                       key->flag &= ~PEK_TO_SELECT;
-                       key->flag |= PEK_SELECT;
-               }
-       }
-}
-
-static void select_less_keys(ParticleSystem *psys, int index, void *userData)
-{
-       ParticleEdit *edit = psys->edit;
-       ParticleData *pa = psys->particles+index;
-       ParticleEditKey *key;
-       int k;
-
-       for(k=0,key=edit->keys[index]; k<pa->totkey; k++,key++){
-               if((key->flag&PEK_SELECT)==0) continue;
-
-               if(k==0){
-                       if(((key+1)->flag&PEK_SELECT)==0)
-                               key->flag |= PEK_TO_SELECT;
-               }
-               else if(k==pa->totkey-1){
-                       if(((key-1)->flag&PEK_SELECT)==0)
-                               key->flag |= PEK_TO_SELECT;
-               }
-               else{
-                       if((((key-1)->flag & (key+1)->flag) & PEK_SELECT)==0)
-                               key->flag |= PEK_TO_SELECT;
-               }
-       }
-
-       for(k=0,key=edit->keys[index]; k<pa->totkey; k++,key++){
-               if(key->flag&PEK_TO_SELECT)
-                       key->flag &= ~(PEK_TO_SELECT|PEK_SELECT);
-       }
-}
-
-/*-----using above callbacks-----*/
-void PE_deselectall(void)
-{
-       Scene *scene= NULL;
-       Object *ob = OBACT;
-       ParticleSystem *psys = PE_get_current(ob);
-       ParticleEdit *edit = 0;
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       ParticleSystem *psys= PE_get_current(scene, ob);
+       ParticleEdit *edit= 0;
        ParticleData *pa;
        ParticleEditKey *key;
-       int i,k,totpart, sel = 0;
-               
-       if(!PE_can_edit(psys)) return;
+       int i, k, totpart, sel= 0;
        
-       edit = psys->edit;
-
-       totpart = psys->totpart;
+       edit= psys->edit;
+       totpart= psys->totpart;
        
-       LOOP_PARTICLES(i,pa){
+       LOOP_PARTICLES(i, pa) {
                if(pa->flag & PARS_HIDE) continue;
-               LOOP_KEYS(k,key){
-                       if(key->flag&PEK_SELECT){
-                               sel = 1;
+               LOOP_KEYS(k, key) {
+                       if(key->flag & PEK_SELECT) {
+                               sel= 1;
                                key->flag &= ~PEK_SELECT;
                                pa->flag |= PARS_EDIT_RECALC;
                        }
                }
        }
 
-       if(sel==0){
-               LOOP_PARTICLES(i,pa){
+       if(sel==0) {
+               LOOP_PARTICLES(i, pa) {
                        if(pa->flag & PARS_HIDE) continue;
-                       LOOP_KEYS(k,key){
+                       LOOP_KEYS(k, key) {
                                if(!(key->flag & PEK_SELECT)) {
                                        key->flag |= PEK_SELECT;
                                        pa->flag |= PARS_EDIT_RECALC;
@@ -1323,206 +1201,303 @@ void PE_deselectall(void)
        }
 
        PE_update_selection(scene, ob, 1);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
 
-       BIF_undo_push("(De)select all keys");
+       return OPERATOR_FINISHED;
 }
 
-void PE_mouse_particles(void)
+void PARTICLE_OT_select_all_toggle(wmOperatorType *ot)
 {
-       struct {Scene *scene;  short *mval; float rad; rcti* rect; int select; } data;
-       Scene *scene= NULL;
-       Object *ob = OBACT;
-       ParticleSystem *psys = PE_get_current(ob);
-       ParticleEdit *edit = 0;
-       ParticleData *pa;
-       ParticleEditKey *key;
-       short mval[2];
-       int i,k,totpart;
-       int shift= 0; // XXX
+       /* identifiers */
+       ot->name= "Select or Deselect All";
+       ot->idname= "PARTICLE_OT_select_all_toggle";
        
-       if(!PE_can_edit(psys)) return;
+       /* api callbacks */
+       ot->exec= de_select_all_exec;
+       ot->poll= PE_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
 
-       edit = psys->edit;
+/************************ pick select operator ************************/
 
-       totpart = psys->totpart;
+int PE_mouse_particles(bContext *C, short *mval, int extend)
+{
+       PEData data;
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       ParticleSystem *psys= PE_get_current(scene, ob);
+       ParticleEdit *edit= 0;
+       ParticleData *pa;
+       ParticleEditKey *key;
+       int i, k, totpart;
+       
+       if(!PE_can_edit(psys))
+               return OPERATOR_CANCELLED;
 
-       bglFlush();
-       glReadBuffer(GL_BACK);
-       glDrawBuffer(GL_BACK);
-//     persp(PERSP_VIEW);
+       edit= psys->edit;
+       totpart= psys->totpart;
 
-       if(shift)
-               LOOP_PARTICLES(i,pa){
+       if(!extend) {
+               LOOP_PARTICLES(i, pa) {
                        if(pa->flag & PARS_HIDE) continue;
-                       LOOP_KEYS(k,key){
+                       LOOP_KEYS(k, key) {
                                if(key->flag & PEK_SELECT) {
                                        key->flag &= ~PEK_SELECT;
                                        pa->flag |= PARS_EDIT_RECALC;
                                }
                        }
                }
+       }
 
-//     getmouseco_areawin(mval);
-
-       data.scene= scene;
+       PE_set_view3d_data(C, &data);
        data.mval= mval;
        data.rad= 75.0f;
-       data.rect= 0;
-       data.select= 0;
 
-       for_mouse_hit_keys(1,psys,toggle_key_select,&data);
+       for_mouse_hit_keys(&data, toggle_key_select, 1);  /* nearest only */
 
        PE_update_selection(scene, ob, 1);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
 
+       return OPERATOR_FINISHED;
 }
 
-void PE_select_root(void)
+/************************ select first operator ************************/
+
+static void select_root(PEData *data, int pa_index)
 {
-       Object *ob=NULL; // XXX
-       ParticleSystem *psys = PE_get_current(ob);
+       ParticleSystem *psys= data->psys;
 
-       if(!PE_can_edit(psys)) return;
+       psys->edit->keys[pa_index]->flag |= PEK_SELECT;
+}
 
-       PE_foreach_element(psys,select_root,NULL);
-       BIF_undo_push("Select first");
+static int select_first_exec(bContext *C, wmOperator *op)
+{
+       PEData data;
+
+       PE_set_data(C, &data);
+       PE_foreach_particle(&data, select_root);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
+
+       return OPERATOR_FINISHED;
 }
 
-void PE_select_tip()
+void PARTICLE_OT_select_first(wmOperatorType *ot)
 {
-       Object *ob=NULL; // XXX
-       ParticleSystem *psys = PE_get_current(ob);
+       /* identifiers */
+       ot->name= "Select First";
+       ot->idname= "PARTICLE_OT_select_first";
+       
+       /* api callbacks */
+       ot->exec= select_first_exec;
+       ot->poll= PE_poll;
 
-       if(!PE_can_edit(psys)) return;
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/************************ select last operator ************************/
+
+static void select_tip(PEData *data, int pa_index)
+{
+       ParticleSystem *psys= data->psys;
+       ParticleData *pa= psys->particles + pa_index;
+       ParticleEditKey *key= psys->edit->keys[pa_index] + pa->totkey-1;
 
-       PE_foreach_element(psys,select_tip,NULL);
-       BIF_undo_push("Select last");
+       key->flag |= PEK_SELECT;
 }
 
-void PE_select_linked(void)
+static int select_last_exec(bContext *C, wmOperator *op)
 {
-       struct {Scene *scene;  short *mval; float rad; rcti* rect; int select; } data;
-       Object *ob=NULL; // XXX
-       Scene *scene= NULL;
-       ParticleSystem *psys = PE_get_current(ob);
-       short mval[2];
-       int shift= 0; // XXX
+       PEData data;
+
+       PE_set_data(C, &data);
+       PE_foreach_particle(&data, select_tip);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
+
+       return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_select_last(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Select Last";
+       ot->idname= "PARTICLE_OT_select_last";
        
-       if(!PE_can_edit(psys)) return;
+       /* api callbacks */
+       ot->exec= select_last_exec;
+       ot->poll= PE_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/************************ select linked operator ************************/
+
+static int select_linked_exec(bContext *C, wmOperator *op)
+{
+       PEData data;
+       short mval[2];
+       int location[2];
+
+       RNA_int_get_array(op->ptr, "location", location);
+       mval[0]= location[0];
+       mval[1]= location[1];
 
-//     getmouseco_areawin(mval);
+       view3d_operator_needs_opengl(C);
 
-       data.scene= NULL; // XXX
-       data.mval=mval;
+       PE_set_view3d_data(C, &data);
+       data.mval= mval;
        data.rad=75.0f;
-       data.rect=0;
-       data.select=(shift);
+       data.select= !RNA_boolean_get(op->ptr, "deselect");
 
-       for_mouse_hit_keys(1,psys,select_keys,&data);
+       for_mouse_hit_keys(&data, select_keys, 1);  /* nearest only */
+       PE_update_selection(data.scene, data.ob, 1);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
 
-       PE_update_selection(scene, ob, 1);
+       return OPERATOR_FINISHED;
+}
+
+static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       ARegion *ar= CTX_wm_region(C);
+       int location[2];
 
-       BIF_undo_push("Select linked keys");
+       location[0]= event->x - ar->winrct.xmin;
+       location[1]= event->y - ar->winrct.ymin;
+       RNA_int_set_array(op->ptr, "location", location);
 
-       return;
+       return select_linked_exec(C, op);
 }
 
-void PE_borderselect(ViewContext *vc, rcti *rect, int select)
+void PARTICLE_OT_select_linked(wmOperatorType *ot)
 {
-       struct {Scene *scene;  short *mval; float rad; rcti* rect; int select; } data;
-       Scene *scene= vc->scene;
-       Object *ob= vc->obact;
-       ParticleSystem *psys = PE_get_current(ob);
+       /* identifiers */
+       ot->name= "Select Linked";
+       ot->idname= "PARTICLE_OT_select_linked";
+       
+       /* api callbacks */
+       ot->exec= select_linked_exec;
+       ot->invoke= select_linked_invoke;
+       ot->poll= PE_poll_3dview;
 
-       if(!PE_can_edit(psys)) return;
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       /* properties */
+       RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked keys rather than selecting them.");
+       RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384);
+}
+
+/************************ border select operator ************************/
+
+int PE_border_select(bContext *C, rcti *rect, int select)
+{
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       ParticleSystem *psys= PE_get_current(scene, ob);
+       PEData data;
 
-       data.scene= scene;
-       data.mval=0;
+       if(!PE_can_edit(psys))
+               return OPERATOR_CANCELLED;
+
+       PE_set_view3d_data(C, &data);
        data.rect= rect;
        data.select= select;
 
-       for_mouse_hit_keys(0, psys, select_key, &data);
+       for_mouse_hit_keys(&data, select_key, 0);
 
        PE_update_selection(scene, ob, 1);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
 
-       BIF_undo_push("Select keys");
-
-       return;
+       return OPERATOR_FINISHED;
 }
 
-void PE_selectionCB(short selecting, Object *editobj, short *mval, float rad)
+/************************ circle select operator ************************/
+
+int PE_circle_select(bContext *C, int selecting, short *mval, float rad)
 {
-       struct {Scene *scene;  short *mval; float rad; rcti* rect; int select; } data;
-       Scene *scene= NULL;
-       ParticleSystem *psys = PE_get_current(OBACT);
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       ParticleSystem *psys= PE_get_current(scene, ob);
+       PEData data;
 
-       if(!PE_can_edit(psys)) return;
+       if(!PE_can_edit(psys))
+               return OPERATOR_FINISHED;
 
-       data.scene= scene;
-       data.mval=mval;
-       data.rad=rad;
-       data.rect=0;
-       data.select=(selecting==LEFTMOUSE);
+       PE_set_view3d_data(C, &data);
+       data.mval= mval;
+       data.rad= rad;
+       data.select= selecting;
+
+       for_mouse_hit_keys(&data, select_key, 0);
 
-       for_mouse_hit_keys(0,psys,select_key,&data);
+       PE_update_selection(scene, ob, 1);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
 
-//     draw_sel_circle(0, 0, 0, 0, 0); /* signal */
+       return OPERATOR_FINISHED;
 }
 
-void PE_do_lasso_select(ViewContext *vc, short mcords[][2], short moves, short select)
+/************************ lasso select operator ************************/
+
+int PE_lasso_select(bContext *C, short mcords[][2], short moves, short select)
 {
-       Scene *scene= vc->scene;
-       ARegion *ar= vc->ar;
-       Object *ob = OBACT;
-       ParticleSystem *psys = PE_get_current(ob);
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       ARegion *ar= CTX_wm_region(C);
+       ParticleSystem *psys= PE_get_current(scene, ob);
        ParticleSystemModifierData *psmd;
        ParticleEdit *edit;
        ParticleData *pa;
        ParticleEditKey *key;
+       ParticleEditSettings *pset= PE_settings(scene);
        float co[3], mat[4][4];
        short vertco[2];
        int i, k, totpart;
 
-       if(!PE_can_edit(psys)) return;
+       if(!PE_can_edit(psys))
+               return OPERATOR_CANCELLED;
 
        psmd= psys_get_modifier(ob, psys);
-       edit=psys->edit;
-       totpart=psys->totpart;
+       edit= psys->edit;
+       totpart= psys->totpart;
 
-       LOOP_PARTICLES(i,pa){
+       LOOP_PARTICLES(i, pa) {
                if(pa->flag & PARS_HIDE) continue;
 
                psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, mat);
 
-               if(scene->selectmode==SCE_SELECT_POINT){
-                       LOOP_KEYS(k,key){
+               if(pset->selectmode==SCE_SELECT_POINT) {
+                       LOOP_KEYS(k, key) {
                                VECCOPY(co, key->co);
                                Mat4MulVecfl(mat, co);
                                project_short(ar, co, vertco);
-                               if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1])){
+                               if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1])) {
                                        if(select && !(key->flag & PEK_SELECT)) {
-                                               key->flag|=PEK_SELECT;
+                                               key->flag |= PEK_SELECT;
                                                pa->flag |= PARS_EDIT_RECALC;
                                        }
                                        else if(key->flag & PEK_SELECT) {
-                                               key->flag&=~PEK_SELECT;
+                                               key->flag &= ~PEK_SELECT;
                                                pa->flag |= PARS_EDIT_RECALC;
                                        }
                                }
                        }
                }
-               else if(scene->selectmode==SCE_SELECT_END){
-                       key = edit->keys[i] + pa->totkey - 1;
+               else if(pset->selectmode==SCE_SELECT_END) {
+                       key= edit->keys[i] + pa->totkey - 1;
 
                        VECCOPY(co, key->co);
                        Mat4MulVecfl(mat, co);
                        project_short(ar, co,vertco);
-                       if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1])){
+                       if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1])) {
                                if(select && !(key->flag & PEK_SELECT)) {
-                                       key->flag|=PEK_SELECT;
+                                       key->flag |= PEK_SELECT;
                                        pa->flag |= PARS_EDIT_RECALC;
                                }
                                else if(key->flag & PEK_SELECT) {
-                                       key->flag&=~PEK_SELECT;
+                                       key->flag &= ~PEK_SELECT;
                                        pa->flag |= PARS_EDIT_RECALC;
                                }
                        }
@@ -1530,38 +1505,27 @@ void PE_do_lasso_select(ViewContext *vc, short mcords[][2], short moves, short s
        }
 
        PE_update_selection(scene, ob, 1);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
 
-       BIF_undo_push("Lasso select particles");
-
+       return OPERATOR_FINISHED;
 }
 
-void PE_hide(int mode)
+/*************************** hide operator **************************/
+
+static int hide_exec(bContext *C, wmOperator *op)
 {
-       Scene *scene= NULL;
-       Object *ob = OBACT;
-       ParticleSystem *psys = PE_get_current(ob);
+       Object *ob= CTX_data_active_object(C);
+       Scene *scene= CTX_data_scene(C);
+       ParticleSystem *psys= PE_get_current(scene, ob);
        ParticleEdit *edit;
        ParticleEditKey *key;
        ParticleData *pa;
        int i, k, totpart;
 
-       if(!PE_can_edit(psys)) return;
-
-       edit = psys->edit;
-       totpart = psys->totpart;
+       edit= psys->edit;
+       totpart= psys->totpart;
        
-       if(mode == 0){ /* reveal all particles */
-               LOOP_PARTICLES(i, pa){
-                       if(pa->flag & PARS_HIDE) {
-                               pa->flag &= ~PARS_HIDE;
-                               pa->flag |= PARS_EDIT_RECALC;
-
-                               LOOP_KEYS(k, key)
-                                       key->flag |= PEK_SELECT;
-                       }
-               }
-       }
-       else if(mode == 1){ /* hide unselected particles */
+       if(RNA_enum_get(op->ptr, "unselected")) {
                LOOP_PARTICLES(i, pa) {
                        if(!particle_is_selected(psys, pa)) {
                                pa->flag |= PARS_HIDE;
@@ -1572,7 +1536,7 @@ void PE_hide(int mode)
                        }
                }
        }
-       else{ /* hide selected particles */
+       else {
                LOOP_PARTICLES(i, pa) {
                        if(particle_is_selected(psys, pa)) {
                                pa->flag |= PARS_HIDE;
@@ -1585,43 +1549,198 @@ void PE_hide(int mode)
        }
 
        PE_update_selection(scene, ob, 1);
-       BIF_undo_push("(Un)hide elements");
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
+
+       return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_hide(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Hide Selected";
+       ot->idname= "PARTICLE_OT_hide";
        
+       /* api callbacks */
+       ot->exec= hide_exec;
+       ot->poll= PE_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       /* props */
+       RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
 }
 
-void PE_select_less(void)
+/*************************** reveal operator **************************/
+
+static int reveal_exec(bContext *C, wmOperator *op)
 {
-       Scene *scene= NULL;
-       ParticleSystem *psys = PE_get_current(OBACT);
+       Object *ob= CTX_data_active_object(C);
+       Scene *scene= CTX_data_scene(C);
+       ParticleSystem *psys= PE_get_current(scene, ob);
+       ParticleEdit *edit;
+       ParticleEditKey *key;
+       ParticleData *pa;
+       int i, k, totpart;
 
-       if(!PE_can_edit(psys)) return;
+       edit= psys->edit;
+       totpart= psys->totpart;
+
+       LOOP_PARTICLES(i, pa) {
+               if(pa->flag & PARS_HIDE) {
+                       pa->flag &= ~PARS_HIDE;
+                       pa->flag |= PARS_EDIT_RECALC;
 
-       PE_foreach_element(psys,select_less_keys,NULL);
+                       LOOP_KEYS(k, key)
+                               key->flag |= PEK_SELECT;
+               }
+       }
+
+       PE_update_selection(scene, ob, 1);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
+
+       return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_reveal(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Reveal";
+       ot->idname= "PARTICLE_OT_reveal";
        
-       BIF_undo_push("Select less");
+       /* api callbacks */
+       ot->exec= reveal_exec;
+       ot->poll= PE_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
-void PE_select_more(void)
+/************************ select less operator ************************/
+
+static void select_less_keys(PEData *data, int pa_index)
 {
-       Scene *scene= NULL;
-       ParticleSystem *psys = PE_get_current(OBACT);
+       ParticleSystem *psys= data->psys;
+       ParticleEdit *edit= psys->edit;
+       ParticleData *pa= &psys->particles[pa_index];
+       ParticleEditKey *key;
+       int k;
 
-       if(!PE_can_edit(psys)) return;
+       for(k=0,key=edit->keys[pa_index]; k<pa->totkey; k++,key++) {
+               if((key->flag & PEK_SELECT)==0) continue;
+
+               if(k==0) {
+                       if(((key+1)->flag&PEK_SELECT)==0)
+                               key->flag |= PEK_TO_SELECT;
+               }
+               else if(k==pa->totkey-1) {
+                       if(((key-1)->flag&PEK_SELECT)==0)
+                               key->flag |= PEK_TO_SELECT;
+               }
+               else {
+                       if((((key-1)->flag & (key+1)->flag) & PEK_SELECT)==0)
+                               key->flag |= PEK_TO_SELECT;
+               }
+       }
+
+       for(k=0,key=edit->keys[pa_index]; k<pa->totkey; k++,key++) {
+               if(key->flag&PEK_TO_SELECT)
+                       key->flag &= ~(PEK_TO_SELECT|PEK_SELECT);
+       }
+}
 
-       PE_foreach_element(psys,select_more_keys,NULL);
+static int select_less_exec(bContext *C, wmOperator *op)
+{
+       PEData data;
+
+       PE_set_data(C, &data);
+       PE_foreach_particle(&data, select_less_keys);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
+
+       return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_select_less(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Select Less";
+       ot->idname= "PARTICLE_OT_select_less";
        
-       BIF_undo_push("Select more");
+       /* api callbacks */
+       ot->exec= select_less_exec;
+       ot->poll= PE_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
-/************************************************/
-/*                     Edit Rekey                                                      */
-/************************************************/
-static void rekey_element(ParticleSystem *psys, int index, void *userData)
+/************************ select more operator ************************/
+
+static void select_more_keys(PEData *data, int pa_index)
+{
+       ParticleSystem *psys= data->psys;
+       ParticleEdit *edit= psys->edit;
+       ParticleData *pa= &psys->particles[pa_index];
+       ParticleEditKey *key;
+       int k;
+
+       for(k=0,key=edit->keys[pa_index]; k<pa->totkey; k++,key++) {
+               if(key->flag & PEK_SELECT) continue;
+
+               if(k==0) {
+                       if((key+1)->flag&PEK_SELECT)
+                               key->flag |= PEK_TO_SELECT;
+               }
+               else if(k==pa->totkey-1) {
+                       if((key-1)->flag&PEK_SELECT)
+                               key->flag |= PEK_TO_SELECT;
+               }
+               else {
+                       if(((key-1)->flag | (key+1)->flag) & PEK_SELECT)
+                               key->flag |= PEK_TO_SELECT;
+               }
+       }
+
+       for(k=0,key=edit->keys[pa_index]; k<pa->totkey; k++,key++) {
+               if(key->flag&PEK_TO_SELECT) {
+                       key->flag &= ~PEK_TO_SELECT;
+                       key->flag |= PEK_SELECT;
+               }
+       }
+}
+
+static int select_more_exec(bContext *C, wmOperator *op)
+{
+       PEData data;
+
+       PE_set_data(C, &data);
+       PE_foreach_particle(&data, select_more_keys);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
+
+       return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_select_more(wmOperatorType *ot)
 {
-       struct {Scene *scene; Object *ob; float dval; } *data = userData;
-       ParticleData *pa = psys->particles + index;
-       ParticleEdit *edit = psys->edit;
-       ParticleEditSettings *pset = PE_settings(data->scene);
+       /* identifiers */
+       ot->name= "Select More";
+       ot->idname= "PARTICLE_OT_select_more";
+       
+       /* api callbacks */
+       ot->exec= select_more_exec;
+       ot->poll= PE_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/************************ rekey operator ************************/
+
+static void rekey_particle(PEData *data, int pa_index)
+{
+       ParticleSystem *psys= data->psys;
+       ParticleData *pa= &psys->particles[pa_index];
+       ParticleEdit *edit= psys->edit;
        ParticleKey state;
        HairKey *key, *new_keys;
        ParticleEditKey *ekey;
@@ -1630,73 +1749,85 @@ static void rekey_element(ParticleSystem *psys, int index, void *userData)
 
        pa->flag |= PARS_REKEY;
 
-       key = new_keys = MEM_callocN(pset->totrekey * sizeof(HairKey),"Hair re-key keys");
+       key= new_keys= MEM_callocN(data->totrekey * sizeof(HairKey),"Hair re-key keys");
 
        /* root and tip stay the same */
        VECCOPY(key->co, pa->hair->co);
-       VECCOPY((key + pset->totrekey - 1)->co, (pa->hair + pa->totkey - 1)->co);
+       VECCOPY((key + data->totrekey - 1)->co, (pa->hair + pa->totkey - 1)->co);
 
-       sta = key->time = pa->hair->time;
-       end = (key + pset->totrekey - 1)->time = (pa->hair + pa->totkey - 1)->time;
-       dval = (end - sta) / (float)(pset->totrekey - 1);
+       sta= key->time= pa->hair->time;
+       end= (key + data->totrekey - 1)->time= (pa->hair + pa->totkey - 1)->time;
+       dval= (end - sta) / (float)(data->totrekey - 1);
 
        /* interpolate new keys from old ones */
-       for(k=1,key++; k<pset->totrekey-1; k++,key++) {
-               state.time = (float)k / (float)(pset->totrekey-1);
-               psys_get_particle_on_path(data->scene, data->ob, psys, index, &state, 0);
+       for(k=1,key++; k<data->totrekey-1; k++,key++) {
+               state.time= (float)k / (float)(data->totrekey-1);
+               psys_get_particle_on_path(data->scene, data->ob, psys, pa_index, &state, 0);
                VECCOPY(key->co, state.co);
-               key->time = sta + k * dval;
+               key->time= sta + k * dval;
        }
 
        /* replace keys */
        if(pa->hair)
                MEM_freeN(pa->hair);
-       pa->hair = new_keys;
+       pa->hair= new_keys;
 
-       pa->totkey=pset->totrekey;
+       pa->totkey=data->totrekey;
 
-       if(edit->keys[index])
-               MEM_freeN(edit->keys[index]);
-       ekey = edit->keys[index] = MEM_callocN(pa->totkey * sizeof(ParticleEditKey),"Hair re-key edit keys");
+       if(edit->keys[pa_index])
+               MEM_freeN(edit->keys[pa_index]);
+       ekey= edit->keys[pa_index]= MEM_callocN(pa->totkey * sizeof(ParticleEditKey),"Hair re-key edit keys");
                
        for(k=0, key=pa->hair; k<pa->totkey; k++, key++, ekey++) {
-               ekey->co = key->co;
-               ekey->time = &key->time;
+               ekey->co= key->co;
+               ekey->time= &key->time;
        }
 
        pa->flag &= ~PARS_REKEY;
        pa->flag |= PARS_EDIT_RECALC;
 }
 
-void PE_rekey(void)
+static int rekey_exec(bContext *C, wmOperator *op)
 {
-       Scene *scene= NULL; // XXX
-       Object *ob=OBACT;
-       ParticleSystem *psys = PE_get_current(ob);
-       ParticleEditSettings *pset = PE_settings(scene);
-       struct {Scene *scene; Object *ob; float dval; } data;
+       PEData data;
 
-       if(!PE_can_edit(psys)) return;
+       PE_set_data(C, &data);
 
-       data.scene = scene;
-       data.ob = ob;
-       data.dval = 1.0f / (float)(pset->totrekey-1);
+       data.dval= 1.0f / (float)(data.totrekey-1);
+       data.totrekey= RNA_int_get(op->ptr, "keys");
 
-       foreach_selected_element(psys, rekey_element, &data);
+       foreach_selected_particle(&data, rekey_particle);
        
-       psys->edit->totkeys = psys_count_keys(psys);
+       data.psys->edit->totkeys= psys_count_keys(data.psys);
+       recalc_lengths(data.psys);
+       
+       PE_update_object(data.scene, data.ob, 1);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, data.ob);
 
-       recalc_lengths(psys);
+       return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_rekey(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Rekey";
+       ot->idname= "PARTICLE_OT_rekey";
        
-       PE_update_object(scene, ob, 1);
+       /* api callbacks */
+       ot->exec= rekey_exec;
+       ot->invoke= WM_operator_props_popup;
+       ot->poll= PE_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 
-       BIF_undo_push("Re-key particles");
+       /* properties */
+       RNA_def_int(ot->srna, "keys", 2, 2, INT_MAX, "Number of Keys", "", 2, 100);
 }
 
-static void rekey_element_to_time(Object *ob, int index, float path_time)
+static void rekey_particle_to_time(Scene *scene, Object *ob, int pa_index, float path_time)
 {
-       Scene *scene= NULL; // XXX
-       ParticleSystem *psys = PE_get_current(ob);
+       ParticleSystem *psys= PE_get_current(scene, ob);
        ParticleEdit *edit=0;
        ParticleData *pa;
        ParticleKey state;
@@ -1706,50 +1837,52 @@ static void rekey_element_to_time(Object *ob, int index, float path_time)
 
        if(psys==0) return;
 
-       edit = psys->edit;
+       edit= psys->edit;
 
-       pa = psys->particles + index;
+       pa= &psys->particles[pa_index];
 
        pa->flag |= PARS_REKEY;
 
-       key = new_keys = MEM_dupallocN(pa->hair);
+       key= new_keys= MEM_dupallocN(pa->hair);
        
        /* interpolate new keys from old ones (roots stay the same) */
        for(k=1, key++; k < pa->totkey; k++, key++) {
-               state.time = path_time * (float)k / (float)(pa->totkey-1);
-               psys_get_particle_on_path(scene, ob, psys, index, &state, 0);
+               state.time= path_time * (float)k / (float)(pa->totkey-1);
+               psys_get_particle_on_path(scene, ob, psys, pa_index, &state, 0);
                VECCOPY(key->co, state.co);
        }
 
        /* replace hair keys */
        if(pa->hair)
                MEM_freeN(pa->hair);
-       pa->hair = new_keys;
+       pa->hair= new_keys;
 
        /* update edit pointers */
-       for(k=0, key=pa->hair, ekey=edit->keys[index]; k<pa->totkey; k++, key++, ekey++) {
-               ekey->co = key->co;
-               ekey->time = &key->time;
+       for(k=0, key=pa->hair, ekey=edit->keys[pa_index]; k<pa->totkey; k++, key++, ekey++) {
+               ekey->co= key->co;
+               ekey->time= &key->time;
        }
 
        pa->flag &= ~PARS_REKEY;
 }
 
-static int remove_tagged_elements(Scene *scene, Object *ob, ParticleSystem *psys)
+/************************* utilities **************************/
+
+static int remove_tagged_particles(Scene *scene, Object *ob, ParticleSystem *psys)
 {
-       ParticleEdit *edit = psys->edit;
-       ParticleEditSettings *pset = PE_settings(scene);
+       ParticleEdit *edit= psys->edit;
+       ParticleEditSettings *pset= PE_settings(scene);
        ParticleData *pa, *npa=0, *new_pars=0;
        ParticleEditKey **key, **nkey=0, **new_keys=0;
        ParticleSystemModifierData *psmd;
-       int i, totpart, new_totpart = psys->totpart, removed = 0;
+       int i, totpart, new_totpart= psys->totpart, removed= 0;
 
        if(pset->flag & PE_X_MIRROR) {
                /* mirror tags */
-               psmd = psys_get_modifier(ob, psys);
-               totpart = psys->totpart;
+               psmd= psys_get_modifier(ob, psys);
+               totpart= psys->totpart;
 
-               LOOP_PARTICLES(i,pa)
+               LOOP_PARTICLES(i, pa)
                        if(pa->flag & PARS_TAG)
                                PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
        }
@@ -1763,12 +1896,12 @@ static int remove_tagged_elements(Scene *scene, Object *ob, ParticleSystem *psys
 
        if(new_totpart != psys->totpart) {
                if(new_totpart) {
-                       npa = new_pars = MEM_callocN(new_totpart * sizeof(ParticleData), "ParticleData array");
-                       nkey = new_keys = MEM_callocN(new_totpart * sizeof(ParticleEditKey *), "ParticleEditKey array");
+                       npa= new_pars= MEM_callocN(new_totpart * sizeof(ParticleData), "ParticleData array");
+                       nkey= new_keys= MEM_callocN(new_totpart * sizeof(ParticleEditKey *), "ParticleEditKey array");
                }
 
-               pa = psys->particles;
-               key = edit->keys;
+               pa= psys->particles;
+               key= edit->keys;
                for(i=0; i<psys->totpart; i++, pa++, key++) {
                        if(pa->flag & PARS_TAG) {
                                if(*key)
@@ -1785,19 +1918,19 @@ static int remove_tagged_elements(Scene *scene, Object *ob, ParticleSystem *psys
                }
 
                if(psys->particles) MEM_freeN(psys->particles);
-               psys->particles = new_pars;
+               psys->particles= new_pars;
 
                if(edit->keys) MEM_freeN(edit->keys);
-               edit->keys = new_keys;
+               edit->keys= new_keys;
 
                if(edit->mirror_cache) {
                        MEM_freeN(edit->mirror_cache);
-                       edit->mirror_cache = NULL;
+                       edit->mirror_cache= NULL;
                }
 
-               psys->totpart = new_totpart;
+               psys->totpart= new_totpart;
 
-               edit->totkeys = psys_count_keys(psys);
+               edit->totkeys= psys_count_keys(psys);
        }
 
        return removed;
@@ -1805,20 +1938,20 @@ static int remove_tagged_elements(Scene *scene, Object *ob, ParticleSystem *psys
 
 static void remove_tagged_keys(Scene *scene, Object *ob, ParticleSystem *psys)
 {
-       ParticleEdit *edit = psys->edit;
-       ParticleEditSettings *pset = PE_settings(scene);
+       ParticleEdit *edit= psys->edit;
+       ParticleEditSettings *pset= PE_settings(scene);
        ParticleData *pa;
        HairKey *key, *nkey, *new_keys=0;
        ParticleEditKey *ekey;
        ParticleSystemModifierData *psmd;
-       int i, k, totpart = psys->totpart;
+       int i, k, totpart= psys->totpart;
        short new_totkey;
 
        if(pset->flag & PE_X_MIRROR) {
                /* mirror key tags */
-               psmd = psys_get_modifier(ob, psys);
+               psmd= psys_get_modifier(ob, psys);
 
-               LOOP_PARTICLES(i,pa) {
+               LOOP_PARTICLES(i, pa) {
                        LOOP_KEYS(k,ekey) {
                                if(ekey->flag & PEK_TAG) {
                                        PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
@@ -1828,8 +1961,8 @@ static void remove_tagged_keys(Scene *scene, Object *ob, ParticleSystem *psys)
                }
        }
 
-       LOOP_PARTICLES(i,pa) {
-               new_totkey = pa->totkey;
+       LOOP_PARTICLES(i, pa) {
+               new_totkey= pa->totkey;
                LOOP_KEYS(k,ekey) {
                        if(ekey->flag & PEK_TAG)
                                new_totkey--;
@@ -1838,19 +1971,19 @@ static void remove_tagged_keys(Scene *scene, Object *ob, ParticleSystem *psys)
                if(new_totkey < 2)
                        pa->flag |= PARS_TAG;
        }
-       remove_tagged_elements(scene, ob, psys);
+       remove_tagged_particles(scene, ob, psys);
 
-       totpart = psys->totpart;
+       totpart= psys->totpart;
 
-       LOOP_PARTICLES(i,pa) {
-               new_totkey = pa->totkey;
+       LOOP_PARTICLES(i, pa) {
+               new_totkey= pa->totkey;
                LOOP_KEYS(k,ekey) {
                        if(ekey->flag & PEK_TAG)
                                new_totkey--;
                }
                if(new_totkey != pa->totkey) {
-                       key = pa->hair;
-                       nkey = new_keys = MEM_callocN(new_totkey*sizeof(HairKey), "HairKeys");
+                       key= pa->hair;
+                       nkey= new_keys= MEM_callocN(new_totkey*sizeof(HairKey), "HairKeys");
 
                        for(k=0, ekey=edit->keys[i]; k<new_totkey; k++, key++, nkey++, ekey++) {
                                while(ekey->flag & PEK_TAG && key < pa->hair + pa->totkey) {
@@ -1860,36 +1993,39 @@ static void remove_tagged_keys(Scene *scene, Object *ob, ParticleSystem *psys)
 
                                if(key < pa->hair + pa->totkey) {
                                        VECCOPY(nkey->co, key->co);
-                                       nkey->time = key->time;
-                                       nkey->weight = key->weight;
+                                       nkey->time= key->time;
+                                       nkey->weight= key->weight;
                                }
                        }
                        if(pa->hair)
                                MEM_freeN(pa->hair);
                        
-                       pa->hair = new_keys;
+                       pa->hair= new_keys;
 
                        pa->totkey=new_totkey;
 
                        if(edit->keys[i])
                                MEM_freeN(edit->keys[i]);
-                       ekey = edit->keys[i] = MEM_callocN(new_totkey*sizeof(ParticleEditKey), "particle edit keys");
+                       ekey= edit->keys[i]= MEM_callocN(new_totkey*sizeof(ParticleEditKey), "particle edit keys");
 
                        for(k=0, key=pa->hair; k<pa->totkey; k++, key++, ekey++) {
-                               ekey->co = key->co;
-                               ekey->time = &key->time;
+                               ekey->co= key->co;
+                               ekey->time= &key->time;
                        }
                }
        }
 
-       edit->totkeys = psys_count_keys(psys);
+       edit->totkeys= psys_count_keys(psys);
 }
+
+/************************ subdivide opertor *********************/
+
 /* works like normal edit mode subdivide, inserts keys between neighbouring selected keys */
-static void subdivide_element(ParticleSystem *psys, int index, void *userData)
+static void subdivide_particle(PEData *data, int pa_index)
 {
-       struct {Scene *scene; Object *ob; } *data = userData;
-       ParticleEdit *edit = psys->edit;
-       ParticleData *pa = psys->particles + index;
+       ParticleSystem *psys= data->psys;
+       ParticleEdit *edit= psys->edit;
+       ParticleData *pa= &psys->particles[pa_index];
        
        ParticleKey state;
        HairKey *key, *nkey, *new_keys;
@@ -1899,7 +2035,7 @@ static void subdivide_element(ParticleSystem *psys, int index, void *userData)
        short totnewkey=0;
        float endtime;
 
-       for(k=0, ekey=edit->keys[index]; k<pa->totkey-1; k++,ekey++){
+       for(k=0, ekey=edit->keys[pa_index]; k<pa->totkey-1; k++,ekey++) {
                if(ekey->flag&PEK_SELECT && (ekey+1)->flag&PEK_SELECT)
                        totnewkey++;
        }
@@ -1908,25 +2044,25 @@ static void subdivide_element(ParticleSystem *psys, int index, void *userData)
 
        pa->flag |= PARS_REKEY;
 
-       nkey = new_keys = MEM_callocN((pa->totkey+totnewkey)*(sizeof(HairKey)),"Hair subdivide keys");
-       nekey = new_ekeys = MEM_callocN((pa->totkey+totnewkey)*(sizeof(ParticleEditKey)),"Hair subdivide edit keys");
-       endtime = pa->hair[pa->totkey-1].time;
+       nkey= new_keys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(HairKey)),"Hair subdivide keys");
+       nekey= new_ekeys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(ParticleEditKey)),"Hair subdivide edit keys");
+       endtime= pa->hair[pa->totkey-1].time;
 
-       for(k=0, key=pa->hair, ekey=edit->keys[index]; k<pa->totkey-1; k++, key++, ekey++){
+       for(k=0, key=pa->hair, ekey=edit->keys[pa_index]; k<pa->totkey-1; k++, key++, ekey++) {
 
                memcpy(nkey,key,sizeof(HairKey));
                memcpy(nekey,ekey,sizeof(ParticleEditKey));
 
-               nekey->co = nkey->co;
-               nekey->time = &nkey->time;
+               nekey->co= nkey->co;
+               nekey->time= &nkey->time;
 
                nkey++;
                nekey++;
 
-               if(ekey->flag & PEK_SELECT && (ekey+1)->flag & PEK_SELECT){
+               if(ekey->flag & PEK_SELECT && (ekey+1)->flag & PEK_SELECT) {
                        nkey->time= (key->time + (key+1)->time)*0.5f;
-                       state.time = (endtime != 0.0f)? nkey->time/endtime: 0.0f;
-                       psys_get_particle_on_path(data->scene, data->ob, psys, index, &state, 0);
+                       state.time= (endtime != 0.0f)? nkey->time/endtime: 0.0f;
+                       psys_get_particle_on_path(data->scene, data->ob, psys, pa_index, &state, 0);
                        VECCOPY(nkey->co, state.co);
 
                        nekey->co= nkey->co;
@@ -1941,61 +2077,71 @@ static void subdivide_element(ParticleSystem *psys, int index, void *userData)
        memcpy(nkey,key,sizeof(HairKey));
        memcpy(nekey,ekey,sizeof(ParticleEditKey));
 
-       nekey->co = nkey->co;
-       nekey->time = &nkey->time;
+       nekey->co= nkey->co;
+       nekey->time= &nkey->time;
 
        if(pa->hair)
                MEM_freeN(pa->hair);
-       pa->hair = new_keys;
+       pa->hair= new_keys;
 
-       if(edit->keys[index])
-               MEM_freeN(edit->keys[index]);
+       if(edit->keys[pa_index])
+               MEM_freeN(edit->keys[pa_index]);
 
-       edit->keys[index] = new_ekeys;
+       edit->keys[pa_index]= new_ekeys;
 
        pa->totkey += totnewkey;
        pa->flag |= PARS_EDIT_RECALC;
        pa->flag &= ~PARS_REKEY;
 }
 
-void PE_subdivide(Object *ob)
+static int subdivide_exec(bContext *C, wmOperator *op)
 {
-       ParticleSystem *psys = PE_get_current(ob);
-       Scene *scene= NULL;
-       struct {Scene *scene; Object *ob; } data;
+       PEData data;
 
-       if(!PE_can_edit(psys)) return;
-
-       data.scene= scene;
-       data.ob= ob;
-       PE_foreach_element(psys,subdivide_element,&data);
+       PE_set_data(C, &data);
+       PE_foreach_particle(&data, subdivide_particle);
        
-       psys->edit->totkeys = psys_count_keys(psys);
+       data.psys->edit->totkeys= psys_count_keys(data.psys);
        
-       recalc_lengths(psys);
-       PE_recalc_world_cos(ob, psys);
+       recalc_lengths(data.psys);
+       psys_update_world_cos(data.ob, data.psys);
+
+       PE_update_object(data.scene, data.ob, 1);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, data.ob);
 
-       PE_update_object(scene, ob, 1);
+       return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_subdivide(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Subdivide";
+       ot->idname= "PARTICLE_OT_subdivide";
        
-       BIF_undo_push("Subdivide hair(s)");
+       /* api callbacks */
+       ot->exec= subdivide_exec;
+       ot->poll= PE_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
-void PE_remove_doubles()
+/************************ remove doubles opertor *********************/
+
+static int remove_doubles_exec(bContext *C, wmOperator *op)
 {
-       Scene *scene= NULL; // XXX
-       Object *ob=OBACT;
-       ParticleSystem *psys=PE_get_current(ob);
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       ParticleSystem *psys= PE_get_current(scene, ob);
        ParticleEditSettings *pset=PE_settings(scene);
        ParticleData *pa;
        ParticleEdit *edit;
        ParticleSystemModifierData *psmd;
        KDTree *tree;
        KDTreeNearest nearest[10];
-       float mat[4][4], co[3];
+       float mat[4][4], co[3], threshold= RNA_float_get(op->ptr, "threshold");
        int i, n, totn, removed, totpart, flag, totremoved;
 
-       if(!PE_can_edit(psys)) return;
-
        edit= psys->edit;
        psmd= psys_get_modifier(ob, psys);
        totremoved= 0;
@@ -2007,7 +2153,7 @@ void PE_remove_doubles()
                tree=BLI_kdtree_new(totpart);
                        
                /* insert particles into kd tree */
-               LOOP_PARTICLES(i,pa) {
+               LOOP_PARTICLES(i, pa) {
                        if(particle_is_selected(psys, pa)) {
                                psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, mat);
                                VECCOPY(co, pa->hair[0].co);
@@ -2019,7 +2165,7 @@ void PE_remove_doubles()
                BLI_kdtree_balance(tree);
 
                /* tag particles to be removed */
-               LOOP_PARTICLES(i,pa) {
+               LOOP_PARTICLES(i, pa) {
                        if(particle_is_selected(psys, pa)) {
                                psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, mat);
                                VECCOPY(co, pa->hair[0].co);
@@ -2029,7 +2175,7 @@ void PE_remove_doubles()
 
                                for(n=0; n<totn; n++) {
                                        /* this needs a custom threshold still */
-                                       if(nearest[n].index > i && nearest[n].dist < 0.0002f) {
+                                       if(nearest[n].index > i && nearest[n].dist < threshold) {
                                                if(!(pa->flag & PARS_TAG)) {
                                                        pa->flag |= PARS_TAG;
                                                        removed++;
@@ -2044,74 +2190,422 @@ void PE_remove_doubles()
                /* remove tagged particles - don't do mirror here! */
                flag= pset->flag;
                pset->flag &= ~PE_X_MIRROR;
-               remove_tagged_elements(scene, ob, psys);
+               remove_tagged_particles(scene, ob, psys);
                pset->flag= flag;
                totremoved += removed;
        } while(removed);
 
-//     if(totremoved)
-// XXX         notice("Removed: %d", totremoved);
+       if(totremoved == 0)
+               return OPERATOR_CANCELLED;
+
+       BKE_reportf(op->reports, RPT_INFO, "Remove %d double particles.", totremoved);
 
-       PE_recalc_world_cos(ob, psys);
+       psys_update_world_cos(ob, psys);
        DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
-       BIF_undo_push("Remove double particles");
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob);
+
+       return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Remove Doubles";
+       ot->idname= "PARTICLE_OT_remove_doubles";
+       
+       /* api callbacks */
+       ot->exec= remove_doubles_exec;
+       ot->poll= PE_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       /* properties */
+       RNA_def_float(ot->srna, "threshold", 0.0002f, 0.0f, FLT_MAX, "Threshold", "Threshold distance withing which particles are removed", 0.00001f, 0.1f);
 }
 
-/* XXX static */
-void PE_radialcontrol_callback(const int mode, const int val)
+/************************ cursor drawing *******************************/
+
+static void brush_drawcursor(bContext *C, int x, int y, void *customdata)
 {
-       ParticleEditSettings *pset = NULL; // XXX PE_settings(scene);
+       ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
+       ParticleBrushData *brush;
+
+       if(pset->brushtype < 0)
+               return;
+
+       brush= &pset->brush[pset->brushtype];
+
+       if(brush) {
+               glPushMatrix();
+
+               glTranslatef((float)x, (float)y, 0.0f);
+
+               glColor4ub(255, 255, 255, 128);
+               glEnable(GL_LINE_SMOOTH );
+               glEnable(GL_BLEND);
+               glutil_draw_lined_arc(0.0, M_PI*2.0, brush->size, 40);
+               glDisable(GL_BLEND);
+               glDisable(GL_LINE_SMOOTH );
+               
+               glPopMatrix();
+       }
+}
 
-       if(pset->brushtype>=0) {
-               ParticleBrushData *brush= &pset->brush[pset->brushtype];
+static void toggle_particle_cursor(bContext *C, int enable)
+{
+       ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
 
-               if(mode == RADIALCONTROL_SIZE)
-                       brush->size = val;
-               else if(mode == RADIALCONTROL_STRENGTH)
-                       brush->strength = val;
+       if(pset->paintcursor && !enable) {
+               WM_paint_cursor_end(CTX_wm_manager(C), pset->paintcursor);
+               pset->paintcursor = NULL;
        }
+       else if(enable)
+               pset->paintcursor= WM_paint_cursor_activate(CTX_wm_manager(C), PE_poll_3dview, brush_drawcursor, NULL);
+}
+
+/********************* radial control operator *********************/
+
+static int brush_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
+       ParticleBrushData *brush;
+       int mode = RNA_enum_get(op->ptr, "mode");
+       float original_value=1.0f;
+
+       if(pset->brushtype < 0)
+               return OPERATOR_CANCELLED;
+
+       brush= &pset->brush[pset->brushtype];
 
-       (*PE_radialcontrol()) = NULL;
+       toggle_particle_cursor(C, 0);
+
+       if(mode == WM_RADIALCONTROL_SIZE)
+               original_value = brush->size;
+       else if(mode == WM_RADIALCONTROL_STRENGTH)
+               original_value = brush->strength;
+
+       RNA_float_set(op->ptr, "initial_value", original_value);
+
+       return WM_radial_control_invoke(C, op, event);
 }
 
-struct RadialControl **PE_radialcontrol(void)
+static int brush_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event)
 {
-       static struct RadialControl *rc = NULL;
-       return &rc;
+       int ret = WM_radial_control_modal(C, op, event);
+
+       if(ret != OPERATOR_RUNNING_MODAL)
+               toggle_particle_cursor(C, 1);
+
+       return ret;
 }
 
-void PE_radialcontrol_start(const int mode)
+static int brush_radial_control_exec(bContext *C, wmOperator *op)
 {
-       ParticleEditSettings *pset = NULL; // XXX PE_settings(scene);
-       int orig= 1;
+       ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
+       ParticleBrushData *brush;
+       int mode = RNA_enum_get(op->ptr, "mode");
+       float new_value = RNA_float_get(op->ptr, "new_value");
 
-       if(pset->brushtype>=0) {
-               ParticleBrushData *brush= &pset->brush[pset->brushtype];
-               
-               if(mode == RADIALCONTROL_SIZE)
-                       orig = brush->size;
-               else if(mode == RADIALCONTROL_STRENGTH)
-                       orig = brush->strength;
-               
-//             if(mode != RADIALCONTROL_NONE)
-//                     (*PE_radialcontrol())= radialcontrol_start(mode, PE_radialcontrol_callback, orig, 100, 0);
+       if(pset->brushtype < 0)
+               return OPERATOR_CANCELLED;
+
+       brush= &pset->brush[pset->brushtype];
+
+       if(mode == WM_RADIALCONTROL_SIZE)
+               brush->size= new_value;
+       else if(mode == WM_RADIALCONTROL_STRENGTH)
+               brush->strength= new_value;
+
+       return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_brush_radial_control(wmOperatorType *ot)
+{
+       WM_OT_radial_control_partial(ot);
+
+       ot->name= "Brush Radial Control";
+       ot->idname= "PARTICLE_OT_brush_radial_control";
+
+       ot->invoke= brush_radial_control_invoke;
+       ot->modal= brush_radial_control_modal;
+       ot->exec= brush_radial_control_exec;
+       ot->poll= PE_poll;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
+}
+
+/*************************** delete operator **************************/
+
+enum { DEL_PARTICLE, DEL_KEY };
+
+static EnumPropertyItem delete_type_items[]= {
+       {DEL_PARTICLE, "PARTICLE", 0, "Particle", ""},
+       {DEL_KEY, "KEY", 0, "Key", ""},
+       {0, NULL, 0, NULL, NULL}};
+
+static void set_delete_particle(PEData *data, int pa_index)
+{
+       ParticleSystem *psys= data->psys;
+
+       psys->particles[pa_index].flag |= PARS_TAG;
+}
+
+static void set_delete_particle_key(PEData *data, int pa_index, int key_index)
+{
+       ParticleSystem *psys= data->psys;
+
+       psys->edit->keys[pa_index][key_index].flag |= PEK_TAG;
+}
+
+static int delete_exec(bContext *C, wmOperator *op)
+{
+       PEData data;
+       int type= RNA_enum_get(op->ptr, "type");
+
+       PE_set_data(C, &data);
+
+       if(type == DEL_KEY) {
+               foreach_selected_key(&data, set_delete_particle_key);
+               remove_tagged_keys(data.scene, data.ob, data.psys);
+               recalc_lengths(data.psys);
+       }
+       else if(type == DEL_PARTICLE) {
+               foreach_selected_particle(&data, set_delete_particle);
+               remove_tagged_particles(data.scene, data.ob, data.psys);
+               recalc_lengths(data.psys);
        }
+
+       DAG_object_flush_update(data.scene, data.ob, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, data.ob);
+
+       return OPERATOR_FINISHED;
 }
 
-/************************************************/
-/*                     Edit Brushes                                            */
-/************************************************/
-static void brush_comb(ParticleSystem *psys, float mat[][4], float imat[][4], int pa_index, int key_index, void *userData)
+void PARTICLE_OT_delete(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Delete";
+       ot->idname= "PARTICLE_OT_delete";
+       
+       /* api callbacks */
+       ot->exec= delete_exec;
+       ot->invoke= WM_menu_invoke;
+       ot->poll= PE_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       /* properties */
+       RNA_def_enum(ot->srna, "type", delete_type_items, DEL_PARTICLE, "Type", "Delete a full particle or only keys.");
+}
+
+/*************************** mirror operator **************************/
+
+static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
+{
+       Mesh *me= (Mesh*)(ob->data);
+       ParticleSystemModifierData *psmd;
+       ParticleSystem *psys= PE_get_current(scene, ob);
+       ParticleEdit *edit;
+       ParticleData *pa, *newpa, *new_pars;
+       ParticleEditKey *ekey, **newkey, **key, **new_keys;
+       HairKey *hkey;
+       int *mirrorfaces;
+       int i, k, rotation, totpart, newtotpart;
+
+       edit= psys->edit;
+       psmd= psys_get_modifier(ob, psys);
+
+       mirrorfaces= mesh_get_x_mirror_faces(ob, NULL);
+
+       if(!edit->mirror_cache)
+               PE_update_mirror_cache(ob, psys);
+
+       totpart= psys->totpart;
+       newtotpart= psys->totpart;
+       LOOP_PARTICLES(i, pa) {
+               if(pa->flag & PARS_HIDE) continue;
+
+               if(!tagged) {
+                       if(particle_is_selected(psys, pa)) {
+                               if(edit->mirror_cache[i] != -1) {
+                                       /* already has a mirror, don't need to duplicate */
+                                       PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
+                                       continue;
+                               }
+                               else
+                                       pa->flag |= PARS_TAG;
+                       }
+               }
+
+               if((pa->flag & PARS_TAG) && mirrorfaces[pa->num*2] != -1)
+                       newtotpart++;
+       }
+
+       if(newtotpart != psys->totpart) {
+               /* allocate new arrays and copy existing */
+               new_pars= MEM_callocN(newtotpart*sizeof(ParticleData), "ParticleData new");
+               new_keys= MEM_callocN(newtotpart*sizeof(ParticleEditKey*), "ParticleEditKey new");
+
+               if(psys->particles) {
+                       memcpy(new_pars, psys->particles, totpart*sizeof(ParticleData));
+                       MEM_freeN(psys->particles);
+               }
+               psys->particles= new_pars;
+
+               if(edit->keys) {
+                       memcpy(new_keys, edit->keys, totpart*sizeof(ParticleEditKey*));
+                       MEM_freeN(edit->keys);
+               }
+               edit->keys= new_keys;
+
+               if(edit->mirror_cache) {
+                       MEM_freeN(edit->mirror_cache);
+                       edit->mirror_cache= NULL;
+               }
+
+               psys->totpart= newtotpart;
+                       
+               /* create new elements */
+               pa= psys->particles;
+               newpa= psys->particles + totpart;
+               key= edit->keys;
+               newkey= edit->keys + totpart;
+
+               for(i=0; i<totpart; i++, pa++, key++) {
+                       if(pa->flag & PARS_HIDE) continue;
+
+                       if(!(pa->flag & PARS_TAG) || mirrorfaces[pa->num*2] == -1)
+                               continue;
+
+                       /* duplicate */
+                       *newpa= *pa;
+                       if(pa->hair) newpa->hair= MEM_dupallocN(pa->hair);
+                       if(pa->keys) newpa->keys= MEM_dupallocN(pa->keys);
+                       if(*key) *newkey= MEM_dupallocN(*key);
+
+                       /* rotate weights according to vertex index rotation */
+                       rotation= mirrorfaces[pa->num*2+1];
+                       newpa->fuv[0]= pa->fuv[2];
+                       newpa->fuv[1]= pa->fuv[1];
+                       newpa->fuv[2]= pa->fuv[0];
+                       newpa->fuv[3]= pa->fuv[3];
+                       while(rotation-- > 0)
+                               if(me->mface[pa->num].v4)
+                                       SHIFT4(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2], newpa->fuv[3])
+                               else
+                                       SHIFT3(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2])
+
+                       /* assign face inddex */
+                       newpa->num= mirrorfaces[pa->num*2];
+                       newpa->num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,newpa->num,newpa->fuv, NULL);
+
+                       /* update edit key pointers */
+                       ekey= *newkey;
+                       for(k=0, hkey=newpa->hair; k<newpa->totkey; k++, hkey++, ekey++) {
+                               ekey->co= hkey->co;
+                               ekey->time= &hkey->time;
+                       }
+
+                       /* map key positions as mirror over x axis */
+                       PE_mirror_particle(ob, psmd->dm, psys, pa, newpa);
+
+                       newpa++;
+                       newkey++;
+               }
+
+               edit->totkeys= psys_count_keys(psys);
+       }
+
+       for(pa=psys->particles, i=0; i<psys->totpart; i++, pa++)
+               pa->flag &= ~PARS_TAG;
+
+       MEM_freeN(mirrorfaces);
+}
+
+static int mirror_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       ParticleSystem *psys= PE_get_current(scene, ob);
+       
+       PE_mirror_x(scene, ob, 0);
+
+       psys_update_world_cos(ob, psys);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob);
+       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+
+       return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_mirror(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Mirror";
+       ot->idname= "PARTICLE_OT_mirror";
+       
+       /* api callbacks */
+       ot->exec= mirror_exec;
+       ot->poll= PE_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/*********************** set brush operator **********************/
+
+static EnumPropertyItem brush_type_items[]= {
+       {PE_BRUSH_NONE, "NONE", 0, "None", ""},
+       {PE_BRUSH_COMB, "COMB", 0, "Comb", ""},
+       {PE_BRUSH_SMOOTH, "SMOOTH", 0, "Smooth", ""},
+       {PE_BRUSH_WEIGHT, "WEIGHT", 0, "Weight", ""},
+       {PE_BRUSH_ADD, "ADD", 0, "Add", ""},
+       {PE_BRUSH_LENGTH, "LENGTH", 0, "Length", ""},
+       {PE_BRUSH_PUFF, "PUFF", 0, "Puff", ""},
+       {PE_BRUSH_CUT, "CUT", 0, "Cut", ""},
+       {0, NULL, 0, NULL, NULL}
+};
+
+static int set_brush_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene= CTX_data_scene(C);
+       ParticleEditSettings *pset= PE_settings(scene);
+
+       pset->brushtype= RNA_enum_get(op->ptr, "type");
+
+       return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_brush_set(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Set Brush";
+       ot->idname= "PARTICLE_OT_brush_set";
+       
+       /* api callbacks */
+       ot->exec= set_brush_exec;
+       ot->invoke= WM_menu_invoke;
+       ot->poll= PE_poll;
+
+       /* properties */
+       RNA_def_enum(ot->srna, "type", brush_type_items, PE_BRUSH_NONE, "Type", "Brush type to select for editing.");
+}
+
+/************************* brush edit callbacks ********************/
+
+static void brush_comb(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index)
 {
-       struct {Scene *scene; Object *ob; short *mval; float rad; rcti* rect; float dist; float *dvec; float combfac;} *data = userData;
+       ParticleSystem *psys= data->psys;
        ParticleData *pa= &psys->particles[pa_index];
        ParticleEditSettings *pset= PE_settings(data->scene);
-       HairKey *key = pa->hair + key_index;
+       HairKey *key= pa->hair + key_index;
        float cvec[3], fac;
 
        if(pset->flag & PE_LOCK_FIRST && key_index == 0) return;
 
-       fac = (float)pow((double)(1.0f - data->dist / data->rad), (double)data->combfac);
+       fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->combfac);
 
        VECCOPY(cvec,data->dvec);
        Mat4Mul3Vecfl(imat,cvec);
@@ -2121,67 +2615,67 @@ static void brush_comb(ParticleSystem *psys, float mat[][4], float imat[][4], in
        pa->flag |= PARS_EDIT_RECALC;
 }
 
-static void brush_cut(ParticleSystem *psys, int index, void *userData)
+static void brush_cut(PEData *data, int pa_index)
 {
-       struct {Scene *scene; short *mval; float rad; rcti* rect; int selected; float cutfac; bglMats mats;} *data = userData;
-       ARegion *ar= NULL; // XXX
-       Object *ob= NULL; // XXX
-       ParticleData *pa= &psys->particles[index];
-       ParticleCacheKey *key = psys->pathcache[index];
-       float rad2, cut_time = 1.0;
+       ParticleSystem *psys= data->psys;
+       ARegion *ar= data->vc.ar;
+       Object *ob= data->ob;
+       ParticleData *pa= &psys->particles[pa_index];
+       ParticleCacheKey *key= psys->pathcache[pa_index];
+       float rad2, cut_time= 1.0;
        float x0, x1, v0, v1, o0, o1, xo0, xo1, d, dv;
-       int k, cut, keys = (int)pow(2.0, (double)psys->part->draw_step);
+       int k, cut, keys= (int)pow(2.0, (double)psys->part->draw_step);
        short vertco[2];
 
        /* blunt scissors */
        if(BLI_frand() > data->cutfac) return;
 
-       rad2 = data->rad * data->rad;
+       rad2= data->rad * data->rad;
 
        cut=0;
 
        project_short_noclip(ar, key->co, vertco);
-       x0 = (float)vertco[0];
-       x1 = (float)vertco[1];
+       x0= (float)vertco[0];
+       x1= (float)vertco[1];
 
-       o0 = (float)data->mval[0];
-       o1 = (float)data->mval[1];
+       o0= (float)data->mval[0];
+       o1= (float)data->mval[1];
        
-       xo0 = x0 - o0;
-       xo1 = x1 - o1;
+       xo0= x0 - o0;
+       xo1= x1 - o1;
 
        /* check if root is inside circle */
-       if(xo0*xo0 + xo1*xo1 < rad2 && test_key_depth(key->co,&(data->mats))) {
-               cut_time = -1.0f;
-               cut = 1;
+       if(xo0*xo0 + xo1*xo1 < rad2 && key_test_depth(data, key->co)) {
+               cut_time= -1.0f;
+               cut= 1;
        }
        else {
                /* calculate path time closest to root that was inside the circle */
-               for(k=1, key++; k<=keys; k++, key++){
+               for(k=1, key++; k<=keys; k++, key++) {
                        project_short_noclip(ar, key->co, vertco);
 
-                       if(test_key_depth(key->co,&(data->mats)) == 0) {
-                               x0 = (float)vertco[0];
-                               x1 = (float)vertco[1];
+                       if(key_test_depth(data, key->co) == 0) {
+                               x0= (float)vertco[0];
+                               x1= (float)vertco[1];
 
-                               xo0 = x0 - o0;
-                               xo1 = x1 - o1;
+                               xo0= x0 - o0;
+                               xo1= x1 - o1;
                                continue;
                        }
 
-                       v0 = (float)vertco[0] - x0;
-                       v1 = (float)vertco[1] - x1;
+                       v0= (float)vertco[0] - x0;
+                       v1= (float)vertco[1] - x1;
 
-                       dv = v0*v0 + v1*v1;
+                       dv= v0*v0 + v1*v1;
 
-                       d = (v0*xo1 - v1*xo0);
+                       d= (v0*xo1 - v1*xo0);
                        
-                       d = dv * rad2 - d*d;
+                       d= dv * rad2 - d*d;
 
                        if(d > 0.0f) {
-                               d = sqrt(d);
+                               d= sqrt(d);
 
-                               cut_time = -(v0*xo0 + v1*xo1 + d);
+                               cut_time= -(v0*xo0 + v1*xo1 + d);
 
                                if(cut_time > 0.0f) {
                                        cut_time /= dv;
@@ -2189,17 +2683,17 @@ static void brush_cut(ParticleSystem *psys, int index, void *userData)
                                        if(cut_time < 1.0f) {
                                                cut_time += (float)(k-1);
                                                cut_time /= (float)keys;
-                                               cut = 1;
+                                               cut= 1;
                                                break;
                                        }
                                }
                        }
 
-                       x0 = (float)vertco[0];
-                       x1 = (float)vertco[1];
+                       x0= (float)vertco[0];
+                       x1= (float)vertco[1];
 
-                       xo0 = x0 - o0;
-                       xo1 = x1 - o1;
+                       xo0= x0 - o0;
+                       xo1= x1 - o1;
                }
        }
 
@@ -2208,24 +2702,24 @@ static void brush_cut(ParticleSystem *psys, int index, void *userData)
                        pa->flag |= PARS_TAG;
                }
                else {
-                       rekey_element_to_time(ob, index, cut_time);
+                       rekey_particle_to_time(data->scene, ob, pa_index, cut_time);
                        pa->flag |= PARS_EDIT_RECALC;
                }
        }
 }
 
-static void brush_length(ParticleSystem *psys, int index, void *userData)
+static void brush_length(PEData *data, int pa_index)
 {
-       struct {Scene *scene; short *mval; float rad; rcti* rect; float dist; float growfac; } *data = userData;
-       ParticleData *pa = &psys->particles[index];
+       ParticleSystem *psys= data->psys;
+       ParticleData *pa= &psys->particles[pa_index];
        HairKey *key;
        float dvec[3],pvec[3];
        int k;
 
-       key = pa->hair;
+       key= pa->hair;
        VECCOPY(pvec,key->co);
 
-       for(k=1, key++; k<pa->totkey; k++,key++){
+       for(k=1, key++; k<pa->totkey; k++,key++) {
                VECSUB(dvec,key->co,pvec);
                VECCOPY(pvec,key->co);
                VecMulf(dvec,data->growfac);
@@ -2235,12 +2729,11 @@ static void brush_length(ParticleSystem *psys, int index, void *userData)
        pa->flag |= PARS_EDIT_RECALC;
 }
 
-static void brush_puff(ParticleSystem *psys, int index, void *userData)
+static void brush_puff(PEData *data, int pa_index)
 {
-       struct {Scene *scene; short *mval; float rad; rcti* rect; float dist;
-               Object *ob; DerivedMesh *dm; float pufffac; int invert; } *data = userData;
-       ParticleData *pa = &psys->particles[index];
-       ParticleEdit *edit = psys->edit;
+       ParticleSystem *psys= data->psys;
+       ParticleData *pa= &psys->particles[pa_index];
+       ParticleEdit *edit= psys->edit;
        HairKey *key;
        float mat[4][4], imat[4][4];
        float lastco[3], rootco[3], co[3], nor[3], kco[3], dco[3], fac, length;
@@ -2250,15 +2743,15 @@ static void brush_puff(ParticleSystem *psys, int index, void *userData)
        Mat4Invert(imat,mat);
 
        /* find root coordinate and normal on emitter */
-       key = pa->hair;
+       key= pa->hair;
        VECCOPY(co, key->co);
        Mat4MulVecfl(mat, co);
 
-       index= BLI_kdtree_find_nearest(edit->emitter_field, co, NULL, NULL);
-       if(index == -1) return;
+       pa_index= BLI_kdtree_find_nearest(edit->emitter_field, co, NULL, NULL);
+       if(pa_index == -1) return;
 
        VECCOPY(rootco, co);
-       VecCopyf(nor, &psys->edit->emitter_cosnos[index*6+3]);
+       VecCopyf(nor, &psys->edit->emitter_cosnos[pa_index*6+3]);
        Normalize(nor);
        length= 0.0f;
 
@@ -2267,7 +2760,7 @@ static void brush_puff(ParticleSystem *psys, int index, void *userData)
        if(data->invert)
                fac= -fac;
 
-       for(k=1, key++; k<pa->totkey; k++, key++){
+       for(k=1, key++; k<pa->totkey; k++, key++) {
                /* compute position as if hair was standing up straight */
                VECCOPY(lastco, co);
                VECCOPY(co, key->co);
@@ -2287,13 +2780,13 @@ static void brush_puff(ParticleSystem *psys, int index, void *userData)
        pa->flag |= PARS_EDIT_RECALC;
 }
 
-static void brush_smooth_get(ParticleSystem *psys, float mat[][4], float imat[][4], int pa_index, int key_index, void *userData)
+static void brush_smooth_get(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index)
 {
-       struct {Scene *scene; Object *ob; short *mval; float rad; rcti* rect; float dist; float vec[3]; int tot; float smoothfac;} *data = userData;
+       ParticleSystem *psys= data->psys;
        ParticleData *pa= &psys->particles[pa_index];
-       HairKey *key = pa->hair + key_index;
+       HairKey *key= pa->hair + key_index;
        
-       if(key_index){
+       if(key_index) {
                float dvec[3];
 
                VecSubf(dvec,key->co,(key-1)->co);
@@ -2303,14 +2796,14 @@ static void brush_smooth_get(ParticleSystem *psys, float mat[][4], float imat[][
        }
 }
 
-static void brush_smooth_do(ParticleSystem *psys, float mat[][4], float imat[][4], int pa_index, int key_index, void *userData)
+static void brush_smooth_do(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index)
 {
-       struct {Scene *scene; Object *ob; short *mval; float rad; rcti* rect; float dist; float vec[3]; int tot; float smoothfac;} *data = userData;
+       ParticleSystem *psys= data->psys;
        ParticleData *pa= &psys->particles[pa_index];
-       HairKey *key = pa->hair + key_index;
+       HairKey *key= pa->hair + key_index;
        float vec[3], dvec[3];
        
-       if(key_index){
+       if(key_index) {
                VECCOPY(vec,data->vec);
                Mat4Mul3Vecfl(imat,vec);
 
@@ -2325,128 +2818,62 @@ static void brush_smooth_do(ParticleSystem *psys, float mat[][4], float imat[][4
        pa->flag |= PARS_EDIT_RECALC;
 }
 
-#define EXPERIMENTAL_DEFORM_ONLY_PAINTING 1
-static void brush_add(Scene *scene, Object *ob, ParticleSystem *psys, short *mval, short number)
+static void brush_add(PEData *data, short number)
 {
-       ParticleData *add_pars = MEM_callocN(number*sizeof(ParticleData),"ParticleData add");
-       ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys);
+       Scene *scene= data->scene;
+       Object *ob= data->ob;
+       ParticleSystem *psys= data->psys;
+       ParticleData *add_pars= MEM_callocN(number*sizeof(ParticleData),"ParticleData add");
+       ParticleSystemModifierData *psmd= psys_get_modifier(ob,psys);
        ParticleEditSettings *pset= PE_settings(scene);
-       ARegion *ar= NULL; // XXX
-       View3D *v3d= NULL; // XXX
-       ParticleEdit *edit = psys->edit;
-       int i, k, n = 0, totpart = psys->totpart;
+       ParticleEdit *edit= psys->edit;
+       int i, k, n= 0, totpart= psys->totpart;
        short mco[2];
-       short dmx = 0, dmy = 0;
+       short dmx= 0, dmy= 0;
        float co1[3], co2[3], min_d, imat[4][4];
-       float framestep, timestep = psys_get_timestep(psys->part);
-       short size = pset->brush[PE_BRUSH_ADD].size;
-       short size2 = size*size;
-#if EXPERIMENTAL_DEFORM_ONLY_PAINTING
+       float framestep, timestep= psys_get_timestep(psys->part);
+       short size= pset->brush[PE_BRUSH_ADD].size;
+       short size2= size*size;
        DerivedMesh *dm=0;
-#endif
        Mat4Invert(imat,ob->obmat);
 
-       BLI_srandom(psys->seed+mval[0]+mval[1]);
+       BLI_srandom(psys->seed+data->mval[0]+data->mval[1]);
        
        /* painting onto the deformed mesh, could be an option? */
-#if EXPERIMENTAL_DEFORM_ONLY_PAINTING
-       if (psmd->dm->deformedOnly)
-               dm = psmd->dm;
+       if(psmd->dm->deformedOnly)
+               dm= psmd->dm;
        else
-               dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
-#endif
-       for(i=0; i<number; i++){
-               if(number>1){
+               dm= mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
+
+       for(i=0; i<number; i++) {
+               if(number>1) {
                        dmx=dmy=size;
-                       while(dmx*dmx+dmy*dmy>size2){
+                       while(dmx*dmx+dmy*dmy>size2) {
                                dmx=(short)((2.0f*BLI_frand()-1.0f)*size);
                                dmy=(short)((2.0f*BLI_frand()-1.0f)*size);
                        }
                }
 
-               mco[0] = mval[0] + dmx;
-               mco[1] = mval[1] + dmy;
-               viewline(ar, v3d, mco, co1, co2);
+               mco[0]= data->mval[0] + dmx;
+               mco[1]= data->mval[1] + dmy;
+               viewline(data->vc.ar, data->vc.v3d, mco, co1, co2);
 
                Mat4MulVecfl(imat,co1);
                Mat4MulVecfl(imat,co2);
                min_d=2.0;
                
                /* warning, returns the derived mesh face */
-#if EXPERIMENTAL_DEFORM_ONLY_PAINTING
                if(psys_intersect_dm(scene, ob,dm,0,co1,co2,&min_d,&add_pars[n].num,add_pars[n].fuv,0,0,0,0)) {
                        add_pars[n].num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,add_pars[n].num,add_pars[n].fuv,NULL);
                        n++;
                }
-#else
-#if 0
-               if (psmd->dm->deformedOnly) {
-                       if(psys_intersect_dm(scene, ob,psmd->dm,0,co1,co2,&min_d,&add_pars[n].num,add_pars[n].fuv,0,0,0,0)){
-                               n++;
-                       }
-               } else {
-                       /* we need to test against the cage mesh, because 1) its faster and 2) then we can avoid converting the fuv back which is not simple */
-                       if(psys_intersect_dm(scene, ob,psmd->dm,0,co1,co2,&min_d,&add_pars[n].num,add_pars[n].fuv,0,0,0,0)){
-                               MFace *mface;
-                               float fuv_mod[3] = {0.0, 0.0, 0.0};
-                               OrigSpaceFace *osface;
-                               
-                               mface= psmd->dm->getFaceData(psmd->dm,add_pars[n].num,CD_MFACE);
-                               osface= psmd->dm->getFaceData(psmd->dm, add_pars[n].num, CD_ORIGSPACE);
-                               
-                               add_pars[n].fuv[2]=0.0;
-                               
-                               /* use the original index for num and the derived index for num_dmcache */
-                               add_pars[n].num_dmcache = add_pars[n].num;
-                               add_pars[n].num = *(int *)psmd->dm->getFaceData(psmd->dm, add_pars[n].num, CD_ORIGINDEX);
-                               
-                               /* This is totally unaceptable code (fakeing mesh dara) but changing the target function isnt really nice either, do this temporarily */
-                               if (1) { /* Evilness*/
-                                       MFace mface_fake;
-                                       MVert mvert_fake[4];
-                                       //int test1,test2;
-                                       //test1 = add_pars[n].num_dmcache;
-                                       //test2 = add_pars[n].num;
-                                       
-                                       mvert_fake[0].co[2] = mvert_fake[1].co[2] = mvert_fake[2].co[2] = mvert_fake[3].co[2] = 0.0;
-                                       
-                                       mface_fake.v1 = 0;
-                                       mface_fake.v2 = 1;
-                                       mface_fake.v3 = 2;
-                                       
-                                       if (mface->v4) {
-                                               mface_fake.v4 = 3;
-                                       } else {
-                                               mface_fake.v4 = 0;
-                                       }
-                                       
-                                       Vec2Copyf(mvert_fake[0].co, osface->uv[0]);
-                                       Vec2Copyf(mvert_fake[1].co, osface->uv[1]);
-                                       Vec2Copyf(mvert_fake[2].co, osface->uv[2]);
-                                       Vec2Copyf(mvert_fake[3].co, osface->uv[3]);
-                                       //printf("before %f %f %i %i\n", add_pars[n].fuv[0], add_pars[n].fuv[1], test1, test2);
-                                       psys_interpolate_face(&mvert_fake, &mface_fake, NULL, &add_pars[n].fuv, &fuv_mod, NULL, NULL, NULL);
-                                       
-                                       /* Apply as the UV */
-                                       Vec2Copyf(add_pars[n].fuv, fuv_mod);
-                                       //printf("after %f %f\n", add_pars[n].fuv[0], add_pars[n].fuv[1]);
-                               }
-                               /* Make a fake face, for calculating the derived face's fuv on the original face */
-                               //PointInFace2DUV(mface->v4, osface->uv[0], osface->uv[1], osface->uv[2], osface->uv[3], add_pars[n].fuv, fuv_mod);
-                               //Vec2Copyf(add_pars[n].fuv, fuv_mod);
-                               
-                               n++;
-                       }
-               }
-#endif
-#endif
        }
-       if(n){
+       if(n) {
                int newtotpart=totpart+n;
                float hairmat[4][4], cur_co[3];
                KDTree *tree=0;
-               ParticleData *pa, *new_pars = MEM_callocN(newtotpart*sizeof(ParticleData),"ParticleData new");
-               ParticleEditKey *ekey, **key, **new_keys = MEM_callocN(newtotpart*sizeof(ParticleEditKey *),"ParticleEditKey array new");
+               ParticleData *pa, *new_pars= MEM_callocN(newtotpart*sizeof(ParticleData),"ParticleData new");
+               ParticleEditKey *ekey, **key, **new_keys= MEM_callocN(newtotpart*sizeof(ParticleEditKey *),"ParticleEditKey array new");
                HairKey *hkey;
 
                /* save existing elements */
@@ -2455,18 +2882,18 @@ static void brush_add(Scene *scene, Object *ob, ParticleSystem *psys, short *mva
 
                /* change old arrays to new ones */
                if(psys->particles) MEM_freeN(psys->particles);
-               psys->particles = new_pars;
+               psys->particles= new_pars;
 
                if(edit->keys) MEM_freeN(edit->keys);
-               edit->keys = new_keys;
+               edit->keys= new_keys;
 
                if(edit->mirror_cache) {
                        MEM_freeN(edit->mirror_cache);
-                       edit->mirror_cache = NULL;
+                       edit->mirror_cache= NULL;
                }
 
                /* create tree for interpolation */
-               if(pset->flag & PE_INTERPOLATE_ADDED && psys->totpart){
+               if(pset->flag & PE_INTERPOLATE_ADDED && psys->totpart) {
                        tree=BLI_kdtree_new(psys->totpart);
                        
                        for(i=0, pa=psys->particles; i<totpart; i++, pa++) {
@@ -2477,21 +2904,21 @@ static void brush_add(Scene *scene, Object *ob, ParticleSystem *psys, short *mva
                        BLI_kdtree_balance(tree);
                }
 
-               psys->totpart = newtotpart;
+               psys->totpart= newtotpart;
 
                /* create new elements */
-               pa = psys->particles + totpart;
-               key = edit->keys + totpart;
+               pa= psys->particles + totpart;
+               key= edit->keys + totpart;
 
-               for(i=totpart; i<newtotpart; i++, pa++, key++){
+               for(i=totpart; i<newtotpart; i++, pa++, key++) {
                        memcpy(pa, add_pars + i - totpart, sizeof(ParticleData));
-                       pa->hair = MEM_callocN(pset->totaddkey * sizeof(HairKey), "BakeKey key add");
-                       ekey = *key = MEM_callocN(pset->totaddkey * sizeof(ParticleEditKey), "ParticleEditKey add");
-                       pa->totkey = pset->totaddkey;
+                       pa->hair= MEM_callocN(pset->totaddkey * sizeof(HairKey), "BakeKey key add");
+                       ekey= *key= MEM_callocN(pset->totaddkey * sizeof(ParticleEditKey), "ParticleEditKey add");
+                       pa->totkey= pset->totaddkey;
 
                        for(k=0, hkey=pa->hair; k<pa->totkey; k++, hkey++, ekey++) {
-                               ekey->co = hkey->co;
-                               ekey->time = &hkey->time;
+                               ekey->co= hkey->co;
+                               ekey->time= &hkey->time;
                        }
                        
                        pa->size= 1.0f;
@@ -2501,9 +2928,9 @@ static void brush_add(Scene *scene, Object *ob, ParticleSystem *psys, short *mva
                        if(pset->flag & PE_X_MIRROR)
                                pa->flag |= PARS_TAG; /* signal for duplicate */
                        
-                       framestep = pa->lifetime/(float)(pset->totaddkey-1);
+                       framestep= pa->lifetime/(float)(pset->totaddkey-1);
 
-                       if(tree){
+                       if(tree) {
                                HairKey *hkey;
                                ParticleKey key[3];
                                KDTreeNearest ptn[3];
@@ -2511,39 +2938,39 @@ static void brush_add(Scene *scene, Object *ob, ParticleSystem *psys, short *mva
                                float maxd, mind, dd, totw=0.0, weight[3];
 
                                psys_particle_on_dm(psmd->dm,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,0,0);
-                               maxw = BLI_kdtree_find_n_nearest(tree,3,co1,NULL,ptn);
+                               maxw= BLI_kdtree_find_n_nearest(tree,3,co1,NULL,ptn);
 
-                               maxd = ptn[maxw-1].dist;
-                               mind = ptn[0].dist;
-                               dd = maxd - mind;
+                               maxd= ptn[maxw-1].dist;
+                               mind= ptn[0].dist;
+                               dd= maxd - mind;
                                
-                               for(w=0; w<maxw; w++){
-                                       weight[w] = (float)pow(2.0, (double)(-6.0f * ptn[w].dist / maxd));
+                               for(w=0; w<maxw; w++) {
+                                       weight[w]= (float)pow(2.0, (double)(-6.0f * ptn[w].dist / maxd));
                                        totw += weight[w];
                                }
-                               for(;w<3; w++){
-                                       weight[w] = 0.0f;
+                               for(;w<3; w++) {
+                                       weight[w]= 0.0f;
                                }
 
                                for(w=0; w<maxw; w++)
                                        weight[w] /= totw;
 
                                for(k=0; k<pset->totaddkey; k++) {
-                                       hkey = pa->hair + k;
-                                       hkey->time = pa->time + k * framestep;
+                                       hkey= pa->hair + k;
+                                       hkey->time= pa->time + k * framestep;
 
-                                       key[0].time = hkey->time/ 100.0f;
+                                       key[0].time= hkey->time/ 100.0f;
                                        psys_get_particle_on_path(scene, ob, psys, ptn[0].index, key, 0);
                                        VecMulf(key[0].co, weight[0]);
                                        
                                        if(maxw>1) {
-                                               key[1].time = key[0].time;
+                                               key[1].time= key[0].time;
                                                psys_get_particle_on_path(scene, ob, psys, ptn[1].index, key + 1, 0);
                                                VecMulf(key[1].co, weight[1]);
                                                VECADD(key[0].co, key[0].co, key[1].co);
 
                                                if(maxw>2) {                                            
-                                                       key[2].time = key[0].time;
+                                                       key[2].time= key[0].time;
                                                        psys_get_particle_on_path(scene, ob, psys, ptn[2].index, key + 2, 0);
                                                        VecMulf(key[2].co, weight[2]);
                                                        VECADD(key[0].co, key[0].co, key[2].co);
@@ -2555,10 +2982,10 @@ static void brush_add(Scene *scene, Object *ob, ParticleSystem *psys, short *mva
 
                                        VECADD(pa->hair[k].co, key[0].co, co1);
 
-                                       pa->hair[k].time = key[0].time;
+                                       pa->hair[k].time= key[0].time;
                                }
                        }
-                       else{
+                       else {
                                for(k=0, hkey=pa->hair; k<pset->totaddkey; k++, hkey++) {
                                        VECADDFAC(hkey->co, pa->state.co, pa->state.vel, k * framestep * timestep);
                                        pa->hair[k].time += k * framestep;
@@ -2570,7 +2997,7 @@ static void brush_add(Scene *scene, Object *ob, ParticleSystem *psys, short *mva
                                Mat4MulVecfl(imat, hkey->co);
                        }
                }
-               edit->totkeys = psys_count_keys(psys);
+               edit->totkeys= psys_count_keys(psys);
 
                if(tree)
                        BLI_kdtree_free(tree);
@@ -2578,422 +3005,358 @@ static void brush_add(Scene *scene, Object *ob, ParticleSystem *psys, short *mva
        if(add_pars)
                MEM_freeN(add_pars);
        
-/* painting onto the deformed mesh, could be an option? */
-#if EXPERIMENTAL_DEFORM_ONLY_PAINTING
-       if (!psmd->dm->deformedOnly)
+       if(!psmd->dm->deformedOnly)
                dm->release(dm);
-#endif
 }
-static void brush_weight(ParticleSystem *psys, float mat[][4], float imat[][4], int pa_index, int key_index, void *userData)
+
+static void brush_weight(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index)
 {
-       struct {Scene *scene; Object *ob; short *mval; float rad; rcti* rect; float dist; float weightfac;} *data = userData;
+       ParticleSystem *psys= data->psys;
        ParticleData *pa;
 
        /* roots have full weight allways */
        if(key_index) {
                pa= &psys->particles[pa_index];
-               pa->hair[key_index].weight = data->weightfac;
+               pa->hair[key_index].weight= data->weightfac;
                pa->flag |= PARS_EDIT_RECALC;
        }
 }
 
-/* returns 0 if no brush was used */
-int PE_brush_particles(void)
-{
-       Scene *scene= NULL; // XXX
-       ARegion *ar= NULL; // XXX
-       Object *ob = OBACT;
-       ParticleSystem *psys = PE_get_current(ob);
-       ParticleEdit *edit;
-       ParticleEditSettings *pset = PE_settings(scene);
-       ParticleSystemModifierData *psmd;
-       ParticleBrushData *brush;
-       float vec1[3], vec2[3];
-       short mval[2], mvalo[2], firsttime = 1, dx, dy;
-       int selected = 0, flip, removed = 0;
+/************************* brush edit operator ********************/
 
-       if(!PE_can_edit(psys)) return 0;
+typedef struct BrushEdit {
+       Scene *scene;
+       Object *ob;
+       ParticleSystem *psys;
 
-       edit = psys->edit;
-       psmd= psys_get_modifier(ob, psys);
+       int first;
+       int lastmouse[2];
+} BrushEdit;
 
-// XXX flip= (get_qual() == LR_SHIFTKEY);
+static int brush_edit_init(bContext *C, wmOperator *op)
+{
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       ParticleSystem *psys= PE_get_current(scene, ob);
+       ParticleEditSettings *pset= PE_settings(scene);
+       ARegion *ar= CTX_wm_region(C);
+       BrushEdit *bedit;
 
-       if(pset->brushtype<0) return 0;
-       brush= &pset->brush[pset->brushtype];
+       if(pset->brushtype < 0)
+               return 0;
 
        initgrabz(ar->regiondata, ob->obmat[3][0], ob->obmat[3][1], ob->obmat[3][2]);
 
-//     getmouseco_areawin(mvalo);
+       bedit= MEM_callocN(sizeof(BrushEdit), "BrushEdit");
+       bedit->first= 1;
+       op->customdata= bedit;
 
-       mval[0] = mvalo[0]; mval[1] = mvalo[1];
+       bedit->scene= scene;
+       bedit->ob= ob;
+       bedit->psys= psys;
 
-       while(0){ // XXX get_mbut
-               bglFlush();
-               glReadBuffer(GL_BACK);
-               glDrawBuffer(GL_BACK);
-//             persp(PERSP_VIEW);
-
-               dx=mval[0]-mvalo[0];
-               dy=mval[1]-mvalo[1];
-               if(((pset->brushtype == PE_BRUSH_ADD) ?
-                       (sqrt(dx * dx + dy * dy) > pset->brush[PE_BRUSH_ADD].step) : (dx != 0 || dy != 0))
-                       || firsttime){
-                       firsttime = 0;
-
-                       selected = (short)count_selected_keys(scene, psys);
+       return 1;
+}
 
-                       switch(pset->brushtype){
-                               case PE_BRUSH_COMB:
-                               {
-                                       struct {Scene *scene; Object *ob; short *mval; float rad; rcti* rect; float dist; float *dvec; float combfac;} data;
+static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
+{
+       BrushEdit *bedit= op->customdata;
+       Scene *scene= bedit->scene;
+       Object *ob= bedit->ob;
+       ParticleSystem *psys= bedit->psys;
+       ParticleEditSettings *pset= PE_settings(scene);
+       ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
+       ParticleBrushData *brush= &pset->brush[pset->brushtype];
+       ARegion *ar= CTX_wm_region(C);
+       float vec1[3], vec2[3], mousef[2];
+       short mval[2], mvalo[2];
+       int flip, mouse[2], dx, dy, removed= 0, selected= 0;
 
-                                       data.scene = scene;
-                                       data.ob = ob;
-                                       data.mval = mval;
-                                       data.rad = (float)brush->size;
+       RNA_float_get_array(itemptr, "mouse", mousef);
+       mouse[0] = mousef[0];
+       mouse[1] = mousef[1];
+       flip= RNA_boolean_get(itemptr, "flip");
 
-                                       data.combfac = (float)(brush->strength - 50) / 50.0f;
-                                       if(data.combfac < 0.0f)
-                                               data.combfac = 1.0f - 9.0f * data.combfac;
-                                       else
-                                               data.combfac = 1.0f - data.combfac;
+       if(bedit->first) {
+               bedit->lastmouse[0]= mouse[0];
+               bedit->lastmouse[1]= mouse[1];
+       }
 
-                                       Mat4Invert(ob->imat, ob->obmat);
+       dx= mouse[0] - bedit->lastmouse[0];
+       dy= mouse[1] - bedit->lastmouse[1];
 
-                                       window_to_3d(ar, vec1, mvalo[0], mvalo[1]);
-                                       window_to_3d(ar, vec2, mval[0], mval[1]);
-                                       VECSUB(vec1, vec2, vec1);
-                                       data.dvec = vec1;
+       mval[0]= mouse[0];
+       mval[1]= mouse[1];
 
-                                       foreach_mouse_hit_key(selected, psys,brush_comb, &data);
-                                       break;
-                               }
-                               case PE_BRUSH_CUT:
-                               {
-                                       struct {Scene *scene; short *mval; float rad; rcti* rect; int selected; float cutfac; bglMats mats;} data;
+       mvalo[0]= bedit->lastmouse[0];
+       mvalo[1]= bedit->lastmouse[1];
 
-                                       data.scene = scene;
-                                       data.mval = mval;
-                                       data.rad = (float)brush->size;
+       if(((pset->brushtype == PE_BRUSH_ADD) ?
+               (sqrt(dx * dx + dy * dy) > pset->brush[PE_BRUSH_ADD].step) : (dx != 0 || dy != 0))
+               || bedit->first) {
 
-                                       data.selected = selected;
+               view3d_operator_needs_opengl(C);
+               selected= (short)count_selected_keys(scene, psys);
 
-                                       data.cutfac = (float)(brush->strength / 100.0f);
+               switch(pset->brushtype) {
+                       case PE_BRUSH_COMB:
+                       {
+                               PEData data;
 
-                                       bgl_get_mats(&(data.mats));
+                               PE_set_view3d_data(C, &data);
+                               data.mval= mval;
+                               data.rad= (float)brush->size;
 
-                                       if(selected)
-                                               foreach_selected_element(psys, brush_cut, &data);
-                                       else
-                                               PE_foreach_element(psys, brush_cut, &data);
+                               data.combfac= (float)(brush->strength - 50) / 50.0f;
+                               if(data.combfac < 0.0f)
+                                       data.combfac= 1.0f - 9.0f * data.combfac;
+                               else
+                                       data.combfac= 1.0f - data.combfac;
 
-                                       removed= remove_tagged_elements(scene, ob, psys);
-                                       if(pset->flag & PE_KEEP_LENGTHS)
-                                               recalc_lengths(psys);
-                                       break;
-                               }
-                               case PE_BRUSH_LENGTH:
-                               {
-                                       struct {Scene *scene; short *mval; float rad; rcti* rect; float dist; float growfac; } data;
-                                       
-                                       data.scene= scene;
-                                       data.mval = mval;
-                                       
-                                       data.rad = (float)brush->size;
-                                       data.growfac = (float)brush->strength / 5000.0f;
+                               Mat4Invert(ob->imat, ob->obmat);
 
-                                       if(brush->invert ^ flip)
-                                               data.growfac = 1.0f - data.growfac;
-                                       else
-                                               data.growfac = 1.0f + data.growfac;
+                               window_to_3d(ar, vec1, mvalo[0], mvalo[1]);
+                               window_to_3d(ar, vec2, mval[0], mval[1]);
+                               VECSUB(vec1, vec2, vec1);
+                               data.dvec= vec1;
 
-                                       foreach_mouse_hit_element(selected, psys, brush_length, &data);
+                               foreach_mouse_hit_key(&data, brush_comb, selected);
+                               break;
+                       }
+                       case PE_BRUSH_CUT:
+                       {
+                               PEData data;
 
-                                       if(pset->flag & PE_KEEP_LENGTHS)
-                                               recalc_lengths(psys);
-                                       break;
-                               }
-                               case PE_BRUSH_PUFF:
-                               {
-                                       struct {Scene *scene; short *mval; float rad; rcti* rect; float dist;
-                                               Object *ob; DerivedMesh *dm; float pufffac; int invert; } data;
-
-                                       data.scene= scene;
-                                       data.ob = ob;
-                                       data.dm = psmd->dm;
-                                       data.mval = mval;
-                                       data.rad = (float)brush->size;
-
-                                       data.pufffac = (float)(brush->strength - 50) / 50.0f;
-                                       if(data.pufffac < 0.0f)
-                                               data.pufffac = 1.0f - 9.0f * data.pufffac;
-                                       else
-                                               data.pufffac = 1.0f - data.pufffac;
-
-                                       data.invert= (brush->invert ^ flip);
-                                       Mat4Invert(ob->imat, ob->obmat);
-
-                                       foreach_mouse_hit_element(selected, psys, brush_puff, &data);
-                                       break;
-                               }
-                               case PE_BRUSH_ADD:
-                                       if(psys->part->from==PART_FROM_FACE){
-                                               brush_add(scene, ob, psys, mval, brush->strength);
-                                               if(pset->flag & PE_KEEP_LENGTHS)
-                                                       recalc_lengths(psys);
-                                       }
-                                       break;
-                               case PE_BRUSH_WEIGHT:
-                               {
-                                       struct {Scene *scene; Object *ob; short *mval; float rad; rcti* rect; float dist; float weightfac;} data;
+                               PE_set_view3d_data(C, &data);
+                               data.mval= mval;
+                               data.rad= (float)brush->size;
+                               data.cutfac= (float)(brush->strength / 100.0f);
 
-                                       data.scene = scene;
-                                       data.ob = ob;
-                                       data.mval = mval;
-                                       data.rad = (float)brush->size;
+                               if(selected)
+                                       foreach_selected_particle(&data, brush_cut);
+                               else
+                                       PE_foreach_particle(&data, brush_cut);
 
-                                       data.weightfac = (float)(brush->strength / 100.0f);
+                               removed= remove_tagged_particles(scene, ob, psys);
+                               if(pset->flag & PE_KEEP_LENGTHS)
+                                       recalc_lengths(psys);
+                               break;
+                       }
+                       case PE_BRUSH_LENGTH:
+                       {
+                               PEData data;
+                               
+                               PE_set_view3d_data(C, &data);
+                               data.mval= mval;
+                               
+                               data.rad= (float)brush->size;
+                               data.growfac= (float)brush->strength / 5000.0f;
 
-                                       foreach_mouse_hit_key(selected, psys, brush_weight, &data);
-                                       break;
-                               }
-                               case PE_BRUSH_SMOOTH:
-                               {
-                                       struct {Scene *scene; Object *ob; short *mval; float rad; rcti* rect; float dist; float vec[3]; int tot; float smoothfac;} data;
+                               if(brush->invert ^ flip)
+                                       data.growfac= 1.0f - data.growfac;
+                               else
+                                       data.growfac= 1.0f + data.growfac;
 
-                                       data.scene = scene;
-                                       data.ob = ob;
-                                       data.mval = mval;
-                                       data.rad = (float)brush->size;
+                               foreach_mouse_hit_particle(&data, brush_length, selected);
 
-                                       data.vec[0] = data.vec[1] = data.vec[2] = 0.0f;
-                                       data.tot = 0;
+                               if(pset->flag & PE_KEEP_LENGTHS)
+                                       recalc_lengths(psys);
+                               break;
+                       }
+                       case PE_BRUSH_PUFF:
+                       {
+                               PEData data;
+
+                               PE_set_view3d_data(C, &data);
+                               data.dm= psmd->dm;
+                               data.mval= mval;
+                               data.rad= (float)brush->size;
+
+                               data.pufffac= (float)(brush->strength - 50) / 50.0f;
+                               if(data.pufffac < 0.0f)
+                                       data.pufffac= 1.0f - 9.0f * data.pufffac;
+                               else
+                                       data.pufffac= 1.0f - data.pufffac;
 
-                                       data.smoothfac = (float)(brush->strength / 100.0f);
+                               data.invert= (brush->invert ^ flip);
+                               Mat4Invert(ob->imat, ob->obmat);
 
-                                       Mat4Invert(ob->imat, ob->obmat);
+                               foreach_mouse_hit_particle(&data, brush_puff, selected);
+                               break;
+                       }
+                       case PE_BRUSH_ADD:
+                       {
+                               PEData data;
 
-                                       foreach_mouse_hit_key(selected, psys, brush_smooth_get, &data);
+                               if(psys->part->from==PART_FROM_FACE) {
+                                       PE_set_view3d_data(C, &data);
+                                       data.mval= mval;
 
-                                       if(data.tot){
-                                               VecMulf(data.vec, 1.0f / (float)data.tot);
-                                               foreach_mouse_hit_key(selected, psys, brush_smooth_do, &data);
-                                       }
+                                       brush_add(&data, brush->strength);
 
-                                       break;
+                                       if(pset->flag & PE_KEEP_LENGTHS)
+                                               recalc_lengths(psys);
                                }
+                               break;
                        }
-                       if((pset->flag & PE_KEEP_LENGTHS)==0)
-                               recalc_lengths(psys);
-
-                       if(pset->brushtype == PE_BRUSH_ADD || removed) {
-                               if(pset->brushtype == PE_BRUSH_ADD && (pset->flag & PE_X_MIRROR))
-                                       PE_mirror_x(scene, 1);
-                               PE_recalc_world_cos(ob,psys);
-                               psys_free_path_cache(psys);
-                               DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
-                       }
-                       else
-                               PE_update_object(scene, ob, 1);
-                       
-                       mvalo[0] = mval[0];
-                       mvalo[1] = mval[1];
-               }
+                       case PE_BRUSH_WEIGHT:
+                       {
+                               PEData data;
 
-               PIL_sleep_ms(10);
-               
-//             getmouseco_areawin(mval);
-       }
+                               PE_set_view3d_data(C, &data);
+                               data.mval= mval;
+                               data.rad= (float)brush->size;
 
-       BIF_undo_push("Brush edit particles");
+                               data.weightfac= (float)(brush->strength / 100.0f);
 
-       return 1;
-}
-
-static void set_delete_particle(ParticleSystem *psys, int index, void *userData)
-{
-       psys->particles[index].flag |= PARS_TAG;
-}
-
-static void set_delete_particle_key(ParticleSystem *psys, int pa_index, int key_index, void *userData)
-{
-       psys->edit->keys[pa_index][key_index].flag |= PEK_TAG;
-}
-
-void PE_delete_particle(void)
-{
-       Scene *scene= NULL; // XXX
-       Object *ob=OBACT;
-       ParticleSystem *psys = PE_get_current(ob);
-       short event=0;
-
-       if(!PE_can_edit(psys)) return;
-
-       event= pupmenu("Erase %t|Particle%x2|Key%x1");
-
-       if(event<1) return;
+                               foreach_mouse_hit_key(&data, brush_weight, selected);
+                               break;
+                       }
+                       case PE_BRUSH_SMOOTH:
+                       {
+                               PEData data;
 
-       if(event==1){
-               foreach_selected_key(psys, set_delete_particle_key, 0);
-               remove_tagged_keys(scene, ob, psys);
-               recalc_lengths(psys);
-       }
-       else if(event==2){
-               foreach_selected_element(psys, set_delete_particle, 0);
-               remove_tagged_elements(scene, ob, psys);
-               recalc_lengths(psys);
-       }
+                               PE_set_view3d_data(C, &data);
+                               data.mval= mval;
+                               data.rad= (float)brush->size;
 
-       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
-       BIF_undo_push("Delete particles/keys");
-}
+                               data.vec[0]= data.vec[1]= data.vec[2]= 0.0f;
+                               data.tot= 0;
 
-void PE_mirror_x(Scene *scene, int tagged)
-{
-       Object *ob=OBACT;
-       Mesh *me= (Mesh*)(ob->data);
-       ParticleSystemModifierData *psmd;
-       ParticleSystem *psys = PE_get_current(ob);
-       ParticleEdit *edit;
-       ParticleData *pa, *newpa, *new_pars;
-       ParticleEditKey *ekey, **newkey, **key, **new_keys;
-       HairKey *hkey;
-       int *mirrorfaces;
-       int i, k, rotation, totpart, newtotpart;
+                               data.smoothfac= (float)(brush->strength / 100.0f);
 
-       if(!PE_can_edit(psys)) return;
+                               Mat4Invert(ob->imat, ob->obmat);
 
-       edit= psys->edit;
-       psmd= psys_get_modifier(ob, psys);
+                               foreach_mouse_hit_key(&data, brush_smooth_get, selected);
 
-       mirrorfaces= mesh_get_x_mirror_faces(ob);
+                               if(data.tot) {
+                                       VecMulf(data.vec, 1.0f / (float)data.tot);
+                                       foreach_mouse_hit_key(&data, brush_smooth_do, selected);
+                               }
 
-       if(!edit->mirror_cache)
-               PE_update_mirror_cache(ob, psys);
+                               break;
+                       }
+               }
+               if((pset->flag & PE_KEEP_LENGTHS)==0)
+                       recalc_lengths(psys);
 
-       totpart= psys->totpart;
-       newtotpart= psys->totpart;
-       LOOP_PARTICLES(i,pa) {
-               if(pa->flag&PARS_HIDE) continue;
+               if(pset->brushtype == PE_BRUSH_ADD || removed) {
+                       if(pset->brushtype == PE_BRUSH_ADD && (pset->flag & PE_X_MIRROR))
+                               PE_mirror_x(scene, ob, 1);
 
-               if(!tagged) {
-                       if(particle_is_selected(psys, pa)) {
-                               if(edit->mirror_cache[i] != -1) {
-                                       /* already has a mirror, don't need to duplicate */
-                                       PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
-                                       continue;
-                               }
-                               else
-                                       pa->flag |= PARS_TAG;
-                       }
+                       psys_update_world_cos(ob,psys);
+                       psys_free_path_cache(psys);
+                       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
                }
+               else
+                       PE_update_object(scene, ob, 1);
 
-               if((pa->flag & PARS_TAG) && mirrorfaces[pa->num*2] != -1)
-                       newtotpart++;
+               WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
+               
+               bedit->lastmouse[0]= mouse[0];
+               bedit->lastmouse[1]= mouse[1];
+               bedit->first= 0;
        }
+}
 
-       if(newtotpart != psys->totpart) {
-               /* allocate new arrays and copy existing */
-               new_pars= MEM_callocN(newtotpart*sizeof(ParticleData), "ParticleData new");
-               new_keys= MEM_callocN(newtotpart*sizeof(ParticleEditKey*), "ParticleEditKey new");
+static void brush_edit_exit(bContext *C, wmOperator *op)
+{
+       BrushEdit *bedit= op->customdata;
 
-               memcpy(new_pars, psys->particles, totpart*sizeof(ParticleData));
-               memcpy(new_keys, edit->keys, totpart*sizeof(ParticleEditKey*));
+       MEM_freeN(bedit);
+}
 
-               if(psys->particles) MEM_freeN(psys->particles);
-               psys->particles= new_pars;
+static int brush_edit_exec(bContext *C, wmOperator *op)
+{
+       if(!brush_edit_init(C, op))
+               return OPERATOR_CANCELLED;
 
-               if(edit->keys) MEM_freeN(edit->keys);
-               edit->keys= new_keys;
+       RNA_BEGIN(op->ptr, itemptr, "stroke") {
+               brush_edit_apply(C, op, &itemptr);
+       }
+       RNA_END;
 
-               if(edit->mirror_cache) {
-                       MEM_freeN(edit->mirror_cache);
-                       edit->mirror_cache= NULL;
-               }
+       brush_edit_exit(C, op);
 
-               psys->totpart= newtotpart;
-                       
-               /* create new elements */
-               pa= psys->particles;
-               newpa= psys->particles + totpart;
-               key= edit->keys;
-               newkey= edit->keys + totpart;
+       return OPERATOR_FINISHED;
+}
 
-               for(i=0; i<totpart; i++, pa++, key++) {
-                       if(pa->flag&PARS_HIDE) continue;
+static void brush_edit_apply_event(bContext *C, wmOperator *op, wmEvent *event)
+{
+       ARegion *ar= CTX_wm_region(C);
+       PointerRNA itemptr;
+       float mouse[2];
 
-                       if(!(pa->flag & PARS_TAG) || mirrorfaces[pa->num*2] == -1)
-                               continue;
+       mouse[0]= event->x - ar->winrct.xmin;
+       mouse[1]= event->y - ar->winrct.ymin;
 
-                       /* duplicate */
-                       *newpa= *pa;
-                       if(pa->hair) newpa->hair= MEM_dupallocN(pa->hair);
-                       if(pa->keys) newpa->keys= MEM_dupallocN(pa->keys);
-                       if(*key) *newkey= MEM_dupallocN(*key);
+       /* fill in stroke */
+       RNA_collection_add(op->ptr, "stroke", &itemptr);
 
-                       /* rotate weights according to vertex index rotation */
-                       rotation= mirrorfaces[pa->num*2+1];
-                       newpa->fuv[0]= pa->fuv[2];
-                       newpa->fuv[1]= pa->fuv[1];
-                       newpa->fuv[2]= pa->fuv[0];
-                       newpa->fuv[3]= pa->fuv[3];
-                       while(rotation-- > 0)
-                               if(me->mface[pa->num].v4)
-                                       SHIFT4(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2], newpa->fuv[3])
-                               else
-                                       SHIFT3(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2])
+       RNA_float_set_array(&itemptr, "mouse", mouse);
+       RNA_boolean_set(&itemptr, "flip", event->shift != 0); // XXX hardcoded
 
-                       /* assign face inddex */
-                       newpa->num= mirrorfaces[pa->num*2];
-                       newpa->num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,newpa->num,newpa->fuv, NULL);
+       /* apply */
+       brush_edit_apply(C, op, &itemptr);
+}
 
-                       /* update edit key pointers */
-                       ekey= *newkey;
-                       for(k=0, hkey=newpa->hair; k<newpa->totkey; k++, hkey++, ekey++) {
-                               ekey->co= hkey->co;
-                               ekey->time= &hkey->time;
-                       }
+static int brush_edit_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       if(!brush_edit_init(C, op))
+               return OPERATOR_CANCELLED;
+       
+       brush_edit_apply_event(C, op, event);
 
-                       /* map key positions as mirror over x axis */
-                       PE_mirror_particle(ob, psmd->dm, psys, pa, newpa);
+       WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
 
-                       newpa++;
-                       newkey++;
-               }
+       return OPERATOR_RUNNING_MODAL;
+}
 
-               edit->totkeys = psys_count_keys(psys);
+static int brush_edit_modal(bContext *C, wmOperator *op, wmEvent *event)
+{
+       switch(event->type) {
+               case LEFTMOUSE:
+               case MIDDLEMOUSE:
+               case RIGHTMOUSE: // XXX hardcoded
+                       brush_edit_exit(C, op);
+                       return OPERATOR_FINISHED;
+               case MOUSEMOVE:
+                       brush_edit_apply_event(C, op, event);
+                       break;
        }
 
-       for(pa=psys->particles, i=0; i<psys->totpart; i++, pa++)
-               pa->flag &= ~PARS_TAG;
+       return OPERATOR_RUNNING_MODAL;
+}
 
-       MEM_freeN(mirrorfaces);
+static int brush_edit_cancel(bContext *C, wmOperator *op)
+{
+       brush_edit_exit(C, op);
 
-       if(!tagged) {
-               PE_recalc_world_cos(ob,psys);
-               DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
-               BIF_undo_push("Mirror particles");
-       }
+       return OPERATOR_CANCELLED;
 }
 
-void PE_selectbrush_menu(Scene *scene)
+void PARTICLE_OT_brush_edit(wmOperatorType *ot)
 {
-       ParticleEditSettings *pset= PE_settings(scene);
-       int val;
-       
-       // XXX pupmenu_set_active(pset->brushtype);
+       /* identifiers */
+       ot->name= "Brush Edit";
+       ot->idname= "PARTICLE_OT_brush_edit";
        
-       val= pupmenu("Select Brush%t|None %x0|Comb %x1|Smooth %x7|Weight %x6|Add %x5|Length %x3|Puff %x4|Cut %x2");
+       /* api callbacks */
+       ot->exec= brush_edit_exec;
+       ot->invoke= brush_edit_invoke;
+       ot->modal= brush_edit_modal;
+       ot->cancel= brush_edit_cancel;
+       ot->poll= PE_poll_3dview;
 
-       if(val>=0) {
-               pset->brushtype= val-1;
-       }
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
+
+       /* properties */
+       RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
 }
 
-/************************************************/
-/*                     Particle Edit Undo                                      */
-/************************************************/
+/*********************** undo ***************************/
+
 static void free_ParticleUndo(ParticleUndo *undo)
 {
        ParticleData *pa;
@@ -3014,31 +3377,33 @@ static void free_ParticleUndo(ParticleUndo *undo)
        //if(undo->emitter_cosnos)
        //      MEM_freeN(undo->emitter_cosnos);
 }
+
 static void make_ParticleUndo(ParticleSystem *psys, ParticleUndo *undo)
 {
        ParticleData *pa,*upa;
        int i;
 
-       undo->totpart = psys->totpart;
-       undo->totkeys = psys->edit->totkeys;
+       undo->totpart= psys->totpart;
+       undo->totkeys= psys->edit->totkeys;
 
-       upa = undo->particles = MEM_dupallocN(psys->particles);
-       undo->keys = MEM_dupallocN(psys->edit->keys);
+       upa= undo->particles= MEM_dupallocN(psys->particles);
+       undo->keys= MEM_dupallocN(psys->edit->keys);
        
        for(i=0, pa=psys->particles; i<undo->totpart; i++, pa++, upa++) {
-               upa->hair = MEM_dupallocN(pa->hair);
-               undo->keys[i] = MEM_dupallocN(psys->edit->keys[i]);
+               upa->hair= MEM_dupallocN(pa->hair);
+               undo->keys[i]= MEM_dupallocN(psys->edit->keys[i]);
                /* no need to update edit key->co & key->time pointers here */
        }
 }
+
 static void get_ParticleUndo(ParticleSystem *psys, ParticleUndo *undo)
 {
        ParticleData *pa, *upa;
        ParticleEditKey *key;
        HairKey *hkey;
-       int i, k, totpart = psys->totpart;
+       int i, k, totpart= psys->totpart;
 
-       LOOP_PARTICLES(i,pa) {
+       LOOP_PARTICLES(i, pa) {
                if(pa->hair)
                        MEM_freeN(pa->hair);
 
@@ -3054,31 +3419,31 @@ static void get_ParticleUndo(ParticleSystem *psys, ParticleUndo *undo)
                psys->edit->mirror_cache= NULL;
        }
 
-       pa = psys->particles = MEM_dupallocN(undo->particles);
-       psys->edit->keys = MEM_dupallocN(undo->keys);
+       pa= psys->particles= MEM_dupallocN(undo->particles);
+       psys->edit->keys= MEM_dupallocN(undo->keys);
 
-       for(i=0,upa=undo->particles; i<undo->totpart; i++, upa++, pa++){
-               hkey = pa->hair = MEM_dupallocN(upa->hair);
-               key = psys->edit->keys[i] = MEM_dupallocN(undo->keys[i]);
+       for(i=0,upa=undo->particles; i<undo->totpart; i++, upa++, pa++) {
+               hkey= pa->hair= MEM_dupallocN(upa->hair);
+               key= psys->edit->keys[i]= MEM_dupallocN(undo->keys[i]);
                for(k=0; k<pa->totkey; k++, hkey++, key++) {
-                       key->co = hkey->co;
-                       key->time = &hkey->time;
+                       key->co= hkey->co;
+                       key->time= &hkey->time;
                }
        }
 
-       psys->totpart = undo->totpart;
-       psys->edit->totkeys = undo->totkeys;
+       psys->totpart= undo->totpart;
+       psys->edit->totkeys= undo->totkeys;
 }
 
 void PE_undo_push(Scene *scene, char *str)
 {
-       ParticleSystem *psys = PE_get_current(OBACT);
-       ParticleEdit *edit = 0;
+       ParticleSystem *psys= PE_get_current(scene, OBACT);
+       ParticleEdit *edit= 0;
        ParticleUndo *undo;
        int nr;
 
        if(!PE_can_edit(psys)) return;
-       edit = psys->edit;
+       edit= psys->edit;
 
        /* remove all undos after (also when curundo==NULL) */
        while(edit->undo.last != edit->curundo) {
@@ -3113,20 +3478,21 @@ void PE_undo_push(Scene *scene, char *str)
        /* copy  */
        make_ParticleUndo(psys,edit->curundo);
 }
+
 void PE_undo_step(Scene *scene, int step)
 {      
-       ParticleSystem *psys = PE_get_current(OBACT);
-       ParticleEdit *edit = 0;
+       ParticleSystem *psys= PE_get_current(scene, OBACT);
+       ParticleEdit *edit= 0;
 
        if(!PE_can_edit(psys)) return;
-       edit=psys->edit;
+       edit= psys->edit;
 
        if(step==0) {
                get_ParticleUndo(psys,edit->curundo);
        }
        else if(step==1) {
                
-               if(edit->curundo==NULL || edit->curundo->prev==NULL) error("No more steps to undo");
+               if(edit->curundo==NULL || edit->curundo->prev==NULL);
                else {
                        if(G.f & G_DEBUG) printf("undo %s\n", edit->curundo->name);
                        edit->curundo= edit->curundo->prev;
@@ -3136,7 +3502,7 @@ void PE_undo_step(Scene *scene, int step)
        else {
                /* curundo has to remain current situation! */
                
-               if(edit->curundo==NULL || edit->curundo->next==NULL) error("No more steps to redo");
+               if(edit->curundo==NULL || edit->curundo->next==NULL);
                else {
                        get_ParticleUndo(psys, edit->curundo->next);
                        edit->curundo= edit->curundo->next;
@@ -3166,7 +3532,7 @@ static void ParticleUndo_clear(ParticleSystem *psys)
 
        if(psys==0) return;
 
-       edit = psys->edit;
+       edit= psys->edit;
 
        if(edit==0) return;
        
@@ -3178,25 +3544,28 @@ static void ParticleUndo_clear(ParticleSystem *psys)
        BLI_freelistN(&edit->undo);
        edit->curundo= NULL;
 }
+
 void PE_undo(Scene *scene)
 {
        PE_undo_step(scene, 1);
 }
+
 void PE_redo(Scene *scene)
 {
        PE_undo_step(scene, -1);
 }
-void PE_undo_menu(Scene *scene)
+
+void PE_undo_menu(Scene *scene, Object *ob)
 {
-       ParticleSystem *psys = PE_get_current(OBACT);
-       ParticleEdit *edit = 0;
+       ParticleSystem *psys= PE_get_current(scene, ob);
+       ParticleEdit *edit= 0;
        ParticleUndo *undo;
        DynStr *ds;
-       short event;
+       short event=0;
        char *menu;
 
        if(!PE_can_edit(psys)) return;
-       edit = psys->edit;
+       edit= psys->edit;
        
        ds= BLI_dynstr_new();
 
@@ -3216,34 +3585,30 @@ void PE_undo_menu(Scene *scene)
        if(event>0) ParticleUndo_number(scene, edit,event);
 }
 
-void PE_get_colors(char sel[4], char nosel[4])
-{
-       UI_GetThemeColor3ubv(TH_EDGE_SELECT, sel);
-       UI_GetThemeColor3ubv(TH_WIRE, nosel);
-}
+/************************ utilities ******************************/
 
 int PE_minmax(Scene *scene, float *min, float *max)
 {
-       Object *ob = OBACT;
-       ParticleSystem *psys = PE_get_current(ob);
+       Object *ob= OBACT;
+       ParticleSystem *psys= PE_get_current(scene, ob);
        ParticleSystemModifierData *psmd;
        ParticleData *pa;
        ParticleEditKey *key;
        float co[3], mat[4][4];
-       int i, k, totpart, ok = 0;
+       int i, k, totpart, ok= 0;
 
        if(!PE_can_edit(psys)) return ok;
        
        psmd= psys_get_modifier(ob, psys);
        totpart= psys->totpart;
 
-       LOOP_PARTICLES(i,pa){
-               if(pa->flag&PARS_HIDE) continue;
+       LOOP_PARTICLES(i, pa) {
+               if(pa->flag & PARS_HIDE) continue;
 
                psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, mat);
 
-               LOOP_KEYS(k,key){
-                       if(key->flag&PEK_SELECT) {
+               LOOP_KEYS(k, key) {
+                       if(key->flag & PEK_SELECT) {
                                VECCOPY(co, key->co);
                                Mat4MulVecfl(mat, co);
                                DO_MINMAX(co, min, max);                
@@ -3260,3 +3625,302 @@ int PE_minmax(Scene *scene, float *min, float *max)
        return ok;
 }
 
+/************************ particle edit toggle operator ************************/
+
+/* initialize needed data for bake edit */
+static void PE_create_particle_edit(Scene *scene, Object *ob, ParticleSystem *psys)
+{
+       ParticleEdit *edit= psys->edit;
+       ParticleData *pa;
+       ParticleEditKey *key;
+       HairKey *hkey;
+       int i, k, totpart= psys->totpart, alloc=1;
+
+       if((psys->flag & PSYS_EDITED)==0)
+               return;
+
+       if(edit) {
+               int newtotkeys= psys_count_keys(psys);
+
+               if(newtotkeys == edit->totkeys)
+                       alloc=0;
+       }
+
+       if(alloc) {
+               if(edit) {
+                       printf("ParticleEdit exists already! Poke jahka!");
+                       PE_free_particle_edit(psys);
+               }
+
+               edit= psys->edit=MEM_callocN(sizeof(ParticleEdit), "PE_create_particle_edit");
+               psys->free_edit= PE_free_particle_edit;
+
+               edit->keys=MEM_callocN(totpart*sizeof(ParticleEditKey*),"ParticleEditKey array");
+
+               LOOP_PARTICLES(i, pa) {
+                       key= edit->keys[i]= MEM_callocN(pa->totkey*sizeof(ParticleEditKey),"ParticleEditKeys");
+                       for(k=0, hkey=pa->hair; k<pa->totkey; k++, hkey++, key++) {
+                               key->co= hkey->co;
+                               key->time= &hkey->time;
+                               key->flag= hkey->editflag;
+                       }
+               }
+
+               edit->totkeys= psys_count_keys(psys);
+
+               UI_GetThemeColor3ubv(TH_EDGE_SELECT, edit->sel_col);
+               UI_GetThemeColor3ubv(TH_WIRE, edit->nosel_col);
+       }
+
+       recalc_lengths(psys);
+       recalc_emitter_field(ob, psys);
+       psys_update_world_cos(ob, psys);
+
+       if(alloc) {
+               ParticleUndo_clear(psys);
+               PE_undo_push(scene, "Original");
+       }
+}
+
+static int particle_edit_toggle_poll(bContext *C)
+{
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+
+       if(!scene || !ob || ob->id.lib)
+               return 0;
+       
+       return (ob->particlesystem.first != NULL);
+}
+
+static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       ParticleSystem *psys= PE_get_current(scene, ob);
+       
+       if(psys==NULL) {
+               psys= ob->particlesystem.first;
+               psys->flag |= PSYS_CURRENT;
+       }
+
+       if(!(ob->mode & OB_MODE_PARTICLE_EDIT)) {
+               if(psys && psys->part->type == PART_HAIR && psys->flag & PSYS_EDITED) {
+                       if(psys_check_enabled(ob, psys)) {
+                               if(psys->edit==NULL)
+                                       PE_create_particle_edit(scene, ob, psys);
+
+                               psys_update_world_cos(ob, psys);
+                       }
+               }
+
+               ob->mode |= OB_MODE_PARTICLE_EDIT;
+               toggle_particle_cursor(C, 1);
+               WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_PARTICLE, NULL);
+       }
+       else {
+               ob->mode &= ~OB_MODE_PARTICLE_EDIT;
+               toggle_particle_cursor(C, 0);
+               WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, NULL);
+       }
+
+       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+
+       return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_particle_edit_toggle(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Particle Edit Toggle";
+       ot->idname= "PARTICLE_OT_particle_edit_toggle";
+       
+       /* api callbacks */
+       ot->exec= particle_edit_toggle_exec;
+       ot->poll= particle_edit_toggle_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+
+/************************ set editable operator ************************/
+
+static int set_editable_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       ParticleSystem *psys= PE_get_current(scene, ob);
+       
+       if(psys->flag & PSYS_EDITED) {
+               if(1) { // XXX okee("Lose changes done in particle mode?")) {
+                       if(psys->edit)
+                               PE_free_particle_edit(psys);
+
+                       psys->flag &= ~PSYS_EDITED;
+                       psys->recalc |= PSYS_RECALC_RESET;
+
+                       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+               }
+       }
+       else {
+               if(psys_check_enabled(ob, psys)) {
+                       psys->flag |= PSYS_EDITED;
+
+                       if(ob->mode & OB_MODE_PARTICLE_EDIT)
+                               PE_create_particle_edit(scene, ob, psys);
+               }
+               else
+                       BKE_report(op->reports, RPT_ERROR, "Particle system not enabled, skipping set editable");
+       }
+
+       return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_editable_set(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Set Editable";
+       ot->idname= "PARTICLE_OT_editable_set";
+       
+       /* api callbacks */
+       ot->exec= set_editable_exec;
+       ot->poll= particle_edit_toggle_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/*********************** change active **************************/
+
+void PE_change_act(void *ob_v, void *act_v)
+{
+       Scene *scene= NULL; // XXX
+       Object *ob= ob_v;
+       ParticleSystem *psys;
+       short act= *((short*)act_v) - 1;
+
+       if((psys=psys_get_current(ob)))
+               psys->flag &= ~PSYS_CURRENT;
+
+       if(act>=0) {
+               if((psys=BLI_findlink(&ob->particlesystem,act))) {
+                       psys->flag |= PSYS_CURRENT;
+
+                       if(psys_check_enabled(ob, psys)) {
+                               if(ob->mode & OB_MODE_PARTICLE_EDIT && !psys->edit)
+                                       PE_create_particle_edit(scene, ob, psys);
+                               psys_update_world_cos(ob, psys);
+                       }
+               }
+       }
+}
+
+void PE_change_act_psys(Scene *scene, Object *ob, ParticleSystem *psys)
+{
+       ParticleSystem *p;
+       
+       if((p=psys_get_current(ob)))
+               p->flag &= ~PSYS_CURRENT;
+       
+       psys->flag |= PSYS_CURRENT;
+       
+       if(psys_check_enabled(ob, psys)) {
+               if(ob->mode & OB_MODE_PARTICLE_EDIT && !psys->edit)
+                       PE_create_particle_edit(scene, ob, psys);
+
+               psys_update_world_cos(ob, psys);
+       }
+}
+
+/*********************** specials menu **************************/
+
+static int specials_menu_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       Scene *scene= CTX_data_scene(C);
+       ParticleEditSettings *pset=PE_settings(scene);
+       uiPopupMenu *pup;
+       uiLayout *layout;
+
+       pup= uiPupMenuBegin(C, "Specials", 0);
+       layout= uiPupMenuLayout(pup);
+
+       uiItemO(layout, NULL, 0, "PARTICLE_OT_rekey");
+       if(pset->selectmode & SCE_SELECT_POINT) {
+               uiItemO(layout, NULL, 0, "PARTICLE_OT_subdivide");
+               uiItemO(layout, NULL, 0, "PARTICLE_OT_select_first");
+               uiItemO(layout, NULL, 0, "PARTICLE_OT_select_last");
+       }
+       uiItemO(layout, NULL, 0, "PARTICLE_OT_remove_doubles");
+
+       uiPupMenuEnd(C, pup);
+
+       return OPERATOR_CANCELLED;
+}
+
+void PARTICLE_OT_specials_menu(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Specials Menu";
+       ot->idname= "PARTICLE_OT_specials_menu";
+       
+       /* api callbacks */
+       ot->invoke= specials_menu_invoke;
+       ot->poll= PE_poll;
+}
+
+/**************************** registration **********************************/
+
+void ED_operatortypes_particle(void)
+{
+       WM_operatortype_append(PARTICLE_OT_select_all_toggle);
+       WM_operatortype_append(PARTICLE_OT_select_first);
+       WM_operatortype_append(PARTICLE_OT_select_last);
+       WM_operatortype_append(PARTICLE_OT_select_linked);
+       WM_operatortype_append(PARTICLE_OT_select_less);
+       WM_operatortype_append(PARTICLE_OT_select_more);
+
+       WM_operatortype_append(PARTICLE_OT_hide);
+       WM_operatortype_append(PARTICLE_OT_reveal);
+
+       WM_operatortype_append(PARTICLE_OT_rekey);
+       WM_operatortype_append(PARTICLE_OT_subdivide);
+       WM_operatortype_append(PARTICLE_OT_remove_doubles);
+       WM_operatortype_append(PARTICLE_OT_delete);
+       WM_operatortype_append(PARTICLE_OT_mirror);
+
+       WM_operatortype_append(PARTICLE_OT_brush_set);
+       WM_operatortype_append(PARTICLE_OT_brush_edit);
+       WM_operatortype_append(PARTICLE_OT_brush_radial_control);
+
+       WM_operatortype_append(PARTICLE_OT_specials_menu);
+
+       WM_operatortype_append(PARTICLE_OT_particle_edit_toggle);
+       WM_operatortype_append(PARTICLE_OT_editable_set);
+}
+
+void ED_keymap_particle(wmWindowManager *wm)
+{
+       ListBase *keymap= WM_keymap_listbase(wm, "Particle", 0, 0);
+       
+       WM_keymap_add_item(keymap, "PARTICLE_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "PARTICLE_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
+       WM_keymap_add_item(keymap, "PARTICLE_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
+       WM_keymap_add_item(keymap, "PARTICLE_OT_select_linked", LKEY, KM_PRESS, 0, 0);
+       RNA_boolean_set(WM_keymap_add_item(keymap, "PARTICLE_OT_select_linked", LKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "deselect", 1);
+
+       WM_keymap_add_item(keymap, "PARTICLE_OT_delete", XKEY, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "PARTICLE_OT_delete", DELKEY, KM_PRESS, 0, 0);
+
+       WM_keymap_add_item(keymap, "PARTICLE_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0);
+       WM_keymap_add_item(keymap, "PARTICLE_OT_hide", HKEY, KM_PRESS, 0, 0);
+       RNA_enum_set(WM_keymap_add_item(keymap, "PARTICLE_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "unselected", 1);
+
+       WM_keymap_add_item(keymap, "PARTICLE_OT_brush_edit", ACTIONMOUSE, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "PARTICLE_OT_brush_edit", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0);
+       RNA_enum_set(WM_keymap_add_item(keymap, "PARTICLE_OT_brush_radial_control", FKEY, KM_PRESS, 0, 0)->ptr, "mode", WM_RADIALCONTROL_SIZE);
+       RNA_enum_set(WM_keymap_add_item(keymap, "PARTICLE_OT_brush_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", WM_RADIALCONTROL_STRENGTH);
+
+       WM_keymap_add_item(keymap, "PARTICLE_OT_specials_menu", WKEY, KM_PRESS, 0, 0);
+}
+