Merge with 2.5 -r 21619:21756.
[blender.git] / source / blender / editors / object / editconstraint.c
index 477d04a818b894ffe901bbf794a029ef85c2372f..437beda324bef9aa31b077b8e7e690d23b905ea6 100644 (file)
@@ -77,9 +77,6 @@
 #include "object_intern.h"
 
 /* XXX */
-static void BIF_undo_push() {}
-static void error() {}
-static int okee() {return 0;}
 static int pupmenu() {return 0;}
 
 /* -------------- Get Active Constraint Data ---------------------- */
@@ -203,8 +200,7 @@ bConstraint *add_new_constraint (short type)
        /* Set up a generic constraint datablock */
        con->type = type;
        con->flag |= CONSTRAINT_EXPAND;
-       con->enforce = 1.0F;
-       strcpy(con->name, "Const");
+       con->enforce = 1.0f;
        
        /* Load the data for it */
        cti = constraint_get_typeinfo(con);
@@ -214,7 +210,12 @@ bConstraint *add_new_constraint (short type)
                /* only constraints that change any settings need this */
                if (cti->new_data)
                        cti->new_data(con->data);
+                       
+               /* set the name based on the type of constraint */
+               strcpy(con->name, cti->name); 
        }
+       else
+               strcpy(con->name, "Const");
        
        return con;
 }
@@ -273,255 +274,6 @@ static void set_constraint_nth_target (bConstraint *con, Object *target, char su
        }
 }
 
