svn merge -r 13095:13148 https://svn.blender.org/svnroot/bf-blender/trunk/blender
authorDaniel Genrich <daniel.genrich@gmx.net>
Mon, 7 Jan 2008 03:25:11 +0000 (03:25 +0000)
committerDaniel Genrich <daniel.genrich@gmx.net>
Mon, 7 Jan 2008 03:25:11 +0000 (03:25 +0000)
1  2 
source/blender/blenloader/intern/readfile.c
source/blender/src/buttons_editing.c
source/blender/src/buttons_object.c
source/blender/src/editparticle.c
source/blender/src/transform_conversions.c

index 37d15b65de5c87dfe8ba11fba067bd99d3445e18,fb7388417f2d86b8d6db4a5c34be5d986cef1eaf..96b0c372835aacd8975be9c8105e69b192af816d
@@@ -60,7 -60,6 +60,7 @@@
  #include "DNA_actuator_types.h"
  #include "DNA_brush_types.h"
  #include "DNA_camera_types.h"
 +#include "DNA_cloth_types.h"
  #include "DNA_color_types.h"
  #include "DNA_controller_types.h"
  #include "DNA_constraint_types.h"
  
  #include "BKE_action.h"
  #include "BKE_armature.h"
 +#include "BKE_cloth.h"
  #include "BKE_colortools.h"
  #include "BKE_constraint.h"
  #include "BKE_curve.h"
@@@ -2981,31 -2979,7 +2981,31 @@@ static void direct_link_modifiers(FileD
                        SubsurfModifierData *smd = (SubsurfModifierData*) md;
  
                        smd->emCache = smd->mCache = 0;
 -              } else if (md->type==eModifierType_Hook) {
 +              } 
 +              else if (md->type==eModifierType_Cloth) {
 +                 ClothModifierData    *clmd = (ClothModifierData*) md;
 +
 +                 clmd->clothObject = NULL;
 +                 /*
 +                 clmd->sim_parms= newdataadr(fd, clmd->sim_parms);
 +                 clmd->coll_parms= newdataadr(fd, clmd->coll_parms);
 +                 */
 +                 
 +              } 
 +              else if (md->type==eModifierType_Collision) {
 +                      /*
 +                      CollisionModifierData *collmd = (CollisionModifierData*) md;
 +                      
 +                      collmd->x = NULL;
 +                      collmd->xnew = NULL;
 +                      collmd->current_x = NULL;
 +                      collmd->current_xnew = NULL;
 +                      collmd->time = -1;
 +                      collmd->numverts = 0;
 +                      collmd->tree = NULL;
 +                      */
 +              }
 +              else if (md->type==eModifierType_Hook) {
                        HookModifierData *hmd = (HookModifierData*) md;
  
                        hmd->indexar= newdataadr(fd, hmd->indexar);
@@@ -3150,6 -3124,7 +3150,6 @@@ static void direct_link_object(FileDat
                sb->bpoint= NULL;       // init pointers so it gets rebuilt nicely
                sb->bspring= NULL;
                sb->scratch= NULL;
 -
                /* although not used anymore */
                /* still have to be loaded to be compatible with old files */
                sb->keys= newdataadr(fd, sb->keys);
@@@ -7892,6 -7867,12 +7892,12 @@@ static void expand_modifier(FileData *f
                        
                expand_doit(fd, mainvar, mmd->mirror_ob);
        }
+       else if (md->type==eModifierType_Displace) {
+               DisplaceModifierData *dmd = (DisplaceModifierData*) md;
+               
+               expand_doit(fd, mainvar, dmd->map_object);
+               expand_doit(fd, mainvar, dmd->texture);
+       }
  }
  
  static void expand_scriptlink(FileData *fd, Main *mainvar, ScriptLink *slink)
index 7c3c8005e9f8061f8ace042587c55ae5a97ab2bc,ff12c9526c78acfe071441c7f5e9d29abc65e5e6..57c9eab5d705dc22012b65e90c649e00333b1fbb
@@@ -984,8 -984,6 +984,8 @@@ static uiBlock *modifiers_add_menu(voi
  
                /* Only allow adding through appropriate other interfaces */
                if(ELEM3(i, eModifierType_Softbody, eModifierType_Hook, eModifierType_ParticleSystem)) continue;
 +              
 +              if(ELEM(i, eModifierType_Cloth, eModifierType_Collision)) continue;
  
                if((mti->flags&eModifierTypeFlag_AcceptsCVs) ||
                   (ob->type==OB_MESH && (mti->flags&eModifierTypeFlag_AcceptsMesh))) {
@@@ -1664,7 -1662,7 +1664,7 @@@ static void draw_modifier(uiBlock *bloc
        uiBlockSetCol(block, TH_AUTO);
        
        /* open/close icon */
 -      if (!isVirtual) {
 +      if (!isVirtual && md->type!=eModifierType_Collision) {
                uiBlockSetEmboss(block, UI_EMBOSSN);
                uiDefIconButBitI(block, ICONTOG, eModifierMode_Expanded, B_MODIFIER_REDRAW, VICON_DISCLOSURE_TRI_RIGHT, x-10, y-2, 20, 20, &md->mode, 0.0, 0.0, 0.0, 0.0, "Collapse/Expand Modifier");
        }
                uiBlockBeginAlign(block);
                uiDefBut(block, TEX, B_MODIFIER_REDRAW, "", x+10, y-1, buttonWidth-60, 19, md->name, 0.0, sizeof(md->name)-1, 0.0, 0.0, "Modifier name"); 
  
 -                      /* Softbody not allowed in this situation, enforce! */
 -              if (md->type!=eModifierType_Softbody || !(ob->pd && ob->pd->deflect)) {
 +              /* Softbody not allowed in this situation, enforce! */
 +              if ((md->type!=eModifierType_Softbody && md->type!=eModifierType_Collision) || !(ob->pd && ob->pd->deflect)) {
                        uiDefIconButBitI(block, TOG, eModifierMode_Render, B_MODIFIER_RECALC, ICON_SCENE, x+10+buttonWidth-60, y-1, 19, 19,&md->mode, 0, 0, 1, 0, "Enable modifier during rendering");
                        but= uiDefIconButBitI(block, TOG, eModifierMode_Realtime, B_MODIFIER_RECALC, VICON_VIEW3D, x+10+buttonWidth-40, y-1, 19, 19,&md->mode, 0, 0, 1, 0, "Enable modifier during interactive display");
                        if (mti->flags&eModifierTypeFlag_SupportsEditmode) {
                uiButSetFunc(but, modifiers_moveDown, ob, md);
                
                uiBlockSetEmboss(block, UI_EMBOSSN);
 -
 -              but = uiDefIconBut(block, BUT, B_MODIFIER_RECALC, VICON_X, x+width-70+40, y, 16, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Delete modifier");
 -              uiButSetFunc(but, modifiers_del, ob, md);
 +              
 +              // deletion over the deflection panel
 +              if(md->type!=eModifierType_Collision)
 +              {
 +                      but = uiDefIconBut(block, BUT, B_MODIFIER_RECALC, VICON_X, x+width-70+40, y, 16, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Delete modifier");
 +                      uiButSetFunc(but, modifiers_del, ob, md);
 +              }
                uiBlockSetCol(block, TH_AUTO);
        }
  
                                height += 20;
                } else if (md->type==eModifierType_Softbody) {
                        height = 31;
 +              } else if (md->type==eModifierType_Cloth) {
 +                      height = 26;
 +              } else if (md->type==eModifierType_Collision) {
 +                      height = 19;
                } else if (md->type==eModifierType_Boolean) {
                        height = 48;
                } else if (md->type==eModifierType_Array) {
                } else if (md->type==eModifierType_Explode) {
                        height = 94;
                }
 -
                                                        /* roundbox 4 free variables: corner-rounding, nop, roundbox type, shade */
                uiDefBut(block, ROUNDBOX, 0, "", x-10, y-height-2, width, height-2, NULL, 5.0, 0.0, 12, 40, ""); 
  
                y -= 18;
  
 -              if (!isVirtual) {
 +              if (!isVirtual && (md->type!=eModifierType_Collision)) {
                        uiBlockBeginAlign(block);
                        if (md->type==eModifierType_ParticleSystem) {
                                but = uiDefBut(block, BUT, B_MODIFIER_RECALC, "Convert",        lx,(cy-=19),60,19, 0, 0, 0, 0, 0, "Convert the current particles to a mesh object");
                                uiButSetFunc(but, modifiers_applyModifier, ob, md);
                        }
                        
 -                      if (md->type!=eModifierType_Softbody && md->type!=eModifierType_ParticleSystem) {
 +                      if (md->type!=eModifierType_Softbody && md->type!=eModifierType_ParticleSystem && (md->type!=eModifierType_Cloth)) {
                                but = uiDefBut(block, BUT, B_MODIFIER_RECALC, "Copy",   lx,(cy-=19),60,19, 0, 0, 0, 0, 0, "Duplicate the current modifier at the same position in the stack");
                                uiButSetFunc(but, modifiers_copyModifier, ob, md);
                        }
@@@ -3625,9 -3616,6 +3625,9 @@@ void do_latticebuts(unsigned short even
                        if(ob==G.obedit) resizelattice(editLatt, lt->opntsu, lt->opntsv, lt->opntsw, NULL);
                        else resizelattice(ob->data, lt->opntsu, lt->opntsv, lt->opntsw, NULL);
                        ob->softflag |= OB_SB_REDO;
 +                      if(modifiers_isClothEnabled(ob)) {
 +                              cloth_free_modifier(modifiers_isClothEnabled(ob));
 +                      }
                        DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
                        allqueue(REDRAWVIEW3D, 0);
                }
                        lt = ob->data;
                        resizelattice(ob->data, lt->opntsu, lt->opntsv, lt->opntsw, ob);
                        ob->softflag |= OB_SB_REDO;
 +                      if(modifiers_isClothEnabled(ob)) {
 +                              cloth_free_modifier(modifiers_isClothEnabled(ob));
 +                      }
                        DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
                        allqueue(REDRAWVIEW3D, 0);
                }
@@@ -5083,7 -5068,7 +5083,7 @@@ static void editing_panel_links(Object 
                        
                        xco= 143;
                        
-                       uiDefBut(block, LABEL,0, "Action (PoseLib):", xco, 154, 130,20, 0, 0, 0, 0, 0, "");
+                       uiDefBut(block, LABEL,0, "Pose Library (Action):", xco, 154, 200, 20, 0, 0, 0, 0, 0, "");
                        
                        /* PoseLib Action */
                        uiBlockSetCol(block, TH_BUT_SETTING2);
                                
                                uiBlockBeginAlign(block);
                                        /* currently 'active' pose */
-                                       uiDefButI(block, MENU, B_POSELIB_APPLYP, menustr, xco, 85,18,20, &act->active_marker, 1, count, 0, 0, "Browses Poses in PoseLib. Applies chosen pose.");
+                                       uiDefButI(block, MENU, B_POSELIB_APPLYP, menustr, xco, 85,18,20, &act->active_marker, 1, count, 0, 0, "Browses Poses in Pose Library. Applies chosen pose.");
                                        MEM_freeN(menustr);
                                        
                                        if (act->active_marker) {
-                                               uiDefBut(block, TEX, REDRAWBUTSEDIT,"",         xco+18,85,160-18-20,20, marker->name, 0, 63, 0, 0, "Displays current PoseLib Pose name. Click to change.");
-                                               uiDefIconBut(block, BUT, B_POSELIB_REMOVEP, VICON_X, xco+160-20, 85, 20, 20, NULL, 0.0, 0.0, 0.0, 0.0, "Remove this PoseLib Pose from PoseLib");
+                                               uiDefBut(block, TEX, REDRAWBUTSEDIT,"",         xco+18,85,160-18-20,20, marker->name, 0, 63, 0, 0, "Displays current Pose Library Pose name. Click to change.");
+                                               uiDefIconBut(block, BUT, B_POSELIB_REMOVEP, VICON_X, xco+160-20, 85, 20, 20, NULL, 0.0, 0.0, 0.0, 0.0, "Remove this Pose Library Pose from Pose Library.");
                                        }
                                        
                                        /* add new poses */
index 662e0df093b0b1bab3b816b6e2650d35fd977d36,bed9084a389dc4a9513c08e1977840454a3d290a..3883db39c74a3ead1618f0d1762e1440f83ad0e7
@@@ -47,7 -47,6 +47,7 @@@
  #include "DNA_scene_types.h"
  
  #include "BKE_action.h"
 +#include "BKE_cloth.h"
  #include "BKE_global.h"
  #include "BKE_main.h"
  #include "BKE_library.h"
@@@ -90,7 -89,6 +90,7 @@@
  #include "DNA_action_types.h"
  #include "DNA_armature_types.h"
  #include "DNA_camera_types.h"
 +#include "DNA_cloth_types.h"
  #include "DNA_constraint_types.h"
  #include "DNA_curve_types.h"
  #include "DNA_effect_types.h"
@@@ -192,15 -190,18 +192,18 @@@ static void constraint_active_func(voi
  
  static void add_constraint_to_active(Object *ob, bConstraint *con)
  {
-       ListBase *list;
+       ListBase *list= get_active_constraints(ob);
+       bPoseChannel *pchan= get_active_posechannel(ob);
        
-       list = get_active_constraints(ob);
        if (list) {
                unique_constraint_name(con, list);
                BLI_addtail(list, con);
                
+               if (proxylocked_constraints_owner(ob, pchan))
+                       con->flag |= CONSTRAINT_PROXY_LOCAL;
+               
                con->flag |= CONSTRAINT_ACTIVE;
-               for(con= con->prev; con; con= con->prev)
+               for (con= con->prev; con; con= con->prev)
                        con->flag &= ~CONSTRAINT_ACTIVE;
        }
  }
@@@ -211,8 -212,7 +214,7 @@@ static void get_constraint_ipo_context(
  {
        Object *ob= ob_v;
        
-       /* todo; check object if it has ob-level action ipo */
-       
+       /* todo: check object if it has ob-level action ipo */
        if (ob->flag & OB_POSEMODE) {
                bPoseChannel *pchan;
                
@@@ -505,12 -505,15 +507,15 @@@ static void draw_constraint_spaceselec
  static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, short *xco, short *yco)
  {
        Object *ob= OBACT;
+       bPoseChannel *pchan= get_active_posechannel(ob);
        bConstraintTypeInfo *cti;
        uiBut *but;
        char typestr[32];
        short height, width = 265;
+       short proxy_protected;
        int rb_col;
  
+       /* get constraint typeinfo */
        cti= constraint_get_typeinfo(con);
        if (cti == NULL) {
                /* exception for 'Null' constraint - it doesn't have constraint typeinfo! */
        else
                strcpy(typestr, cti->name);
                
+       /* determine whether constraint is proxy protected or not */
+       if (proxylocked_constraints_owner(ob, pchan)) {
+               proxy_protected= (con->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1;
+       }
+       else
+               proxy_protected= 0;
+               
        /* unless button has own callback, it adds this callback to button */
        uiBlockSetFunc(block, constraint_active_func, ob, con);
  
        /* open/close */
        uiDefIconButBitS(block, ICONTOG, CONSTRAINT_EXPAND, B_CONSTRAINT_TEST, ICON_DISCLOSURE_TRI_RIGHT, *xco-10, *yco, 20, 20, &con->flag, 0.0, 0.0, 0.0, 0.0, "Collapse/Expand Constraint");
        
-       /* up/down */
-       uiBlockBeginAlign(block);
-       uiBlockSetEmboss(block, UI_EMBOSS);
-       but = uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, VICON_MOVE_UP, *xco+width-50, *yco, 16, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Move constraint up in constraint stack");
-       uiButSetFunc(but, constraint_moveUp, ob, con);
-       
-       but = uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, VICON_MOVE_DOWN, *xco+width-50+18, *yco, 16, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Move constraint down in constraint stack");
-       uiButSetFunc(but, constraint_moveDown, ob, con);
-       uiBlockEndAlign(block);
-       
-       if (con->flag & CONSTRAINT_EXPAND) {
+       /* name */      
+       if ((con->flag & CONSTRAINT_EXPAND) && (proxy_protected==0)) {
                if (con->flag & CONSTRAINT_DISABLE)
                        uiBlockSetCol(block, TH_REDALERT);
                
  
        uiBlockSetCol(block, TH_AUTO);  
        
-       uiBlockSetEmboss(block, UI_EMBOSSN);
+       /* proxy-protected constraints cannot be edited, so hide up/down + close buttons */
+       if (proxy_protected) {
+               uiBlockSetEmboss(block, UI_EMBOSSN);
+               
+               /* draw a ghost icon (for proxy) and also a lock beside it, to show that constraint is "proxy locked" */
+               uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_GHOST, *xco+244, *yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Proxy Protected");
+               uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_LOCKED, *xco+262, *yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Proxy Protected");
+               
+               uiBlockSetEmboss(block, UI_EMBOSS);
+       }
+       else {
+               short prev_proxylock;
+               
+               /* Up/Down buttons: 
+                *      Proxy-constraints are not allowed to occur after local (non-proxy) constraints
+                *      as that poses problems when restoring them, so disable the "up" button where
+                *      it may cause this situation.
+                */
+               if (proxylocked_constraints_owner(ob, pchan)) {
+                       if (con->prev) {
+                               prev_proxylock= (con->prev->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1;
+                       }
+                       else
+                               prev_proxylock= 0;
+               }
+               else
+                       prev_proxylock= 0;
+                
+               uiBlockBeginAlign(block);
+                       uiBlockSetEmboss(block, UI_EMBOSS);
+                       
+                       if (prev_proxylock == 0) {
+                               but = uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, VICON_MOVE_UP, *xco+width-50, *yco, 16, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Move constraint up in constraint stack");
+                               uiButSetFunc(but, constraint_moveUp, ob, con);
+                       }
+                       
+                       but = uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, VICON_MOVE_DOWN, *xco+width-50+18, *yco, 16, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Move constraint down in constraint stack");
+                       uiButSetFunc(but, constraint_moveDown, ob, con);
+               uiBlockEndAlign(block);
+               
+               
+               /* Close 'button' - emboss calls here disable drawing of 'button' behind X */
+               uiBlockSetEmboss(block, UI_EMBOSSN);
+               
+                       but = uiDefIconBut(block, BUT, B_CONSTRAINT_CHANGETARGET, ICON_X, *xco+262, *yco, 19, 19, list, 0.0, 0.0, 0.0, 0.0, "Delete constraint");
+                       uiButSetFunc(but, del_constraint_func, ob, con);
+               
+               uiBlockSetEmboss(block, UI_EMBOSS);
+       }
+       
+       /* Set but-locks for protected settings (magic numbers are used here!) */
+       if (proxy_protected)
+               uiSetButLock(1, "Cannot edit Proxy-Protected Constraint");
        
-       but = uiDefIconBut(block, BUT, B_CONSTRAINT_CHANGETARGET, ICON_X, *xco+262, *yco, 19, 19, list, 0.0, 0.0, 0.0, 0.0, "Delete constraint");
-       uiButSetFunc(but, del_constraint_func, ob, con);
-       uiBlockSetEmboss(block, UI_EMBOSS);
        /* Draw constraint data */
        if ((con->flag & CONSTRAINT_EXPAND) == 0) {
                (*yco) -= 21;
                                                
                                                /* target label */
                                                sprintf(tarstr, "Target %02d:", tarnum);
-                                               uiDefBut(block, LABEL, B_CONSTRAINT_TEST, tarstr, *xco+45, *yco-(48+yoffset), 60, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
+                                               uiDefBut(block, LABEL, B_CONSTRAINT_TEST, tarstr, *xco+45, *yco-(48+yoffset), 80, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
                                                
                                                /* target space-selector - per target */
                                                if (is_armature_target(ct->tar)) {
                                /* Inverse options */
                                uiBlockBeginAlign(block);
                                        but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Set Offset", *xco, *yco-151, (width/2),18, NULL, 0, 24, 0, 0, "Calculate current Parent-Inverse Matrix (i.e. restore offset from parent)");
-                                       uiButSetFunc(but, childof_const_setinv, data, NULL);
+                                       uiButSetFunc(but, childof_const_setinv, con, NULL);
                                        
                                        but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Clear Offset", *xco+((width/2)+10), *yco-151, (width/2),18, NULL, 0, 24, 0, 0, "Clear Parent-Inverse Matrix (i.e. clear offset from parent)");
-                                       uiButSetFunc(but, childof_const_clearinv, data, NULL);
+                                       uiButSetFunc(but, childof_const_clearinv, con, NULL);
                                uiBlockEndAlign(block);
                        }
                        break;
        else {
                (*yco)-=3;
        }
+       
+       /* clear any locks set up for proxies/lib-linking */
+       uiClearButLock();
  }
  
  static uiBlock *add_constraintmenu(void *arg_unused)
@@@ -2987,67 -3037,6 +3039,67 @@@ void do_effects_panels(unsigned short e
                }
                allqueue(REDRAWVIEW3D, 0);
                break;
 +      case B_CLOTH_CLEARCACHEALL:
 +      {
 +              ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
 +              if(clmd)
 +              {
 +                      CFRA= 1;
 +                      update_for_newframe_muted();
 +                      DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); 
 +                      cloth_clear_cache(ob, clmd, 2); 
 +                      allqueue(REDRAWBUTSOBJECT, 0);
 +                      allqueue(REDRAWVIEW3D, 0);
 +              }       
 +      }
 +      break;  
 +      case B_CLOTH_CLEARCACHEFRAME:
 +      {
 +              ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
 +              if(clmd)
 +              {
 +                      cloth_clear_cache(ob, clmd, MAX2(2.0,G.scene->r.cfra + 1.0));
 +                      allqueue(REDRAWBUTSOBJECT, 0);
 +              }
 +      }
 +      break;  
 +      case B_CLOTH_CHANGEPREROLL:
 +      {
 +              ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
 +              if(clmd)
 +              {
 +                      if(clmd->sim_parms.cache)
 +                      {
 +                              CFRA= 1;
 +                              update_for_newframe_muted();
 +                              DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); 
 +                              allqueue(REDRAWBUTSOBJECT, 0);
 +                              allqueue(REDRAWVIEW3D, 0);
 +                      }
 +              }
 +      }
 +      break;  
 +      case B_CLOTH_DEL_VG:
 +      {
 +              ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
 +              if(clmd)
 +              {
 +                      clmd->sim_parms.vgroup_mass = 0;
 +                      do_object_panels(B_CLOTH_RENEW);
 +              }
 +              allqueue(REDRAWBUTSOBJECT, 0);
 +      }
 +      break;  
 +      case B_CLOTH_RENEW:
 +      {
 +              ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
 +              if(clmd)
 +              {
 +                      do_object_panels(B_CLOTH_CLEARCACHEALL);
 +                      cloth_free_modifier (clmd);
 +              }
 +      }
 +      break;
        default:
                if(event>=B_SELEFFECT && event<B_SELEFFECT+MAX_EFFECT) {
                        ob= OBACT;
@@@ -3084,31 -3073,10 +3136,31 @@@ static void field_testTexture(char *nam
        }
        *idpp = 0;
  }
 +
 +/* Panel for collision */
 +static void object_collision__enabletoggle ( void *ob_v, void *arg2 )
 +{
 +      Object *ob = ob_v;
 +      ModifierData *md = modifiers_findByType ( ob, eModifierType_Collision );
 +
 +      if ( !md )
 +      {
 +              md = modifier_new ( eModifierType_Collision );
 +              BLI_addhead ( &ob->modifiers, md );
 +      }
 +      else
 +      {
 +              BLI_remlink ( &ob->modifiers, md );
 +              modifier_free ( md );
 +              allqueue(REDRAWBUTSEDIT, 0);
 +      }
 +}
 +
  /* Panels for particle interaction settings */
  static void object_panel_deflection(Object *ob)
  {
        uiBlock *block;
 +      uiBut *but;
  
        block= uiNewBlock(&curarea->uiblocks, "object_panel_deflection", UI_EMBOSS, UI_HELV, curarea->win);
        if(uiNewPanel(curarea, block, "Deflection", "Physics", 0, 0, 318, 204)==0) return;
        if(ob->pd && ob->type==OB_MESH) {
                PartDeflect *pd= ob->pd;
                
 -              uiDefButBitS(block, TOG, 1, B_REDR, "Deflection",160,160,150,20, &pd->deflect, 0, 0, 0, 0, "Deflects particles based on collision");
 +              but = uiDefButBitS(block, TOG, 1, B_REDR, "Deflection",160,160,150,20, &pd->deflect, 0, 0, 0, 0, "Deflects particles based on collision");
 +              uiButSetFunc(but, object_collision__enabletoggle, ob, NULL);
 +              
                if(pd->deflect) {
                        uiDefBut(block, LABEL, 0, "Particles",                  160,140,75,20, NULL, 0.0, 0, 0, 0, "");
                        uiDefButBitS(block, TOG, PDEFLE_KILL_PART, B_DIFF, "Kill",235,140,75,20, &pd->flag, 0, 0, 0, 0, "Kill collided particles");
@@@ -4787,242 -4753,6 +4839,242 @@@ errMessage
  #endif // DISABLE_ELBEEM
  }
  
 +/* Panel for cloth */
 +static void object_cloth__enabletoggle(void *ob_v, void *arg2)
 +{
 +      Object *ob = ob_v;
 +      ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth);
 +
 +      if (!md) {
 +              md = modifier_new(eModifierType_Cloth);
 +              BLI_addhead(&ob->modifiers, md);
 +      }
 +      else {
 +              BLI_remlink(&ob->modifiers, md);
 +              modifier_free(md);
 +      }
 +
 +      allqueue(REDRAWBUTSEDIT, 0);
 +}
 +
 +static void object_panel_cloth(Object *ob)
 +{
 +      uiBlock *block;
 +      static int val, val2;
 +      uiBut *but;
 +      ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
 +      block= uiNewBlock(&curarea->uiblocks, "object_panel_cloth", UI_EMBOSS, UI_HELV, curarea->win);
 +      if(uiNewPanel(curarea, block, "Cloth", "Physics", 640, 0, 318, 204)==0) return;
 +
 +      if(ob->id.lib) uiSetButLock(1, "Can't edit library data");
 +      val = ((clmd)?(1):(0));
 +
 +      but = uiDefButI(block, TOG, REDRAWBUTSOBJECT, "Cloth Object",   10,200,130,20, &val, 0, 0, 0, 0, "Sets object to become cloth");
 +      uiButSetFunc(but, object_cloth__enabletoggle, ob, NULL);
 +      uiDefBut(block, LABEL, 0, "",10,10,300,0, NULL, 0.0, 0, 0, 0, ""); /* tell UI we go to 10,10*/
 +      
 +      if(clmd)
 +      {
 +              but = uiDefButBitI(block, TOG, CLOTH_SIMSETTINGS_FLAG_COLLOBJ, B_EFFECT_DEP, "Collision Object",        170,200,130,20, &clmd->sim_parms.flags, 0, 0, 0, 0, "Sets object to become a cloth collision object");
 +
 +              if (!(clmd->sim_parms.flags & CLOTH_SIMSETTINGS_FLAG_COLLOBJ))
 +              {
 +                      Cloth *cloth = clmd->clothObject;
 +                      int defCount;
 +                      char *clvg1, *clvg2;
 +                      char clmvg [] = "Mass Vertex Group%t|None%x0|";
 +      
 +                      val2=0;
 +      
 +      //              uiDefButBitI(block, TOG, CSIMSETT_FLAG_ADVANCED, REDRAWBUTSOBJECT, "Advanced",  180,200,130,20, &clmd->sim_parms.flags, 0, 0, 0, 0, "Enable advanced mode");
 +                      
 +                      /* GENERAL STUFF */
 +                      uiClearButLock();
 +                      uiBlockBeginAlign(block);
 +                      uiDefButF(block, NUM, B_CLOTH_RENEW, "StructStiff:",       10,170,150,20, &clmd->sim_parms.structural, 1.0, 10000.0, 100, 0, "Overall stiffness of structure");
 +                      uiDefButF(block, NUM, B_CLOTH_RENEW, "BendStiff:",         160,170,150,20, &clmd->sim_parms.bending, 0.0, 10000.0, 1000, 0, "Wrinkle possibility");
 +                      uiDefButI(block, NUM, B_CLOTH_RENEW, "Steps per Frame:",           10,150,150,20, &clmd->sim_parms.stepsPerFrame, 1.0, 100.0, 5, 0, "Quality of the simulation (higher=better=slower)");
 +                      uiBlockEndAlign(block);
 +                      uiBlockBeginAlign(block);
 +                      uiDefButF(block, NUM, B_CLOTH_RENEW, "Spring Damp:",       160,150,150,20, &clmd->sim_parms.Cdis, 0.0, 10.0, 10, 0, "Spring damping");
 +                      uiDefButF(block, NUM, B_DIFF, "Air Damp:",         10,130,150,20, &clmd->sim_parms.Cvi, 0.0, 10.0, 10, 0, "Apply gravitation to point movement");
 +                      uiBlockEndAlign(block);                 
 +                      
 +                      uiClearButLock();
 +                      
 +                      uiBlockBeginAlign(block);
 +                      uiDefBut(block, LABEL, 0, "Gravity:",  10,100,60,20, NULL, 0.0, 0, 0, 0, "");
 +                      // uiClearButLock();
 +                      
 +                      uiDefButF(block, NUM, B_CLOTH_RENEW, "X:",         70,100,80,20, &clmd->sim_parms.gravity[0], -100.0, 100.0, 10, 0, "Apply gravitation to point movement");
 +                      uiDefButF(block, NUM, B_CLOTH_RENEW, "Y:",         150,100,80,20, &clmd->sim_parms.gravity[1], -100.0, 100.0, 10, 0, "Apply gravitation to point movement");
 +                      uiDefButF(block, NUM, B_CLOTH_RENEW, "Z:",         230,100,80,20, &clmd->sim_parms.gravity[2], -100.0, 100.0, 10, 0, "Apply gravitation to point movement");
 +                      uiBlockEndAlign(block);
 +                      
 +                      /* GOAL STUFF */
 +                      uiBlockBeginAlign(block);
 +                      uiDefButBitI(block, TOG, CLOTH_SIMSETTINGS_FLAG_GOAL, REDRAWVIEW3D, "Use Goal", 10,70,130,20, &clmd->sim_parms.flags, 0, 0, 0, 0, "Define forces for vertices to stick to animated position");
 +                      if (clmd->sim_parms.flags & CLOTH_SIMSETTINGS_FLAG_GOAL)
 +                      {
 +                              if(ob->type==OB_MESH) 
 +                              {
 +                                      
 +                                      defCount = sizeof (clmvg);
 +                                      clvg1 = get_vertexgroup_menustr (ob);
 +                                      clvg2 = MEM_callocN (strlen (clvg1) + 1 + defCount, "clothVgMS");
 +                                      if (! clvg2) {
 +                                              printf ("draw_modifier: error allocating memory for cloth vertex group menu string.\n");
 +                                              return;
 +                                      }
 +                                      defCount = BLI_countlist (&ob->defbase);
 +                                      if (defCount == 0) 
 +                                      {
 +                                              clmd->sim_parms.vgroup_mass = 0;
 +                                      }
 +                                      sprintf (clvg2, "%s%s", clmvg, clvg1);
 +                                      
 +                                      uiDefButS(block, MENU, B_CLOTH_RENEW, clvg2,    140,70,20,20, &clmd->sim_parms.vgroup_mass, 0, defCount, 0, 0, "Browses available vertex groups");      
 +                                      MEM_freeN (clvg1);
 +                                      MEM_freeN (clvg2);
 +                                      
 +                                      if(clmd->sim_parms.vgroup_mass) 
 +                                      {
 +                                              bDeformGroup *defGroup = BLI_findlink(&ob->defbase, clmd->sim_parms.vgroup_mass-1);
 +                                              if(defGroup)
 +                                                      uiDefBut(block, BUT, B_DIFF, defGroup->name,    160,70,130,20, NULL, 0.0, 0.0, 0, 0, "Name of current vertex group");
 +                                              else
 +                                                      uiDefBut(block, BUT, B_DIFF, "(no group)",      160,70,130,20, NULL, 0.0, 0.0, 0, 0, "Vertex Group doesn't exist anymore");
 +                                              
 +                                              uiDefIconBut(block, BUT, B_CLOTH_DEL_VG, ICON_X, 290,70,20,20, 0, 0, 0, 0, 0, "Disable use of vertex group");
 +                                              
 +                                      }
 +                                      else
 +                                              uiDefButF(block, NUM, B_CLOTH_RENEW, "Goal:",   160,70,150,20, &clmd->sim_parms.defgoal, 0.0, 1.0, 10, 0, "Default Goal (vertex target position) value, when no Vertex Group used");
 +                              
 +                              }
 +                              else 
 +                              {
 +                                      uiDefButS(block, TOG, B_CLOTH_RENEW, "W",                       140,70,20,20, &clmd->sim_parms.vgroup_mass, 0, 1, 0, 0, "Use control point weight values");
 +                                      uiDefButF(block, NUM, B_CLOTH_RENEW, "Goal:",   160,70,150,20, &clmd->sim_parms.defgoal, 0.0, 1.0, 10, 0, "Default Goal (vertex target position) value, when no Vertex Group used");
 +                              }
 +                              
 +                              uiDefButF(block, NUM, B_CLOTH_RENEW, "G Stiff:",        10,50,150,20, &clmd->sim_parms.goalspring, 0.0, 500.0, 10, 0, "Goal (vertex target position) spring stiffness");
 +                              uiDefButF(block, NUM, B_CLOTH_RENEW, "G Damp:", 160,50,150,20, &clmd->sim_parms.goalfrict  , 0.0, 50.0, 10, 0, "Goal (vertex target position) friction");
 +                              uiDefButF(block, NUM, B_CLOTH_RENEW, "G Min:",          10,30,150,20, &clmd->sim_parms.mingoal, 0.0, 1.0, 10, 0, "Goal minimum, vertex group weights are scaled to match this range");
 +                              uiDefButF(block, NUM, B_CLOTH_RENEW, "G Max:",          160,30,150,20, &clmd->sim_parms.maxgoal, 0.0, 1.0, 10, 0, "Goal maximum, vertex group weights are scaled to match this range");
 +                      }
 +                      uiBlockEndAlign(block); 
 +                      
 +                      /*
 +                      // no tearing supported anymore since modifier stack restrictions 
 +                      uiBlockBeginAlign(block);
 +                      uiDefButBitI(block, TOG, CSIMSETT_FLAG_TEARING_ENABLED, B_EFFECT_DEP, "Tearing",        10,0,150,20, &clmd->sim_parms.flags, 0, 0, 0, 0, "Sets object to become a cloth collision object");
 +                      
 +                      if (clmd->sim_parms.flags & CSIMSETT_FLAG_TEARING_ENABLED)
 +                      {
 +                      uiDefButI(block, NUM, B_DIFF, "Max extent:",       160,0,150,20, &clmd->sim_parms.maxspringlen, 1.0, 1000.0, 10, 0, "Maximum extension before spring gets cut");
 +              }
 +                      
 +                      uiBlockEndAlign(block); 
 +                      */
 +              }
 +      }
 +}
 +
 +
 +static void object_panel_cloth_II(Object *ob)
 +{
 +      uiBlock *block;
 +      static int val;
 +      uiBut *but;
 +      ClothModifierData *clmd = NULL;
 +      
 +      clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
 +      if(clmd)
 +      {
 +              if (!(clmd->sim_parms.flags & CLOTH_SIMSETTINGS_FLAG_COLLOBJ))
 +              {
 +                      Cloth *cloth = clmd->clothObject;
 +                      char str[128];
 +                      
 +                      block= uiNewBlock(&curarea->uiblocks, "object_panel_cloth_II", UI_EMBOSS, UI_HELV, curarea->win);
 +                      uiNewPanelTabbed("Cloth", "Physics");
 +                      if(uiNewPanel(curarea, block, "Cloth Cache", "Physics", 651, 0, 318, 204)==0) return;
 +              
 +                      uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
 +                      
 +                      uiDefButI(block, NUM, B_DIFF, "First Frame:",           10,160,150,20, &clmd->sim_parms.firstframe, 0, MAXFRAME, 1, 0, "Frame on which the simulation starts");
 +                      uiDefButI(block, NUM, B_DIFF, "Last Frame:",            160,160,150,20, &clmd->sim_parms.lastframe, 0, MAXFRAME, 10, 0, "Frame on which the simulation stops");
 +
 +                      if(clmd->sim_parms.cache)
 +                      {
 +                              int length = BLI_linklist_length(clmd->sim_parms.cache);
 +                              
 +                              /* correct spelling if only 1 frame cacheed --> only gimmick  */
 +                              if(length-clmd->sim_parms.preroll>1)
 +                                      sprintf (str, "Frame 1 - %d cached. [%d in preroll, %d in total]", length-clmd->sim_parms.preroll, clmd->sim_parms.preroll, length);
 +                              else
 +                                      sprintf (str, "Frame %d cached. [%d in preroll, %d in total]", length-clmd->sim_parms.preroll, clmd->sim_parms.preroll, length);
 +                              
 +                              uiDefBut(block, LABEL, 0, str,  10,140,290,20, NULL, 0.0, 0, 0, 0, "");
 +                              uiDefBut(block, LABEL, 0, "Clear cache:",  10,120,290,20, NULL, 0.0, 0, 0, 0, "");
 +                              uiBlockBeginAlign (block);
 +                              uiDefBut(block, BUT, B_CLOTH_CLEARCACHEALL, "All", 10, 100,145,20, NULL, 0.0, 0.0, 0, 0, "Free cloth cache without preroll");
 +                              uiDefBut(block, BUT, B_CLOTH_CLEARCACHEFRAME, "From next frame", 155, 100,145,20, NULL, 0.0, 0.0, 0, 0, "Free cloth cache");    
 +                              if(length>1) // B_CLOTH_CHANGEPREROLL
 +                                      uiDefButI(block, NUM, B_CLOTH_CHANGEPREROLL, "Preroll:", 10,80,145,20, &clmd->sim_parms.preroll, 0, length-1, 1, 0, "Simulation starts on this frame"); 
 +                              else
 +                                      uiDefBut(block, LABEL, 0, " ",  10,80,145,20, NULL, 0.0, 0, 0, 0, "");
 +                      }
 +                      else
 +                      {
 +                              uiDefBut(block, LABEL, 0, "No frames cached.",  10,120,290,20, NULL, 0.0, 0, 0, 0, "");
 +                      }
 +                      uiDefButBitI(block, TOG, CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT, REDRAWVIEW3D, "Protect Cache",  10,50,145,20, &clmd->sim_parms.flags, 0, 0, 0, 0, "Protect cache from automatic freeing when scene changed");
 +                      uiBlockEndAlign(block);
 +              }
 +      }
 +      // uiBlockEndAlign(block);
 +}
 +
 +static void object_panel_cloth_III(Object *ob)
 +{
 +      uiBlock *block;
 +      static int val;
 +      uiBut *but;
 +      ClothModifierData *clmd = NULL;
 +      
 +      clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
 +      if(clmd)
 +      {
 +              if (!(clmd->sim_parms.flags & CLOTH_SIMSETTINGS_FLAG_COLLOBJ))
 +              {
 +                      Cloth *cloth = clmd->clothObject;
 +                      char str[128];
 +                      
 +                      block= uiNewBlock(&curarea->uiblocks, "object_panel_cloth_III", UI_EMBOSS, UI_HELV, curarea->win);
 +                      uiNewPanelTabbed("Cloth", "Physics");
 +                      if(uiNewPanel(curarea, block, "Cloth Collisions", "Physics", 651, 0, 318, 204)==0) return;
 +              
 +                      uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
 +                      
 +                      uiBlockBeginAlign(block);
 +                      uiDefButBitI(block, TOG, CLOTH_COLLISIONSETTINGS_FLAG_ENABLED, REDRAWVIEW3D, "Enable collisions",       10,70,130,20, &clmd->coll_parms.flags, 0, 0, 0, 0, "Enable collisions with this object");
 +                      if (clmd->coll_parms.flags & CLOTH_COLLISIONSETTINGS_FLAG_ENABLED)
 +                      {
 +                              // uiDefBut(block, LABEL, 0, "",10,10,300,20, NULL, 0.0, 0, 0, 0, ""); /* tell UI we go to 10,10*/
 +                              uiDefButF(block, NUM, B_CLOTH_RENEW, "Min Distance:",      10,30,150,20, &clmd->coll_parms.epsilon, 0.001f, 1.0, 0.01f, 0, "Minimum distance between collision objects before collision response takes in");
 +                              uiDefBut(block, LABEL, 0, "",160,30,150,20, NULL, 0.0, 0, 0, 0, "");
 +                      }
 +                      else
 +                              uiDefBut(block, LABEL, 0, "",140,10,170,20, NULL, 0.0, 0, 0, 0, "");
 +                      uiBlockEndAlign(block);
 +              }
 +      }
 +      // uiBlockEndAlign(block);
 +}
 +
 +
  void object_panels()
  {
        Object *ob;
@@@ -5051,9 -4781,6 +5103,9 @@@ void physics_panels(
                object_panel_fields(ob);
                object_softbodies(ob);
                object_softbodies_II(ob);
 +              object_panel_cloth(ob);
 +              object_panel_cloth_II(ob);
 +              object_panel_cloth_III(ob);
                object_panel_fluidsim(ob);
        }
  }
index 2c05daa189564e601a8e37a59d5bc9f56468bbe5,9e9fc5aa236051d07a2af540fa6c0418aab787eb..2274cc63980e790186408eb74ff879c4e9187f05
@@@ -244,6 -244,10 +244,10 @@@ static int key_inside_circle(short mco[
        short vertco[2];
  
        project_short(co,vertco);
+       
+       if (vertco[0]==IS_CLIPPED)
+               return 0;
+       
        dx=(float)(mco[0]-vertco[0]);
        dy=(float)(mco[1]-vertco[1]);
        dist=(float)sqrt((double)(dx*dx + dy*dy));
@@@ -261,6 -265,9 +265,9 @@@ static int key_inside_rect(rcti *rect, 
  
        project_short(co,vertco);
  
+       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;
@@@ -278,7 -285,10 +285,10 @@@ static int test_key_depth(float *co, bg
                        (GLint *)mats->viewport, &ux, &uy, &uz );
  
        project_short(co,wco);
+       
+       if (wco[0]==IS_CLIPPED)
+               return 0;
+       
        x=wco[0];
        y=wco[1];
  
@@@ -601,11 -611,11 +611,11 @@@ static void PE_mirror_particle(Object *
        edit= psys->edit;
        i= pa - psys->particles;
  
 +      if(!edit->mirror_cache)
 +              PE_update_mirror_cache(ob, psys);
 +
        /* find mirrored particle if needed */
        if(!mpa) {
 -              if(!edit->mirror_cache)
 -                      PE_update_mirror_cache(ob, psys);
 -
                mi= edit->mirror_cache[i];
                if(mi == -1)
                        return;
@@@ -1453,7 -1463,7 +1463,7 @@@ void PE_do_lasso_select(short mcords[][
                                VECCOPY(co, key->co);
                                Mat4MulVecfl(mat, co);
                                project_short(co,vertco);
-                               if(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;
                                                pa->flag |= PARS_EDIT_RECALC;
                        VECCOPY(co, key->co);
                        Mat4MulVecfl(mat, co);
                        project_short(co,vertco);
-                       if(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;
                                        pa->flag |= PARS_EDIT_RECALC;
@@@ -2018,7 -2028,7 +2028,7 @@@ static void brush_cut(ParticleSystem *p
  
        cut=0;
  
-       project_short(key->co, vertco);
+       project_short_noclip(key->co, vertco);
        x0 = (float)vertco[0];
        x1 = (float)vertco[1];
  
        else {
                /* calculate path time closest to root that was inside the circle */
                for(k=1, key++; k<=keys; k++, key++){
-                       project_short(key->co, vertco);
+                       project_short_noclip(key->co, vertco);
  
                        v0 = (float)vertco[0] - x0;
                        v1 = (float)vertco[1] - x1;
index 83bac0e257ccbfd33d83b2b517ddbb1db2f57fc0,2a803d84fe7460d1a12e8fbfa7c59438646d64ff..6e5f808c4904d39fecaf137f18f7b6db5ded1d78
@@@ -77,7 -77,6 +77,7 @@@
  #include "BKE_action.h"
  #include "BKE_armature.h"
  #include "BKE_blender.h"
 +#include "BKE_cloth.h"
  #include "BKE_curve.h"
  #include "BKE_constraint.h"
  #include "BKE_depsgraph.h"
@@@ -788,10 -787,11 +788,11 @@@ static short pose_grab_with_ik_add(bPos
        if (pchan == NULL) 
                return 0;
        
-       /* rule: not if there's already an IK on this channel */
-       for (con= pchan->constraints.first; con; con= con->next)
+       /* Rule: not if there's already an IK on this channel */
+       for (con= pchan->constraints.first; con; con= con->next) {
                if (con->type==CONSTRAINT_TYPE_KINEMATIC)
                        break;
+       }
        
        if (con) {
                /* but, if this is a targetless IK, we make it auto anyway (for the children loop) */
        return 1;
  }
  
- /* bone is a canditate to get IK, but we don't do it if it has children connected */
+ /* bone is a candidate to get IK, but we don't do it if it has children connected */
  static short pose_grab_with_ik_children(bPose *pose, Bone *bone)
  {
        Bone *bonec;
  static short pose_grab_with_ik(Object *ob)
  {
        bArmature *arm;
-       bPoseChannel *pchan, *pchansel= NULL;
+       bPoseChannel *pchan, *parent;
        Bone *bonec;
+       short tot_ik= 0;
        
-       if (ob==NULL || ob->pose==NULL || (ob->flag & OB_POSEMODE)==0)
+       if ((ob==NULL) || (ob->pose==NULL) || (ob->flag & OB_POSEMODE)==0)
                return 0;
                
        arm = ob->data;
        
-       /* rule: only one Bone */
+       /* Rule: allow multiple Bones (but they must be selected, and only one ik-solver per chain should get added) */
        for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
                if (pchan->bone->layer & arm->layer) {
                        if (pchan->bone->flag & BONE_SELECTED) {
-                               if (pchansel)
-                                       break;
-                               pchansel= pchan;
+                               /* Rule: no IK for solitatry (unconnected) bones */
+                               for (bonec=pchan->bone->childbase.first; bonec; bonec=bonec->next) {
+                                       if (bonec->flag & BONE_CONNECTED) {
+                                               break;
+                                       }
+                               }
+                               if ((pchan->bone->flag & BONE_CONNECTED)==0 && (bonec == NULL))
+                                       continue;
+                               
+                               /* rule: if selected Bone is not a root bone, it gets a temporal IK */
+                               if (pchan->parent) {
+                                       /* only adds if there's no IK yet (and no parent bone was selected) */
+                                       for (parent= pchan->parent; parent; parent= parent->parent) {
+                                               if (parent->bone->flag & BONE_SELECTED)
+                                                       break;
+                                       }
+                                       if (parent == NULL)
+                                               tot_ik += pose_grab_with_ik_add(pchan);
+                               }
+                               else {
+                                       /* rule: go over the children and add IK to the tips */
+                                       tot_ik += pose_grab_with_ik_children(ob->pose, pchan->bone);
+                               }
                        }
                }
        }
-       if (pchan || pchansel==NULL) return 0;
-       /* rule: no IK for solitary (unconnected) bone */
-       for (bonec=pchansel->bone->childbase.first; bonec; bonec=bonec->next) {
-               if (bonec->flag & BONE_CONNECTED) {
-                       break;
-               }
-       }
-       if ((pchansel->bone->flag & BONE_CONNECTED)==0 && (bonec == NULL)) return 0;
        
-       /* rule: if selected Bone is not a root bone, it gets a temporal IK */
-       if (pchansel->parent) {
-               /* only adds if there's no IK yet */
-               return pose_grab_with_ik_add(pchansel);
-       }
-       else {
-               /* rule: go over the children and add IK to the tips */
-               return pose_grab_with_ik_children(ob->pose, pchansel->bone);
-       }
+       return (tot_ik) ? 1 : 0;
  }     
  
  
@@@ -3322,17 -3326,13 +3327,17 @@@ void special_aftertrans_update(TransInf
        }
        else {
                base= FIRSTBASE;
 -              while (base) {  
 -                      
 +
 +              while (base) {                  
 +
                        if(base->flag & BA_DO_IPO) redrawipo= 1;
                        
                        ob= base->object;
                        
                        if (modifiers_isSoftbodyEnabled(ob)) ob->softflag |= OB_SB_REDO;
 +                      else if(modifiers_isClothEnabled(ob)) {
 +                              cloth_free_modifier(modifiers_isClothEnabled(ob));
 +                      }
                        
                        /* Set autokey if necessary */
                        if ((!cancelled) && (t->mode != TFM_DUMMY) && (base->flag & SELECT)) {