-/* context: active object in posemode, active channel, optional selected channel */
-void add_constraint (Scene *scene, View3D *v3d, short only_IK)
-{
-       Object *ob= OBACT, *obsel=NULL;
-       bPoseChannel *pchanact=NULL, *pchansel=NULL;
-       bConstraint *con=NULL;
-       Base *base;
-       short nr;
-       
-       /* paranoia checks */
-       if ((ob==NULL) || (ob==scene->obedit)) 
-               return;
-
-       if ((ob->pose) && (ob->flag & OB_POSEMODE)) {
-               bArmature *arm= ob->data;
-               
-               /* find active channel */
-               pchanact= get_active_posechannel(ob);
-               if (pchanact==NULL) 
-                       return;
-               
-               /* find selected bone */
-               for (pchansel=ob->pose->chanbase.first; pchansel; pchansel=pchansel->next) {
-                       if (pchansel != pchanact) {
-                               if (pchansel->bone->flag & BONE_SELECTED)  {
-                                       if (pchansel->bone->layer & arm->layer)
-                                               break;
-                               }
-                       }
-               }
-       }
-       
-       /* find selected object */
-       for (base= FIRSTBASE; base; base= base->next) {
-               if ((TESTBASE(v3d, base)) && (base->object!=ob)) 
-                       obsel= base->object;
-       }
-       
-       /* the only_IK caller has checked for posemode! */
-       if (only_IK) {
-               for (con= pchanact->constraints.first; con; con= con->next) {
-                       if (con->type==CONSTRAINT_TYPE_KINEMATIC) break;
-               }
-               if (con) {
-                       error("Pose Channel already has IK");
-                       return;
-               }
-               
-               if (pchansel)
-                       nr= pupmenu("Add IK Constraint%t|To Active Bone%x10");
-               else if (obsel)
-                       nr= pupmenu("Add IK Constraint%t|To Active Object%x10");
-               else 
-                       nr= pupmenu("Add IK Constraint%t|To New Empty Object%x10|Without Target%x11");
-       }
-       else {
-               if (pchanact) {
-                       if (pchansel)
-                               nr= pupmenu("Add Constraint to Active Bone%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18");
-                       else if ((obsel) && (obsel->type==OB_CURVE))
-                               nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|Stretch To%x7|%l|Action%x16|Script%x18");
-                       else if ((obsel) && (obsel->type==OB_MESH))
-                               nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Shrinkwrap%x22|Stretch To%x7|%l|Action%x16|Script%x18");
-                       else if (obsel)
-                               nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18");
-                       else
-                               nr= pupmenu("Add Constraint to New Empty Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18");
-               }
-               else {
-                       if ((obsel) && (obsel->type==OB_CURVE))
-                               nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|%l|Action%x16|Script%x18");
-                       else if ((obsel) && (obsel->type==OB_MESH))
-                               nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Shrinkwrap%x22|%l|Action%x16|Script%x18");
-                       else if (obsel)
-                               nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|%l|Action%x16|Script%x18");
-                       else
-                               nr= pupmenu("Add Constraint to New Empty Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|%l|Action%x16|Script%x18");
-               }
-       }
-       
-       if (nr < 1) return;
-       
-       /* handle IK separate */
-       if (nr==10 || nr==11) {
-               /* ik - prevent weird chains... */
-               if (pchansel) {
-                       bPoseChannel *pchan= pchanact;
-                       while (pchan) {
-                               if (pchan==pchansel) break;
-                               pchan= pchan->parent;
-                       }
-                       if (pchan) {
-                               error("IK root cannot be linked to IK tip");
-                               return;
-                       }
-                       
-                       pchan= pchansel;
-                       while (pchan) {
-                               if (pchan==pchanact) break;
-                               pchan= pchan->parent;
-                       }
-                       if (pchan) {
-                               error("IK tip cannot be linked to IK root");
-                               return;
-                       }               
-               }
-               
-               con = add_new_constraint(CONSTRAINT_TYPE_KINEMATIC);
-               BLI_addtail(&pchanact->constraints, con);
-               unique_constraint_name(con, &pchanact->constraints);
-               pchanact->constflag |= PCHAN_HAS_IK;    /* for draw, but also for detecting while pose solving */
-               if (nr==11) 
-                       pchanact->constflag |= PCHAN_HAS_TARGET;
-               if (proxylocked_constraints_owner(ob, pchanact))
-                       con->flag |= CONSTRAINT_PROXY_LOCAL;
-       }
-       else {
-               /* normal constraints - add data */
-               if (nr==1) con = add_new_constraint(CONSTRAINT_TYPE_LOCLIKE);
-               else if (nr==2) con = add_new_constraint(CONSTRAINT_TYPE_ROTLIKE);
-               else if (nr==3) con = add_new_constraint(CONSTRAINT_TYPE_TRACKTO);
-               else if (nr==4) con = add_new_constraint(CONSTRAINT_TYPE_MINMAX);
-               else if (nr==5) con = add_new_constraint(CONSTRAINT_TYPE_LOCKTRACK);
-               else if (nr==6) {
-                       Curve *cu= obsel->data;
-                       cu->flag |= CU_PATH;
-                       con = add_new_constraint(CONSTRAINT_TYPE_FOLLOWPATH);
-               }
-               else if (nr==7) con = add_new_constraint(CONSTRAINT_TYPE_STRETCHTO);
-               else if (nr==8) con = add_new_constraint(CONSTRAINT_TYPE_SIZELIKE);
-               else if (nr==13) con = add_new_constraint(CONSTRAINT_TYPE_LOCLIMIT);
-               else if (nr==14) con = add_new_constraint(CONSTRAINT_TYPE_ROTLIMIT);
-               else if (nr==15) con = add_new_constraint(CONSTRAINT_TYPE_SIZELIMIT);
-               else if (nr==16) {
-                       /* TODO: add a popup-menu to display list of available actions to use (like for pyconstraints) */
-                       con = add_new_constraint(CONSTRAINT_TYPE_ACTION);
-               }
-               else if (nr==17) {
-                       Curve *cu= obsel->data;
-                       cu->flag |= CU_PATH;
-                       con = add_new_constraint(CONSTRAINT_TYPE_CLAMPTO);
-               }
-               else if (nr==18) {      
-                       char *menustr;
-                       int scriptint= 0;
-#ifndef DISABLE_PYTHON
-                       /* popup a list of usable scripts */
-                       menustr = buildmenu_pyconstraints(NULL, &scriptint);
-                       scriptint = pupmenu(menustr);
-                       MEM_freeN(menustr);
-                       
-                       /* only add constraint if a script was chosen */
-                       if (scriptint) {
-                               /* add constraint */
-                               con = add_new_constraint(CONSTRAINT_TYPE_PYTHON);
-                               validate_pyconstraint_cb(con->data, &scriptint);
-                               
-                               /* make sure target allowance is set correctly */
-                               BPY_pyconstraint_update(ob, con);
-                       }
-#endif
-               }
-               else if (nr==19) {
-                       con = add_new_constraint(CONSTRAINT_TYPE_CHILDOF);
-               
-                       /* if this constraint is being added to a posechannel, make sure
-                        * the constraint gets evaluated in pose-space
-                        */
-                       if (pchanact) {
-                               con->ownspace = CONSTRAINT_SPACE_POSE;
-                               con->flag |= CONSTRAINT_SPACEONCE;
-                       }
-               }
-               else if (nr==20) con = add_new_constraint(CONSTRAINT_TYPE_TRANSFORM);
-               else if (nr==21) con = add_new_constraint(CONSTRAINT_TYPE_DISTLIMIT);
-               else if (nr==22) con = add_new_constraint(CONSTRAINT_TYPE_SHRINKWRAP);
-               
-               if (con==NULL) return;  /* paranoia */
-               
-               if (pchanact) {
-                       BLI_addtail(&pchanact->constraints, con);
-                       unique_constraint_name(con, &pchanact->constraints);
-                       pchanact->constflag |= PCHAN_HAS_CONST; /* for draw */
-                       if (proxylocked_constraints_owner(ob, pchanact))
-                               con->flag |= CONSTRAINT_PROXY_LOCAL;
-               }
-               else {
-                       BLI_addtail(&ob->constraints, con);
-                       unique_constraint_name(con, &ob->constraints);
-                       if (proxylocked_constraints_owner(ob, NULL))
-                               con->flag |= CONSTRAINT_PROXY_LOCAL;
-               }
-       }
-       
-       /* set the target */
-       if (pchansel) {
-               set_constraint_nth_target(con, ob, pchansel->name, 0);
-       }
-       else if (obsel) {
-               set_constraint_nth_target(con, obsel, "", 0);
-       }
-       else if (ELEM4(nr, 11, 13, 14, 15)==0) {        /* add new empty as target */
-               Base *base= BASACT, *newbase;
-               Object *obt;
-               
-               obt= add_object(scene, OB_EMPTY);
-               /* set layers OK */
-               newbase= BASACT;
-               newbase->lay= base->lay;
-               obt->lay= newbase->lay;
-               
-               /* transform cent to global coords for loc */
-               if (pchanact) {
-                       if (only_IK)
-                               VecMat4MulVecfl(obt->loc, ob->obmat, pchanact->pose_tail);
-                       else
-                               VecMat4MulVecfl(obt->loc, ob->obmat, pchanact->pose_head);
-               }
-               else
-                       VECCOPY(obt->loc, ob->obmat[3]);
-               
-               set_constraint_nth_target(con, obt, "", 0);
-               
-               /* restore, add_object sets active */
-               BASACT= base;
-               base->flag |= SELECT;
-       }
-       
-       /* active flag */
-       con->flag |= CONSTRAINT_ACTIVE;
-       for (con= con->prev; con; con= con->prev)
-               con->flag &= ~CONSTRAINT_ACTIVE;
-
-       DAG_scene_sort(scene);          // sort order of objects
-       
-       if (pchanact) {
-               ob->pose->flag |= POSE_RECALC;  // sort pose channels
-               DAG_object_flush_update(scene, ob, OB_RECALC_DATA);     // and all its relations
-       }
-       else
-               DAG_object_flush_update(scene, ob, OB_RECALC_OB);       // and all its relations
-
-       if (only_IK)
-               BIF_undo_push("Add IK Constraint");
-       else
-               BIF_undo_push("Add Constraint");
-
-}
-
 /* ------------- Constraint Sanity Testing ------------------- */
 
 /* checks validity of object pointers, and NULLs,
@@ -1055,6 +807,7 @@ void OBJECT_OT_constraints_clear(wmOperatorType *ot)
 static short get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, short add)
 {
        Object *obact= CTX_data_active_object(C);
+       bPoseChannel *pchanact= get_active_posechannel(obact);
        short only_curve= 0, only_mesh= 0, only_ob= 0;
        short found= 0;
        
@@ -1078,21 +831,24 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
                        return 0;
                        
                /* restricted target-type constraints -------------- */
+               /* NOTE: for these, we cannot try to add a target object if no valid ones are found, since that doesn't work */
                        /* curve-based constraints - set the only_curve and only_ob flags */
                case CONSTRAINT_TYPE_TRACKTO:
                case CONSTRAINT_TYPE_CLAMPTO:
                case CONSTRAINT_TYPE_FOLLOWPATH:
                        only_curve= 1;
                        only_ob= 1;
+                       add= 0;
                        break;
                        
                        /* mesh only? */
                case CONSTRAINT_TYPE_SHRINKWRAP:
                        only_mesh= 1;
                        only_ob= 1;
+                       add= 0;
                        break;
                        
-                       /* object only */
+                       /* object only - add here is ok? */
                case CONSTRAINT_TYPE_RIGIDBODYJOINT:
                        only_ob= 1;
                        break;
@@ -1103,12 +859,14 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
                /* search in list of selected Pose-Channels for target */
                CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pchans) 
                {
-                       /* just use the first one that we encounter... */
-                       *tar_ob= obact;
-                       *tar_pchan= pchan;
-                       found= 1;
-                       
-                       break;
+                       /* just use the first one that we encounter, as long as it is not the active one */
+                       if (pchan != pchanact) {
+                               *tar_ob= obact;
+                               *tar_pchan= pchan;
+                               found= 1;
+                               
+                               break;
+                       }
                }
                CTX_DATA_END;
        }
@@ -1144,11 +902,13 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
        
        /* if still not found, add a new empty to act as a target (if allowed) */
        if ((found == 0) && (add)) {
-#if 0 // XXX old code to be fixed
-               Base *base= BASACT, *newbase;
+               Scene *scene= CTX_data_scene(C);
+               Base *base= BASACT, *newbase=NULL;
                Object *obt;
                
+               /* add new target object */
                obt= add_object(scene, OB_EMPTY);
+               
                /* set layers OK */
                newbase= BASACT;
                newbase->lay= base->lay;
@@ -1156,20 +916,24 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
                
                /* transform cent to global coords for loc */
                if (pchanact) {
-                       if (only_IK)
-                               VecMat4MulVecfl(obt->loc, ob->obmat, pchanact->pose_tail);
+                       /* since by default, IK targets the tip of the last bone, use the tip of the active PoseChannel 
+                        * if adding a target for an IK Constraint
+                        */
+                       if (con_type == CONSTRAINT_TYPE_KINEMATIC)
+                               VecMat4MulVecfl(obt->loc, obact->obmat, pchanact->pose_tail);
                        else
-                               VecMat4MulVecfl(obt->loc, ob->obmat, pchanact->pose_head);
+                               VecMat4MulVecfl(obt->loc, obact->obmat, pchanact->pose_head);
                }
                else
-                       VECCOPY(obt->loc, ob->obmat[3]);
-               
-               //set_constraint_nth_target(con, obt, "", 0);
+                       VECCOPY(obt->loc, obact->obmat[3]);
                
                /* restore, add_object sets active */
                BASACT= base;
                base->flag |= SELECT;
-#endif // XXX old code to be ported
+               
+               /* make our new target the new object */
+               *tar_ob= obt;
+               found= 1;
        }
        
        /* return whether there's any target */
@@ -1177,14 +941,24 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
 }
 
 /* used by add constraint operators to add the constraint required */
-static int constraint_add_exec(bContext *C, wmOperator *op, ListBase *list)
+static int constraint_add_exec(bContext *C, wmOperator *op, Object *ob, ListBase *list, int type, short setTarget)
 {
        Scene *scene= CTX_data_scene(C);
-    Object *ob = CTX_data_active_object(C);
        bPoseChannel *pchan= get_active_posechannel(ob);
        bConstraint *con;
-       int type= RNA_enum_get(op->ptr, "type");
-       int setTarget= RNA_boolean_get(op->ptr, "set_targets");
+       
+       /* check if constraint to be added is valid for the given constraints stack */
+       if (type == CONSTRAINT_TYPE_NULL) {
+               return OPERATOR_CANCELLED;
+       }
+       if ( (type == CONSTRAINT_TYPE_RIGIDBODYJOINT) && (list != &ob->constraints) ) {
+               BKE_report(op->reports, RPT_ERROR, "Rigid Body Joint Constraint can only be added to Objects.");
+               return OPERATOR_CANCELLED;
+       }
+       if ( (type == CONSTRAINT_TYPE_KINEMATIC) && ((!pchan) || (list != &pchan->constraints)) ) {
+               BKE_report(op->reports, RPT_ERROR, "IK Constraint can only be added to Bones.");
+               return OPERATOR_CANCELLED;
+       }
        
        /* create a new constraint of the type requried, and add it to the active/given constraints list */
        con = add_new_constraint(type);
@@ -1295,91 +1069,64 @@ static int constraint_add_exec(bContext *C, wmOperator *op, ListBase *list)
 
 /* ------------------ */
 
-#if 0 // BUGGY
-/* for object cosntraints, don't include NULL or IK for now */
-static int object_constraint_add_invoke(bContext *C, wmOperator *op, wmEvent *evt)
-{
-       EnumPropertyItem *item;
-       uiPopupMenu *pup;
-       uiLayout *layout;
-       int i, totitem;
-       
-       pup= uiPupMenuBegin(C, "Add Constraint", 0);
-       layout= uiPupMenuLayout(pup);
-       
-       /* loop over the constraint-types as defined in the enum 
-        *      - code below is based on the code used for WM_menu_invoke()
-        */
-       totitem= sizeof(&constraint_type_items[0]) / sizeof(EnumPropertyItem);
-       item= constraint_type_items;
-        
-       for (i=0; i < totitem; i++) {
-               if (ELEM(item[i].value, CONSTRAINT_TYPE_NULL, CONSTRAINT_TYPE_KINEMATIC) == 0) {
-                       if (item[i].identifier[0])
-                               uiItemEnumO(layout, (char*)item[i].name, item[i].icon, "OBJECT_OT_constraint_add", "type", item[i].value);
-                       else
-                               uiItemS(layout);
-               }
-       }
-       
-       uiPupMenuEnd(C, pup);
-}
-#endif // BUGGY
-
 /* dummy operator callback */
 static int object_constraint_add_exec(bContext *C, wmOperator *op)
 {
-       Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
-
-       if (!ob)
-               return OPERATOR_CANCELLED;
-
-       return constraint_add_exec(C, op, &ob->constraints);
-}
-
-#if 0 // BUGGY
-/* for bone constraints, don't include NULL for now */
-static int pose_constraint_add_invoke(bContext *C, wmOperator *op, wmEvent *evt)
-{
-       EnumPropertyItem *item;
-       uiPopupMenu *pup;
-       uiLayout *layout;
-       int i, totitem;
+       ScrArea *sa= CTX_wm_area(C);
+       Object *ob;
+       int type= RNA_enum_get(op->ptr, "type");
+       short with_targets= 0;
        
-       pup= uiPupMenuBegin(C, "Add Constraint", 0);
-       layout= uiPupMenuLayout(pup);
+       /* get active object from context */
+       if (sa->spacetype == SPACE_BUTS)
+               ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+       else
+               ob= CTX_data_active_object(C);
        
-       /* loop over the constraint-types as defined in the enum 
-        *      - code below is based on the code used for WM_menu_invoke()
-        */
-       totitem= sizeof(&constraint_type_items[0]) / sizeof(EnumPropertyItem);
-       item= constraint_type_items;
-        
-       for (i=0; i < totitem; i++) {
-               // TODO: can add some other conditions here...
-               if (item[i].value != CONSTRAINT_TYPE_NULL) {
-                       if (item[i].identifier[0])
-                               uiItemEnumO(layout, (char*)item[i].name, item[i].icon, "POSE_OT_constraint_add", "type", item[i].value);
-                       else
-                               uiItemS(layout);
-               }
+       if (!ob) {
+               BKE_report(op->reports, RPT_ERROR, "No active object to add constraint to.");
+               return OPERATOR_CANCELLED;
        }
-       
-       uiPupMenuEnd(C, pup);
+               
+       /* hack: set constraint targets from selected objects in context is allowed when
+        *              operator name included 'with_targets', since the menu doesn't allow multiple properties
+        */
+       if (strstr(op->idname, "with_targets"))
+               with_targets= 1;
+
+       return constraint_add_exec(C, op, ob, &ob->constraints, type, with_targets);
 }
-#endif // BUGGY
 
 /* dummy operator callback */
 static int pose_constraint_add_exec(bContext *C, wmOperator *op)
 {
-       Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
-
-       if (!ob)
+       ScrArea *sa= CTX_wm_area(C);
+       Object *ob;
+       int type= RNA_enum_get(op->ptr, "type");
+       short with_targets= 0;
+       
+       /* get active object from context */
+       if (sa->spacetype == SPACE_BUTS)
+               ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+       else
+               ob= CTX_data_active_object(C);
+       
+       if (!ob) {
+               BKE_report(op->reports, RPT_ERROR, "No active object to add constraint to.");
                return OPERATOR_CANCELLED;
+       }
+               
+       /* hack: set constraint targets from selected objects in context is allowed when
+        *              operator name included 'with_targets', since the menu doesn't allow multiple properties
+        */
+       if (strstr(op->idname, "with_targets"))
+               with_targets= 1;
        
-       return constraint_add_exec(C, op, get_active_constraints(ob));
+       return constraint_add_exec(C, op, ob, get_active_constraints(ob), type, with_targets);
 }
 
+/* ------------------ */
+
 void OBJECT_OT_constraint_add(wmOperatorType *ot)
 {
        /* identifiers */
@@ -1388,7 +1135,26 @@ void OBJECT_OT_constraint_add(wmOperatorType *ot)
        ot->idname= "OBJECT_OT_constraint_add";
        
        /* api callbacks */
-       ot->invoke= WM_menu_invoke;//object_constraint_add_invoke;
+       ot->invoke= WM_menu_invoke;
+       ot->exec= object_constraint_add_exec;
+       ot->poll= ED_operator_object_active;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* properties */
+       RNA_def_enum(ot->srna, "type", constraint_type_items, 0, "Type", "");
+}
+
+void OBJECT_OT_constraint_add_with_targets(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Add Constraint (with Targets)";
+       ot->description = "Add a constraint to the active object, with target (where applicable) set to the selected Objects/Bones.";
+       ot->idname= "OBJECT_OT_constraint_add_with_targets";
+       
+       /* api callbacks */
+       ot->invoke= WM_menu_invoke;
        ot->exec= object_constraint_add_exec;
        ot->poll= ED_operator_object_active;
        
@@ -1397,7 +1163,6 @@ void OBJECT_OT_constraint_add(wmOperatorType *ot)
        
        /* properties */
        RNA_def_enum(ot->srna, "type", constraint_type_items, 0, "Type", "");
-       RNA_def_boolean(ot->srna, "set_targets", 0, "Set Targets", "Set target info for new constraints from context.");
 }
 
 void POSE_OT_constraint_add(wmOperatorType *ot)
@@ -1408,7 +1173,7 @@ void POSE_OT_constraint_add(wmOperatorType *ot)
        ot->idname= "POSE_OT_constraint_add";
        
        /* api callbacks */
-       ot->invoke= WM_menu_invoke; //pose_constraint_add_invoke;
+       ot->invoke= WM_menu_invoke;
        ot->exec= pose_constraint_add_exec;
        ot->poll= ED_operator_posemode;
        
@@ -1417,6 +1182,158 @@ void POSE_OT_constraint_add(wmOperatorType *ot)
        
        /* properties */
        RNA_def_enum(ot->srna, "type", constraint_type_items, 0, "Type", "");
-       RNA_def_boolean(ot->srna, "set_targets", 0, "Set Targets", "Set target info for new constraints from context.");
 }
 
+void POSE_OT_constraint_add_with_targets(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Add Constraint (with Targets)";
+       ot->description = "Add a constraint to the active bone, with target (where applicable) set to the selected Objects/Bones.";
+       ot->idname= "POSE_OT_constraint_add_with_targets";
+       
+       /* api callbacks */
+       ot->invoke= WM_menu_invoke;
+       ot->exec= pose_constraint_add_exec;
+       ot->poll= ED_operator_posemode;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* properties */
+       RNA_def_enum(ot->srna, "type", constraint_type_items, 0, "Type", "");
+}
+
+/************************ IK Constraint operators *********************/
+/* NOTE: only for Pose-Channels */
+// TODO: should these be here, or back in editors/armature/poseobject.c again?
+
+/* present menu with options + validation for targets to use */
+static int pose_ik_add_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+{
+       Object *ob= CTX_data_active_object(C);
+       bPoseChannel *pchan= get_active_posechannel(ob);
+       bConstraint *con= NULL;
+       
+       uiPopupMenu *pup;
+       uiLayout *layout;
+       Object *tar_ob= NULL;
+       bPoseChannel *tar_pchan= NULL;
+       
+       /* must have active bone */
+       if (ELEM(NULL, ob, pchan)) {
+               BKE_report(op->reports, RPT_ERROR, "Must have active bone to add IK Constraint to.");
+               return OPERATOR_CANCELLED;
+       }
+       
+       /* bone must not have any constraints already */
+       for (con= pchan->constraints.first; con; con= con->next) {
+               if (con->type==CONSTRAINT_TYPE_KINEMATIC) break;
+       }
+       if (con) {
+               BKE_report(op->reports, RPT_ERROR, "Bone already has IK Constraint.");
+               return OPERATOR_CANCELLED;
+       }
+       
+       /* prepare popup menu to choose targetting options */
+       pup= uiPupMenuBegin(C, "Add IK", 0);
+       layout= uiPupMenuLayout(pup);
+       
+       /* the type of targets we'll set determines the menu entries to show... */
+       if (get_new_constraint_target(C, CONSTRAINT_TYPE_KINEMATIC, &tar_ob, &tar_pchan, 0)) {
+               /* bone target, or object target? 
+                *      - the only thing that matters is that we want a target...
+                */
+               if (tar_pchan)
+                       uiItemBooleanO(layout, "To Active Bone", 0, "POSE_OT_ik_add", "with_targets", 1);
+               else
+                       uiItemBooleanO(layout, "To Active Object", 0, "POSE_OT_ik_add", "with_targets", 1);
+       }
+       else {
+               /* we have a choice of adding to a new empty, or not setting any target (targetless IK) */
+               uiItemBooleanO(layout, "To New Empty Object", 0, "POSE_OT_ik_add", "with_targets", 1);
+               uiItemBooleanO(layout, "Without Targets", 0, "POSE_OT_ik_add", "with_targets", 0);
+       }
+       
+       /* finish building the menu, and process it (should result in calling self again) */
+       uiPupMenuEnd(C, pup);
+       
+       return OPERATOR_CANCELLED;
+}
+
+/* call constraint_add_exec() to add the IK constraint */
+static int pose_ik_add_exec(bContext *C, wmOperator *op)
+{
+       Object *ob= CTX_data_active_object(C);
+       int with_targets= RNA_boolean_get(op->ptr, "with_targets");
+       
+       /* add the constraint - all necessary checks should have been done by the invoke() callback already... */
+       return constraint_add_exec(C, op, ob, get_active_constraints(ob), CONSTRAINT_TYPE_KINEMATIC, with_targets);
+}
+
+void POSE_OT_ik_add(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Add IK to Bone";
+       ot->description= "Add IK Constraint to the active Bone.";
+       ot->idname= "POSE_OT_ik_add";
+       
+       /* api callbacks */
+       ot->invoke= pose_ik_add_invoke;
+       ot->exec= pose_ik_add_exec;
+       ot->poll= ED_operator_posemode;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* properties */
+       RNA_def_boolean(ot->srna, "with_targets", 1, "With Targets", "Assign IK Constraint with targets derived from the select bones/objects");
+}
+
+/* ------------------ */
+
+/* remove IK constraints from selected bones */
+static int pose_ik_clear_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene = CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       
+       /* only remove IK Constraints */
+       CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pchans) 
+       {
+               bConstraint *con, *next;
+               
+               // TODO: should we be checking if these contraints were local before we try and remove them?
+               for (con= pchan->constraints.first; con; con= next) {
+                       next= con->next;
+                       if (con->type==CONSTRAINT_TYPE_KINEMATIC) {
+                               free_constraint_data(con);
+                               BLI_freelinkN(&pchan->constraints, con);
+                       }
+               }
+               pchan->constflag &= ~(PCHAN_HAS_IK|PCHAN_HAS_TARGET);
+       }
+       CTX_DATA_END;
+       
+       /* */
+       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+
+       /* note, notifier might evolve */
+       WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT|NA_REMOVED, ob);
+       
+       return OPERATOR_FINISHED;
+}
+
+void POSE_OT_ik_clear(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Remove IK";
+       ot->description= "Remove all IK Constraints from selected bones.";
+       ot->idname= "POSE_OT_ik_clear";
+       
+       /* api callbacks */
+       ot->exec= pose_ik_clear_exec;
+       ot->poll= ED_operator_posemode;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}