code cleanup: rename BKE_tessmesh -> BKE_editmesh, rename EditDerivedBMesh.tc ->...
[blender-staging.git] / source / blender / editors / object / object_relations.c
index 651f84f0f348425e88bb545b43acce0e10ac61ea..5a688d7daf388c5ce59a91627727c4ff5d85478c 100644 (file)
@@ -35,6 +35,7 @@
 #include "MEM_guardedalloc.h"
 
 #include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
 #include "DNA_mesh_types.h"
 #include "DNA_constraint_types.h"
 #include "DNA_group_types.h"
 #include "DNA_speaker_types.h"
 #include "DNA_world_types.h"
 #include "DNA_object_types.h"
+#include "DNA_vfont_types.h"
 
 #include "BLI_math.h"
 #include "BLI_listbase.h"
+#include "BLI_linklist.h"
 #include "BLI_string.h"
 #include "BLI_utildefines.h"
 
+#include "BLF_translation.h"
+
 #include "BKE_action.h"
 #include "BKE_animsys.h"
 #include "BKE_armature.h"
@@ -64,6 +69,7 @@
 #include "BKE_DerivedMesh.h"
 #include "BKE_displist.h"
 #include "BKE_global.h"
+#include "BKE_group.h"
 #include "BKE_fcurve.h"
 #include "BKE_lamp.h"
 #include "BKE_lattice.h"
@@ -79,7 +85,7 @@
 #include "BKE_scene.h"
 #include "BKE_speaker.h"
 #include "BKE_texture.h"
-#include "BKE_tessmesh.h"
+#include "BKE_editmesh.h"
 
 #include "WM_api.h"
 #include "WM_types.h"
@@ -133,6 +139,9 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
 
                em = me->edit_btmesh;
 
+               EDBM_mesh_normals_update(em);
+               BMEdit_RecalcTessellation(em);
+
                /* derivedMesh might be needed for solving parenting,
                 * so re-create it here */
                makeDerivedMesh(scene, obedit, em, CD_MASK_BAREMESH, 0);
@@ -206,7 +215,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
                }
        }
        
-       if (v4 || !((v1 && v2 == 0 && v3 == 0) || (v1 && v2 && v3)) ) {
+       if (v4 || !((v1 && v2 == 0 && v3 == 0) || (v1 && v2 && v3))) {
                BKE_report(op->reports, RPT_ERROR, "Select either 1 or 3 vertices to parent to");
                return OPERATOR_CANCELLED;
        }
@@ -214,7 +223,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
        CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
        {
                if (ob != obedit) {
-                       ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
+                       DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
                        par = obedit->parent;
                        
                        while (par) {
@@ -251,7 +260,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
        }
        CTX_DATA_END;
        
-       DAG_scene_sort(bmain, scene);
+       DAG_relations_tag_update(bmain);
 
        WM_event_add_notifier(C, NC_OBJECT, NULL);
 
@@ -277,7 +286,7 @@ void OBJECT_OT_vertex_parent_set(wmOperatorType *ot)
 /********************** Make Proxy Operator *************************/
 
 /* set the object to proxify */
-static int make_proxy_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+static int make_proxy_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 {
        Scene *scene = CTX_data_scene(C);
        Object *ob = ED_object_active_context(C);
@@ -290,12 +299,12 @@ static int make_proxy_invoke(bContext *C, wmOperator *op, wmEvent *evt)
        if (ob->dup_group && ob->dup_group->id.lib) {
                /* gives menu with list of objects in group */
                //proxy_group_objects_menu(C, op, ob, ob->dup_group);
-               WM_enum_search_invoke(C, op, evt);
+               WM_enum_search_invoke(C, op, event);
                return OPERATOR_CANCELLED;
 
        }
        else if (ob->id.lib) {
-               uiPopupMenu *pup = uiPupMenuBegin(C, "OK?", ICON_QUESTION);
+               uiPopupMenu *pup = uiPupMenuBegin(C, IFACE_("OK?"), ICON_QUESTION);
                uiLayout *layout = uiPupMenuLayout(pup);
                
                /* create operator menu item with relevant properties filled in */
@@ -348,14 +357,14 @@ static int make_proxy_exec(bContext *C, wmOperator *op)
                
                /* remove base, leave user count of object, it gets linked in BKE_object_make_proxy */
                if (gob == NULL) {
-                       BLI_remlink(&scene->base, oldbase);
+                       BKE_scene_base_unlink(scene, oldbase);
                        MEM_freeN(oldbase);
                }
                
                BKE_object_make_proxy(newob, ob, gob);
                
                /* depsgraph flushes are needed for the new data */
-               DAG_scene_sort(bmain, scene);
+               DAG_relations_tag_update(bmain);
                DAG_id_tag_update(&newob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
                WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, newob);
        }
@@ -417,37 +426,99 @@ void OBJECT_OT_proxy_make(wmOperatorType *ot)
 
 /********************** Clear Parent Operator ******************* */
 
+typedef enum eObClearParentTypes {
+       CLEAR_PARENT_ALL = 0,
+       CLEAR_PARENT_KEEP_TRANSFORM,
+       CLEAR_PARENT_INVERSE
+} eObClearParentTypes;
+
 EnumPropertyItem prop_clear_parent_types[] = {
-       {0, "CLEAR", 0, "Clear Parent", ""},
-       {1, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation", ""},
-       {2, "CLEAR_INVERSE", 0, "Clear Parent Inverse", ""},
+       {CLEAR_PARENT_ALL, "CLEAR", 0, "Clear Parent", ""},
+       {CLEAR_PARENT_KEEP_TRANSFORM, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation", ""},
+       {CLEAR_PARENT_INVERSE, "CLEAR_INVERSE", 0, "Clear Parent Inverse", ""},
        {0, NULL, 0, NULL, NULL}
 };
 
-void ED_object_parent_clear(Object *ob, int type)
+/* Helper for ED_object_parent_clear() - Remove deform-modifiers associated with parent */
+static void object_remove_parent_deform_modifiers(Object *ob, const Object *par)
 {
+       if (ELEM3(par->type, OB_ARMATURE, OB_LATTICE, OB_CURVE)) {
+               ModifierData *md, *mdn;
+               
+               /* assume that we only need to remove the first instance of matching deform modifier here */
+               for (md = ob->modifiers.first; md; md = mdn) {
+                       short free = FALSE;
+                       
+                       mdn = md->next;
+                       
+                       /* need to match types (modifier + parent) and references */
+                       if ((md->type == eModifierType_Armature) && (par->type == OB_ARMATURE)) {
+                               ArmatureModifierData *amd = (ArmatureModifierData *)md;
+                               if (amd->object == par) {
+                                       free = TRUE;
+                               }
+                       }
+                       else if ((md->type == eModifierType_Lattice) && (par->type == OB_LATTICE)) {
+                               LatticeModifierData *lmd = (LatticeModifierData *)md;
+                               if (lmd->object == par) {
+                                       free = TRUE;
+                               }
+                       }
+                       else if ((md->type == eModifierType_Curve) && (par->type == OB_CURVE)) {
+                               CurveModifierData *cmd = (CurveModifierData *)md;
+                               if (cmd->object == par) {
+                                       free = TRUE;
+                               }
+                       }
+                       
+                       /* free modifier if match */
+                       if (free) {
+                               BLI_remlink(&ob->modifiers, md);
+                               modifier_free(md);
+                       }
+               }
+       }
+}
 
+void ED_object_parent_clear(Object *ob, int type)
+{
        if (ob->parent == NULL)
                return;
+       
+       switch (type) {
+               case CLEAR_PARENT_ALL:
+               {
+                       /* for deformers, remove corresponding modifiers to prevent a large number of modifiers building up */
+                       object_remove_parent_deform_modifiers(ob, ob->parent);
+                       
+                       /* clear parenting relationship completely */
+                       ob->parent = NULL;
+               }
+               break;
                
-       if (type == 0) {
-               ob->parent = NULL;
-       }
-       else if (type == 1) {
-               ob->parent = NULL;
-               BKE_object_apply_mat4(ob, ob->obmat, TRUE, FALSE);
-       }
-       else if (type == 2)
-               unit_m4(ob->parentinv);
+               case CLEAR_PARENT_KEEP_TRANSFORM:
+               {
+                       /* remove parent, and apply the parented transform result as object's local transforms */
+                       ob->parent = NULL;
+                       BKE_object_apply_mat4(ob, ob->obmat, TRUE, FALSE);
+               }
+               break;
                
-       ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
+               case CLEAR_PARENT_INVERSE:
+               {
+                       /* object stays parented, but the parent inverse (i.e. offset from parent to retain binding state) is cleared */
+                       unit_m4(ob->parentinv);
+               }
+               break;
+       }
+       
+       DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
 }
 
 /* note, poll should check for editable scene */
 static int parent_clear_exec(bContext *C, wmOperator *op)
 {
        Main *bmain = CTX_data_main(C);
-       Scene *scene = CTX_data_scene(C);
        int type = RNA_enum_get(op->ptr, "type");
 
        CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
@@ -456,8 +527,7 @@ static int parent_clear_exec(bContext *C, wmOperator *op)
        }
        CTX_DATA_END;
 
-       DAG_scene_sort(bmain, scene);
-       DAG_ids_flush_update(bmain, 0);
+       DAG_relations_tag_update(bmain);
        WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
        WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
        return OPERATOR_FINISHED;
@@ -479,7 +549,7 @@ void OBJECT_OT_parent_clear(wmOperatorType *ot)
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
        
-       ot->prop = RNA_def_enum(ot->srna, "type", prop_clear_parent_types, 0, "Type", "");
+       ot->prop = RNA_def_enum(ot->srna, "type", prop_clear_parent_types, CLEAR_PARENT_ALL, "Type", "");
 }
 
 /* ******************** Make Parent Operator *********************** */
@@ -509,6 +579,7 @@ EnumPropertyItem prop_make_parent_types[] = {
        {PAR_ARMATURE_AUTO, "ARMATURE_AUTO", 0, "   With Automatic Weights", ""},
        {PAR_ARMATURE_ENVELOPE, "ARMATURE_ENVELOPE", 0, "   With Envelope Weights", ""},
        {PAR_BONE, "BONE", 0, "Bone", ""},
+       {PAR_BONE_RELATIVE, "BONE_RELATIVE", 0, "Bone Relative", ""},
        {PAR_CURVE, "CURVE", 0, "Curve Deform", ""},
        {PAR_FOLLOW, "FOLLOW", 0, "Follow Path", ""},
        {PAR_PATH_CONST, "PATH_CONST", 0, "Path Constraint", ""},
@@ -518,12 +589,13 @@ EnumPropertyItem prop_make_parent_types[] = {
        {0, NULL, 0, NULL, NULL}
 };
 
-int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object *ob, Object *par, int partype)
+int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object *ob, Object *par,
+                         int partype, int xmirror, int keep_transform)
 {
        bPoseChannel *pchan = NULL;
        int pararm = ELEM4(partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO);
        
-       par->recalc |= OB_RECALC_OB;
+       DAG_id_tag_update(&par->id, OB_RECALC_OB);
        
        /* preconditions */
        if (partype == PAR_FOLLOW || partype == PAR_PATH_CONST) {
@@ -536,8 +608,10 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
                                cu->flag |= CU_PATH | CU_FOLLOW;
                                BKE_displist_make_curveTypes(scene, par, 0);  /* force creation of path data */
                        }
-                       else cu->flag |= CU_FOLLOW;
-                       
+                       else {
+                               cu->flag |= CU_FOLLOW;
+                       }
+
                        /* if follow, add F-Curve for ctime (i.e. "eval_time") so that path-follow works */
                        if (partype == PAR_FOLLOW) {
                                /* get or create F-Curve */
@@ -552,13 +626,13 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
                        /* fall back on regular parenting now (for follow only) */
                        if (partype == PAR_FOLLOW)
                                partype = PAR_OBJECT;
-               }               
+               }
        }
-       else if (partype == PAR_BONE) {
+       else if (ELEM(partype, PAR_BONE, PAR_BONE_RELATIVE)) {
                pchan = BKE_pose_channel_active(par);
                
                if (pchan == NULL) {
-                       BKE_report(reports, RPT_ERROR, "No active Bone");
+                       BKE_report(reports, RPT_ERROR, "No active bone");
                        return 0;
                }
        }
@@ -570,10 +644,14 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
                }
                else {
                        Object workob;
-                       
+
                        /* apply transformation of previous parenting */
-                       /* BKE_object_apply_mat4(ob, ob->obmat); */ /* removed because of bug [#23577] */
-                       
+                       if (keep_transform) {
+                               /* was removed because of bug [#23577],
+                                * but this can be handy in some cases too [#32616], so make optional */
+                               BKE_object_apply_mat4(ob, ob->obmat, FALSE, FALSE);
+                       }
+
                        /* set the parent (except for follow-path constraint option) */
                        if (partype != PAR_PATH_CONST) {
                                ob->parent = par;
@@ -593,31 +671,54 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
                                 * NOTE: the old (2.4x) method was to set ob->partype = PARSKEL, creating the virtual modifiers
                                 */
                                ob->partype = PAROBJECT; /* note, dna define, not operator property */
-                               //ob->partype= PARSKEL; /* note, dna define, not operator property */
+                               //ob->partype = PARSKEL; /* note, dna define, not operator property */
                                
-                               /* BUT, to keep the deforms, we need a modifier, and then we need to set the object that it uses */
+                               /* BUT, to keep the deforms, we need a modifier, and then we need to set the object that it uses 
+                                * - We need to ensure that the modifier we're adding doesn't already exist, so we check this by
+                                *   assuming that the parent is selected too...
+                                */
                                // XXX currently this should only happen for meshes, curves, surfaces, and lattices - this stuff isn't available for metas yet
                                if (ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
                                        ModifierData *md;
                                        
                                        switch (partype) {
                                                case PAR_CURVE: /* curve deform */
-                                                       md = ED_object_modifier_add(reports, bmain, scene, ob, NULL, eModifierType_Curve);
-                                                       ((CurveModifierData *)md)->object = par;
+                                                       if ( modifiers_isDeformedByCurve(ob) != par) {
+                                                               md = ED_object_modifier_add(reports, bmain, scene, ob, NULL, eModifierType_Curve);
+                                                               if (md) {
+                                                                       ((CurveModifierData *)md)->object = par;
+                                                               }
+                                                       }
                                                        break;
                                                case PAR_LATTICE: /* lattice deform */
-                                                       md = ED_object_modifier_add(reports, bmain, scene, ob, NULL, eModifierType_Lattice);
-                                                       ((LatticeModifierData *)md)->object = par;
+                                                       if (modifiers_isDeformedByLattice(ob) != par) {
+                                                               md = ED_object_modifier_add(reports, bmain, scene, ob, NULL, eModifierType_Lattice);
+                                                               if (md) {
+                                                                       ((LatticeModifierData *)md)->object = par;
+                                                               }
+                                                       }
                                                        break;
                                                default: /* armature deform */
-                                                       md = ED_object_modifier_add(reports, bmain, scene, ob, NULL, eModifierType_Armature);
-                                                       ((ArmatureModifierData *)md)->object = par;
+                                                       if (modifiers_isDeformedByArmature(ob) != par) {
+                                                               md = ED_object_modifier_add(reports, bmain, scene, ob, NULL, eModifierType_Armature);
+                                                               if (md) {
+                                                                       ((ArmatureModifierData *)md)->object = par;
+                                                               }
+                                                       }
                                                        break;
                                        }
                                }
                        }
-                       else if (partype == PAR_BONE)
+                       else if (partype == PAR_BONE) {
                                ob->partype = PARBONE;  /* note, dna define, not operator property */
+                               if (pchan->bone)
+                                       pchan->bone->flag &= ~BONE_RELATIVE_PARENTING;
+                       }
+                       else if (partype == PAR_BONE_RELATIVE) {
+                               ob->partype = PARBONE;  /* note, dna define, not operator property */
+                               if (pchan->bone)
+                                       pchan->bone->flag |= BONE_RELATIVE_PARENTING;
+                       }
                        else
                                ob->partype = PAROBJECT;  /* note, dna define, not operator property */
                        
@@ -627,12 +728,12 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
                                bFollowPathConstraint *data;
                                float cmat[4][4], vec[3];
                                
-                               con = add_ob_constraint(ob, "AutoPath", CONSTRAINT_TYPE_FOLLOWPATH);
+                               con = BKE_add_ob_constraint(ob, "AutoPath", CONSTRAINT_TYPE_FOLLOWPATH);
                                
                                data = con->data;
                                data->tar = par;
                                
-                               get_constraint_target_matrix(scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra);
+                               BKE_get_constraint_target_matrix(scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra);
                                sub_v3_v3v3(vec, ob->obmat[3], cmat[3]);
                                
                                ob->loc[0] = vec[0];
@@ -641,12 +742,12 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
                        }
                        else if (pararm && ob->type == OB_MESH && par->type == OB_ARMATURE) {
                                if (partype == PAR_ARMATURE_NAME)
-                                       create_vgroups_from_armature(reports, scene, ob, par, ARM_GROUPS_NAME, 0);
+                                       create_vgroups_from_armature(reports, scene, ob, par, ARM_GROUPS_NAME, FALSE);
                                else if (partype == PAR_ARMATURE_ENVELOPE)
-                                       create_vgroups_from_armature(reports, scene, ob, par, ARM_GROUPS_ENVELOPE, 0);
+                                       create_vgroups_from_armature(reports, scene, ob, par, ARM_GROUPS_ENVELOPE, xmirror);
                                else if (partype == PAR_ARMATURE_AUTO) {
                                        WM_cursor_wait(1);
-                                       create_vgroups_from_armature(reports, scene, ob, par, ARM_GROUPS_AUTO, 0);
+                                       create_vgroups_from_armature(reports, scene, ob, par, ARM_GROUPS_AUTO, xmirror);
                                        WM_cursor_wait(0);
                                }
                                /* get corrected inverse */
@@ -661,7 +762,7 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
                                invert_m4_m4(ob->parentinv, workob.obmat);
                        }
                        
-                       ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA;
+                       DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
                }
        }
 
@@ -674,11 +775,13 @@ static int parent_set_exec(bContext *C, wmOperator *op)
        Scene *scene = CTX_data_scene(C);
        Object *par = ED_object_active_context(C);
        int partype = RNA_enum_get(op->ptr, "type");
+       int xmirror = RNA_boolean_get(op->ptr, "xmirror");
+       int keep_transform = RNA_boolean_get(op->ptr, "keep_transform");
        int ok = 1;
 
        CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
        {
-               if (!ED_object_parent_set(op->reports, bmain, scene, ob, par, partype)) {
+               if (!ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, xmirror, keep_transform)) {
                        ok = 0;
                        break;
                }
@@ -688,8 +791,7 @@ static int parent_set_exec(bContext *C, wmOperator *op)
        if (!ok)
                return OPERATOR_CANCELLED;
 
-       DAG_scene_sort(bmain, scene);
-       DAG_ids_flush_update(bmain, 0);
+       DAG_relations_tag_update(bmain);
        WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
        WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
 
@@ -697,30 +799,43 @@ static int parent_set_exec(bContext *C, wmOperator *op)
 }
 
 
-static int parent_set_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
+static int parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
 {
        Object *ob = ED_object_active_context(C);
-       uiPopupMenu *pup = uiPupMenuBegin(C, "Set Parent To", ICON_NONE);
+       uiPopupMenu *pup = uiPupMenuBegin(C, IFACE_("Set Parent To"), ICON_NONE);
        uiLayout *layout = uiPupMenuLayout(pup);
-       
-       uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
-       uiItemEnumO(layout, "OBJECT_OT_parent_set", NULL, 0, "type", PAR_OBJECT);
-       
+
+       wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_parent_set", TRUE);
+       PointerRNA opptr;
+
+#if 0
+       uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_OBJECT);
+#else
+       opptr = uiItemFullO_ptr(layout, ot, IFACE_("Object"), ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+       RNA_enum_set(&opptr, "type", PAR_OBJECT);
+       RNA_boolean_set(&opptr, "keep_transform", FALSE);
+
+       opptr = uiItemFullO_ptr(layout, ot, IFACE_("Object (Keep Transform)"), ICON_NONE, NULL, WM_OP_EXEC_DEFAULT,
+                               UI_ITEM_O_RETURN_PROPS);
+       RNA_enum_set(&opptr, "type", PAR_OBJECT);
+       RNA_boolean_set(&opptr, "keep_transform", TRUE);
+#endif
        /* ob becomes parent, make the associated menus */
        if (ob->type == OB_ARMATURE) {
-               uiItemEnumO(layout, "OBJECT_OT_parent_set", NULL, 0, "type", PAR_ARMATURE);
-               uiItemEnumO(layout, "OBJECT_OT_parent_set", NULL, 0, "type", PAR_ARMATURE_NAME);
-               uiItemEnumO(layout, "OBJECT_OT_parent_set", NULL, 0, "type", PAR_ARMATURE_ENVELOPE);
-               uiItemEnumO(layout, "OBJECT_OT_parent_set", NULL, 0, "type", PAR_ARMATURE_AUTO);
-               uiItemEnumO(layout, "OBJECT_OT_parent_set", NULL, 0, "type", PAR_BONE);
+               uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_ARMATURE);
+               uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_ARMATURE_NAME);
+               uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_ARMATURE_ENVELOPE);
+               uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_ARMATURE_AUTO);
+               uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_BONE);
+               uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_BONE_RELATIVE);
        }
        else if (ob->type == OB_CURVE) {
-               uiItemEnumO(layout, "OBJECT_OT_parent_set", NULL, 0, "type", PAR_CURVE);
-               uiItemEnumO(layout, "OBJECT_OT_parent_set", NULL, 0, "type", PAR_FOLLOW);
-               uiItemEnumO(layout, "OBJECT_OT_parent_set", NULL, 0, "type", PAR_PATH_CONST);
+               uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_CURVE);
+               uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_FOLLOW);
+               uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_PATH_CONST);
        }
        else if (ob->type == OB_LATTICE) {
-               uiItemEnumO(layout, "OBJECT_OT_parent_set", NULL, 0, "type", PAR_LATTICE);
+               uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_LATTICE);
        }
        
        uiPupMenuEnd(C, pup);
@@ -728,6 +843,33 @@ static int parent_set_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSE
        return OPERATOR_CANCELLED;
 }
 
+static bool parent_set_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop)
+{
+       const char *prop_id = RNA_property_identifier(prop);
+       int type = RNA_enum_get(ptr, "type");
+
+       /* Only show XMirror for PAR_ARMATURE_ENVELOPE and PAR_ARMATURE_AUTO! */
+       if (STREQ(prop_id, "xmirror")) {
+               if (ELEM(type, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO))
+                       return true;
+               else
+                       return false;
+       }
+
+       return true;
+}
+
+static void parent_set_ui(bContext *C, wmOperator *op)
+{
+       uiLayout *layout = op->layout;
+       wmWindowManager *wm = CTX_wm_manager(C);
+       PointerRNA ptr;
+
+       RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
+
+       /* Main auto-draw call. */
+       uiDefAutoButsRNA(layout, &ptr, parent_set_draw_check_prop, '\0');
+}
 
 void OBJECT_OT_parent_set(wmOperatorType *ot)
 {
@@ -739,13 +881,18 @@ void OBJECT_OT_parent_set(wmOperatorType *ot)
        /* api callbacks */
        ot->invoke = parent_set_invoke;
        ot->exec = parent_set_exec;
-       
        ot->poll = ED_operator_object_active;
+       ot->ui = parent_set_ui;
        
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
        
        RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", "");
+       RNA_def_boolean(ot->srna, "xmirror", FALSE, "X Mirror",
+                       "Apply weights symmetrically along X axis, for Envelope/Automatic vertex groups creation");
+       RNA_def_boolean(ot->srna, "keep_transform", FALSE, "Keep Transform",
+                       "Apply transformation before parenting");
+
 }
 
 /* ************ Make Parent Without Inverse Operator ******************* */
@@ -755,7 +902,7 @@ static int parent_noinv_set_exec(bContext *C, wmOperator *op)
        Main *bmain = CTX_data_main(C);
        Object *par = ED_object_active_context(C);
        
-       par->recalc |= OB_RECALC_OB;
+       DAG_id_tag_update(&par->id, OB_RECALC_OB);
        
        /* context iterator */
        CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
@@ -770,7 +917,7 @@ static int parent_noinv_set_exec(bContext *C, wmOperator *op)
                                memset(ob->loc, 0, 3 * sizeof(float));
                                
                                /* set recalc flags */
-                               ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA;
+                               DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
                                
                                /* set parenting type for object - object only... */
                                ob->parent = par;
@@ -780,8 +927,7 @@ static int parent_noinv_set_exec(bContext *C, wmOperator *op)
        }
        CTX_DATA_END;
        
-       DAG_scene_sort(bmain, CTX_data_scene(C));
-       DAG_ids_flush_update(bmain, 0);
+       DAG_relations_tag_update(bmain);
        WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
        
        return OPERATOR_FINISHED;
@@ -807,7 +953,6 @@ void OBJECT_OT_parent_no_inverse_set(wmOperatorType *ot)
 
 static int object_slow_parent_clear_exec(bContext *C, wmOperator *UNUSED(op))
 {
-       Main *bmain = CTX_data_main(C);
        Scene *scene = CTX_data_scene(C);
 
        CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
@@ -817,13 +962,12 @@ static int object_slow_parent_clear_exec(bContext *C, wmOperator *UNUSED(op))
                                ob->partype -= PARSLOW;
                                BKE_object_where_is_calc(scene, ob);
                                ob->partype |= PARSLOW;
-                               ob->recalc |= OB_RECALC_OB;
+                               DAG_id_tag_update(&ob->id, OB_RECALC_OB);
                        }
                }
        }
        CTX_DATA_END;
 
-       DAG_ids_flush_update(bmain, 0);
        WM_event_add_notifier(C, NC_SCENE, scene);
        
        return OPERATOR_FINISHED;
@@ -850,7 +994,6 @@ void OBJECT_OT_slow_parent_clear(wmOperatorType *ot)
 
 static int object_slow_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
 {
-       Main *bmain = CTX_data_main(C);
        Scene *scene = CTX_data_scene(C);
 
        CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
@@ -858,12 +1001,11 @@ static int object_slow_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
                if (ob->parent)
                        ob->partype |= PARSLOW;
 
-               ob->recalc |= OB_RECALC_OB;
+               DAG_id_tag_update(&ob->id, OB_RECALC_OB);
                
        }
        CTX_DATA_END;
 
-       DAG_ids_flush_update(bmain, 0);
        WM_event_add_notifier(C, NC_SCENE, scene);
        
        return OPERATOR_FINISHED;
@@ -898,11 +1040,10 @@ static EnumPropertyItem prop_clear_track_types[] = {
 static int object_track_clear_exec(bContext *C, wmOperator *op)
 {
        Main *bmain = CTX_data_main(C);
-       Scene *scene = CTX_data_scene(C);
        int type = RNA_enum_get(op->ptr, "type");
 
        if (CTX_data_edit_object(C)) {
-               BKE_report(op->reports, RPT_ERROR, "Operation cannot be performed in EditMode");
+               BKE_report(op->reports, RPT_ERROR, "Operation cannot be performed in edit mode");
                return OPERATOR_CANCELLED;
        }
        CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
@@ -911,13 +1052,13 @@ static int object_track_clear_exec(bContext *C, wmOperator *op)
                
                /* remove track-object for old track */
                ob->track = NULL;
-               ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
+               DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
                
                /* also remove all tracking constraints */
                for (con = ob->constraints.last; con; con = pcon) {
                        pcon = con->prev;
                        if (ELEM3(con->type, CONSTRAINT_TYPE_TRACKTO, CONSTRAINT_TYPE_LOCKTRACK, CONSTRAINT_TYPE_DAMPTRACK))
-                               remove_constraint(&ob->constraints, con);
+                               BKE_remove_constraint(&ob->constraints, con);
                }
                
                if (type == 1)
@@ -925,8 +1066,7 @@ static int object_track_clear_exec(bContext *C, wmOperator *op)
        }
        CTX_DATA_END;
 
-       DAG_ids_flush_update(bmain, 0);
-       DAG_scene_sort(bmain, scene);
+       DAG_relations_tag_update(bmain);
        WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
 
        return OPERATOR_FINISHED;
@@ -935,7 +1075,7 @@ static int object_track_clear_exec(bContext *C, wmOperator *op)
 void OBJECT_OT_track_clear(wmOperatorType *ot)
 {
        /* identifiers */
-       ot->name = "Clear track";
+       ot->name = "Clear Track";
        ot->description = "Clear tracking constraint or flag from object";
        ot->idname = "OBJECT_OT_track_clear";
        
@@ -963,7 +1103,6 @@ static EnumPropertyItem prop_make_track_types[] = {
 static int track_set_exec(bContext *C, wmOperator *op)
 {
        Main *bmain = CTX_data_main(C);
-       Scene *scene = CTX_data_scene(C);
        Object *obact = ED_object_active_context(C);
        
        int type = RNA_enum_get(op->ptr, "type");
@@ -975,11 +1114,11 @@ static int track_set_exec(bContext *C, wmOperator *op)
                CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
                {
                        if (ob != obact) {
-                               con = add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_DAMPTRACK);
+                               con = BKE_add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_DAMPTRACK);
 
                                data = con->data;
                                data->tar = obact;
-                               ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
+                               DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
                                
                                /* Lamp, Camera and Speaker track differently by default */
                                if (ob->type == OB_LAMP || ob->type == OB_CAMERA || ob->type == OB_SPEAKER)
@@ -995,11 +1134,11 @@ static int track_set_exec(bContext *C, wmOperator *op)
                CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
                {
                        if (ob != obact) {
-                               con = add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_TRACKTO);
+                               con = BKE_add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_TRACKTO);
 
                                data = con->data;
                                data->tar = obact;
-                               ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
+                               DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
                                
                                /* Lamp, Camera and Speaker track differently by default */
                                if (ob->type == OB_LAMP || ob->type == OB_CAMERA || ob->type == OB_SPEAKER) {
@@ -1017,11 +1156,11 @@ static int track_set_exec(bContext *C, wmOperator *op)
                CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
                {
                        if (ob != obact) {
-                               con = add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_LOCKTRACK);
+                               con = BKE_add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_LOCKTRACK);
 
                                data = con->data;
                                data->tar = obact;
-                               ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
+                               DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
                                
                                /* Lamp, Camera and Speaker track differently by default */
                                if (ob->type == OB_LAMP || ob->type == OB_CAMERA || ob->type == OB_SPEAKER) {
@@ -1033,8 +1172,7 @@ static int track_set_exec(bContext *C, wmOperator *op)
                CTX_DATA_END;
        }
        
-       DAG_scene_sort(bmain, scene);
-       DAG_ids_flush_update(bmain, 0);
+       DAG_relations_tag_update(bmain);
        WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
        
        return OPERATOR_FINISHED;
@@ -1091,7 +1229,7 @@ static unsigned int move_to_layer_init(bContext *C, wmOperator *op)
        return lay;
 }
 
-static int move_to_layer_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int move_to_layer_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 {
        View3D *v3d = CTX_wm_view3d(C);
        if (v3d && v3d->localvd) {
@@ -1126,7 +1264,7 @@ static int move_to_layer_exec(bContext *C, wmOperator *op)
                        base->object->lay = lay;
                        base->object->flag &= ~SELECT;
                        base->flag &= ~SELECT;
-                       /* if (base->object->type==OB_LAMP) is_lamp = TRUE; */
+                       /* if (base->object->type == OB_LAMP) is_lamp = TRUE; */
                }
                CTX_DATA_END;
        }
@@ -1139,7 +1277,7 @@ static int move_to_layer_exec(bContext *C, wmOperator *op)
                        local = base->lay & 0xFF000000;
                        base->lay = lay + local;
                        base->object->lay = lay;
-                       /* if (base->object->type==OB_LAMP) is_lamp = TRUE; */
+                       /* if (base->object->type == OB_LAMP) is_lamp = TRUE; */
                }
                CTX_DATA_END;
        }
@@ -1149,7 +1287,7 @@ static int move_to_layer_exec(bContext *C, wmOperator *op)
        WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, scene);
        WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
 
-       DAG_scene_sort(bmain, scene);
+       DAG_relations_tag_update(bmain);
 
        return OPERATOR_FINISHED;
 }
@@ -1212,21 +1350,20 @@ Base *ED_object_scene_link(Scene *scene, Object *ob)
 
 static int make_links_scene_exec(bContext *C, wmOperator *op)
 {
-       Main *bmain = CTX_data_main(C);
        Scene *scene_to = BLI_findlink(&CTX_data_main(C)->scene, RNA_enum_get(op->ptr, "scene"));
 
        if (scene_to == NULL) {
-               BKE_report(op->reports, RPT_ERROR, "Couldn't find scene");
+               BKE_report(op->reports, RPT_ERROR, "Could not find scene");
                return OPERATOR_CANCELLED;
        }
 
        if (scene_to == CTX_data_scene(C)) {
-               BKE_report(op->reports, RPT_ERROR, "Can't link objects into the same scene");
+               BKE_report(op->reports, RPT_ERROR, "Cannot link objects into the same scene");
                return OPERATOR_CANCELLED;
        }
 
        if (scene_to->id.lib) {
-               BKE_report(op->reports, RPT_ERROR, "Can't link objects into a linked scene");
+               BKE_report(op->reports, RPT_ERROR, "Cannot link objects into a linked scene");
                return OPERATOR_CANCELLED;
        }
 
@@ -1236,7 +1373,8 @@ static int make_links_scene_exec(bContext *C, wmOperator *op)
        }
        CTX_DATA_END;
 
-       DAG_ids_flush_update(bmain, 0);
+       /* redraw the 3D view because the object center points are colored differently */
+       WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
 
        /* one day multiple scenes will be visible, then we should have some update function for them */
        return OPERATOR_FINISHED;
@@ -1246,31 +1384,42 @@ enum {
        MAKE_LINKS_OBDATA = 1,
        MAKE_LINKS_MATERIALS,
        MAKE_LINKS_ANIMDATA,
+       MAKE_LINKS_GROUP,
        MAKE_LINKS_DUPLIGROUP,
-       MAKE_LINKS_MODIFIERS
+       MAKE_LINKS_MODIFIERS,
+       MAKE_LINKS_FONTS
 };
 
 /* Return 1 if make link data is allow, zero otherwise */
-static int allow_make_links_data(int ev, Object *ob, Object *obt)
+static int allow_make_links_data(const int type, Object *ob_src, Object *ob_dst)
 {
-       switch (ev) {
+       switch (type) {
                case MAKE_LINKS_OBDATA:
-                       if (ob->type == obt->type && ob->type != OB_EMPTY)
+                       if (ob_src->type == ob_dst->type && ob_src->type != OB_EMPTY)
                                return 1;
                        break;
                case MAKE_LINKS_MATERIALS:
-                       if (OB_TYPE_SUPPORT_MATERIAL(ob->type) &&
-                           OB_TYPE_SUPPORT_MATERIAL(obt->type))
+                       if (OB_TYPE_SUPPORT_MATERIAL(ob_src->type) &&
+                           OB_TYPE_SUPPORT_MATERIAL(ob_dst->type))
                        {
                                return 1;
                        }
                        break;
                case MAKE_LINKS_ANIMDATA:
+               case MAKE_LINKS_GROUP:
                case MAKE_LINKS_DUPLIGROUP:
                        return 1;
                case MAKE_LINKS_MODIFIERS:
-                       if (ob->type != OB_EMPTY && obt->type != OB_EMPTY)
+                       if (ob_src->type != OB_EMPTY && ob_dst->type != OB_EMPTY)
+                               return 1;
+                       break;
+               case MAKE_LINKS_FONTS:
+                       if ((ob_src->data != ob_dst->data) &&
+                           (ob_src->type == OB_FONT) &&
+                           (ob_dst->type == OB_FONT))
+                       {
                                return 1;
+                       }
                        break;
        }
        return 0;
@@ -1279,63 +1428,123 @@ static int allow_make_links_data(int ev, Object *ob, Object *obt)
 static int make_links_data_exec(bContext *C, wmOperator *op)
 {
        Main *bmain = CTX_data_main(C);
-       int event = RNA_enum_get(op->ptr, "type");
-       Object *ob;
+       Scene *scene = CTX_data_scene(C);
+       const int type = RNA_enum_get(op->ptr, "type");
+       Object *ob_src;
        ID *id;
        int a;
 
-       ob = ED_object_active_context(C);
+       /* group */
+       LinkNode *ob_groups = NULL;
+       int is_cycle = FALSE;
 
-       CTX_DATA_BEGIN (C, Object *, obt, selected_editable_objects)
+       ob_src = ED_object_active_context(C);
+
+       /* avoid searching all groups in source object each time */
+       if (type == MAKE_LINKS_GROUP) {
+               ob_groups = BKE_object_groups(ob_src);
+       }
+
+       CTX_DATA_BEGIN (C, Base *, base_dst, selected_editable_bases)
        {
-               if (ob != obt) {
-                       if (allow_make_links_data(event, ob, obt)) {
-                               switch (event) {
+               Object *ob_dst = base_dst->object;
+
+               if (ob_src != ob_dst) {
+                       if (allow_make_links_data(type, ob_src, ob_dst)) {
+                               switch (type) {
                                        case MAKE_LINKS_OBDATA: /* obdata */
-                                               id = obt->data;
+                                               id = ob_dst->data;
                                                id->us--;
 
-                                               id = ob->data;
+                                               id = ob_src->data;
                                                id_us_plus(id);
-                                               obt->data = id;
+                                               ob_dst->data = id;
 
                                                /* if amount of material indices changed: */
-                                               test_object_materials(obt->data);
+                                               test_object_materials(ob_dst->data);
 
-                                               obt->recalc |= OB_RECALC_DATA;
+                                               DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
                                                break;
                                        case MAKE_LINKS_MATERIALS:
                                                /* new approach, using functions from kernel */
-                                               for (a = 0; a < ob->totcol; a++) {
-                                                       Material *ma = give_current_material(ob, a + 1);
-                                                       assign_material(obt, ma, a + 1); /* also works with ma==NULL */
+                                               for (a = 0; a < ob_src->totcol; a++) {
+                                                       Material *ma = give_current_material(ob_src, a + 1);
+                                                       assign_material(ob_dst, ma, a + 1, BKE_MAT_ASSIGN_USERPREF); /* also works with ma==NULL */
                                                }
                                                break;
                                        case MAKE_LINKS_ANIMDATA:
-                                               BKE_copy_animdata_id((ID *)obt, (ID *)ob, FALSE);
-                                               BKE_copy_animdata_id((ID *)obt->data, (ID *)ob->data, FALSE);
+                                               BKE_copy_animdata_id((ID *)ob_dst, (ID *)ob_src, FALSE);
+                                               BKE_copy_animdata_id((ID *)ob_dst->data, (ID *)ob_src->data, FALSE);
                                                break;
+                                       case MAKE_LINKS_GROUP:
+                                       {
+                                               LinkNode *group_node;
+
+                                               /* first clear groups */
+                                               BKE_object_groups_clear(scene, base_dst, ob_dst);
+
+                                               /* now add in the groups from the link nodes */
+                                               for (group_node = ob_groups; group_node; group_node = group_node->next) {
+                                                       if (ob_dst->dup_group != group_node->link) {
+                                                               BKE_group_object_add(group_node->link, ob_dst, scene, base_dst);
+                                                       }
+                                                       else {
+                                                               is_cycle = TRUE;
+                                                       }
+                                               }
+                                       }
                                        case MAKE_LINKS_DUPLIGROUP:
-                                               obt->dup_group = ob->dup_group;
-                                               if (obt->dup_group) {
-                                                       id_lib_extern(&obt->dup_group->id);
-                                                       obt->transflag |= OB_DUPLIGROUP;
+                                               ob_dst->dup_group = ob_src->dup_group;
+                                               if (ob_dst->dup_group) {
+                                                       id_lib_extern(&ob_dst->dup_group->id);
+                                                       ob_dst->transflag |= OB_DUPLIGROUP;
                                                }
                                                break;
                                        case MAKE_LINKS_MODIFIERS:
-                                               BKE_object_link_modifiers(obt, ob);
-                                               obt->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
+                                               BKE_object_link_modifiers(ob_dst, ob_src);
+                                               DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+                                               break;
+                                       case MAKE_LINKS_FONTS:
+                                       {
+                                               Curve *cu_src = ob_src->data;
+                                               Curve *cu_dst = ob_dst->data;
+
+                                               if (cu_dst->vfont) cu_dst->vfont->id.us--;
+                                               cu_dst->vfont = cu_src->vfont;
+                                               id_us_plus((ID *)cu_dst->vfont);
+                                               if (cu_dst->vfontb) cu_dst->vfontb->id.us--;
+                                               cu_dst->vfontb = cu_src->vfontb;
+                                               id_us_plus((ID *)cu_dst->vfontb);
+                                               if (cu_dst->vfonti) cu_dst->vfonti->id.us--;
+                                               cu_dst->vfonti = cu_src->vfonti;
+                                               id_us_plus((ID *)cu_dst->vfonti);
+                                               if (cu_dst->vfontbi) cu_dst->vfontbi->id.us--;
+                                               cu_dst->vfontbi = cu_src->vfontbi;
+                                               id_us_plus((ID *)cu_dst->vfontbi);
+
+                                               DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
                                                break;
+                                       }
                                }
                        }
                }
        }
        CTX_DATA_END;
 
-       DAG_scene_sort(bmain, CTX_data_scene(C));
-       
-       DAG_ids_flush_update(bmain, 0);
+       if (type == MAKE_LINKS_GROUP) {
+               if (ob_groups) {
+                       BLI_linklist_free(ob_groups, NULL);
+               }
+
+               if (is_cycle) {
+                       BKE_report(op->reports, RPT_WARNING, "Skipped some groups because of cycle detected");
+               }
+       }
+
+       DAG_relations_tag_update(bmain);
        WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C));
+       WM_event_add_notifier(C, NC_OBJECT, NULL);
+
        return OPERATOR_FINISHED;
 }
 
@@ -1369,8 +1578,10 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot)
                {MAKE_LINKS_OBDATA,     "OBDATA", 0, "Object Data", ""},
                {MAKE_LINKS_MATERIALS,  "MATERIAL", 0, "Materials", ""},
                {MAKE_LINKS_ANIMDATA,   "ANIMATION", 0, "Animation Data", ""},
+               {MAKE_LINKS_GROUP,      "GROUPS", 0, "Group", ""},
                {MAKE_LINKS_DUPLIGROUP, "DUPLIGROUP", 0, "DupliGroup", ""},
                {MAKE_LINKS_MODIFIERS,  "MODIFIERS", 0, "Modifiers", ""},
+               {MAKE_LINKS_FONTS,      "FONTS", 0, "Fonts", ""},
                {0, NULL, 0, NULL, NULL}};
 
        /* identifiers */
@@ -1408,7 +1619,7 @@ static void single_object_users(Scene *scene, View3D *v3d, int flag)
                 */
                ob->id.newid = NULL;
                
-               if ( (base->flag & flag) == flag) {
+               if ((base->flag & flag) == flag) {
                        if (ob->id.lib == NULL && ob->id.us > 1) {
                                /* base gets copy of object */
                                obn = BKE_object_copy(ob);
@@ -1482,7 +1693,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, int flag)
                        id = ob->data;
                        
                        if (id && id->us > 1 && id->lib == NULL) {
-                               ob->recalc = OB_RECALC_DATA;
+                               DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
                                
                                BKE_copy_animdata_id_action(id);
                                
@@ -1500,7 +1711,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, int flag)
                                                break;
                                        case OB_MESH:
                                                ob->data = BKE_mesh_copy(ob->data);
-                                               //me= ob->data;
+                                               //me = ob->data;
                                                //if (me && me->key)
                                                //      ipo_idnew(me->key->ipo);        /* drivers */
                                                break;
@@ -1518,7 +1729,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, int flag)
                                                ob->data = BKE_lattice_copy(ob->data);
                                                break;
                                        case OB_ARMATURE:
-                                               ob->recalc |= OB_RECALC_DATA;
+                                               DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
                                                ob->data = BKE_armature_copy(ob->data);
                                                BKE_pose_rebuild(ob, ob->data);
                                                break;
@@ -1554,7 +1765,7 @@ static void single_object_action_users(Scene *scene, int flag)
        for (base = FIRSTBASE; base; base = base->next) {
                ob = base->object;
                if (ob->id.lib == NULL && (flag == 0 || (base->flag & SELECT)) ) {
-                       ob->recalc = OB_RECALC_DATA;
+                       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
                        BKE_copy_animdata_id_action(&ob->id);
                }
        }
@@ -1582,7 +1793,7 @@ static void single_mat_users(Scene *scene, int flag, int do_textures)
                                                BKE_copy_animdata_id_action(&man->id);
                                                
                                                man->id.us = 0;
-                                               assign_material(ob, man, a);
+                                               assign_material(ob, man, a, BKE_MAT_ASSIGN_USERPREF);
 
                                                if (do_textures) {
                                                        for (b = 0; b < MAX_MTEX; b++) {
@@ -1720,11 +1931,11 @@ static void make_local_makelocalmaterial(Material *ma)
        AnimData *adt;
        int b;
        
-       id_make_local(&ma->id, 0);
+       id_make_local(&ma->id, false);
        
        for (b = 0; b < MAX_MTEX; b++)
                if (ma->mtex[b] && ma->mtex[b]->tex)
-                       id_make_local(&ma->mtex[b]->tex->id, 0);
+                       id_make_local(&ma->mtex[b]->tex->id, false);
        
        adt = BKE_animdata_from_id(&ma->id);
        if (adt) BKE_animdata_make_local(adt);
@@ -1732,6 +1943,13 @@ static void make_local_makelocalmaterial(Material *ma)
        /* nodetree? XXX */
 }
 
+enum {
+       MAKE_LOCAL_SELECT_OB,
+       MAKE_LOCAL_SELECT_OBDATA,
+       MAKE_LOCAL_SELECT_OBDATA_MATERIAL,
+       MAKE_LOCAL_ALL
+};
+
 static int make_local_exec(bContext *C, wmOperator *op)
 {
        Main *bmain = CTX_data_main(C);
@@ -1742,8 +1960,8 @@ static int make_local_exec(bContext *C, wmOperator *op)
        ID *id;
        int a, b, mode = RNA_enum_get(op->ptr, "type");
        
-       if (mode == 4) {
-               BKE_library_make_local(bmain, NULL, 0); /* NULL is all libs */
+       if (mode == MAKE_LOCAL_ALL) {
+               BKE_library_make_local(bmain, NULL, false); /* NULL is all libs */
                WM_event_add_notifier(C, NC_WINDOW, NULL);
                return OPERATOR_FINISHED;
        }
@@ -1753,7 +1971,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
        CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
        {
                if (ob->id.lib)
-                       id_make_local(&ob->id, 0);
+                       id_make_local(&ob->id, false);
        }
        CTX_DATA_END;
        
@@ -1770,8 +1988,8 @@ static int make_local_exec(bContext *C, wmOperator *op)
        {
                id = ob->data;
                        
-               if (id && (mode == 2 || mode == 3)) {
-                       id_make_local(id, 0);
+               if (id && (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL))) {
+                       id_make_local(id, false);
                        adt = BKE_animdata_from_id(id);
                        if (adt) BKE_animdata_make_local(adt);
                        
@@ -1787,14 +2005,14 @@ static int make_local_exec(bContext *C, wmOperator *op)
                }
 
                for (psys = ob->particlesystem.first; psys; psys = psys->next)
-                       id_make_local(&psys->part->id, 0);
+                       id_make_local(&psys->part->id, false);
 
                adt = BKE_animdata_from_id(&ob->id);
                if (adt) BKE_animdata_make_local(adt);
        }
        CTX_DATA_END;
 
-       if (mode == 3) {
+       if (mode == MAKE_LOCAL_SELECT_OBDATA_MATERIAL) {
                CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
                {
                        if (ob->type == OB_LAMP) {
@@ -1802,7 +2020,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
 
                                for (b = 0; b < MAX_MTEX; b++)
                                        if (la->mtex[b] && la->mtex[b]->tex)
-                                               id_make_local(&la->mtex[b]->tex->id, 0);
+                                               id_make_local(&la->mtex[b]->tex->id, false);
                        }
                        else {
                                for (a = 0; a < ob->totcol; a++) {
@@ -1832,11 +2050,12 @@ static int make_local_exec(bContext *C, wmOperator *op)
 void OBJECT_OT_make_local(wmOperatorType *ot)
 {
        static EnumPropertyItem type_items[] = {
-               {1, "SELECTED_OBJECTS", 0, "Selected Objects", ""},
-               {2, "SELECTED_OBJECTS_DATA", 0, "Selected Objects and Data", ""},
-               {3, "SELECTED_OBJECTS_DATA_MAT", 0, "Selected Objects, Data and Materials", ""},
-               {4, "ALL", 0, "All", ""},
-               {0, NULL, 0, NULL, NULL}};
+               {MAKE_LOCAL_SELECT_OB, "SELECT_OBJECT", 0, "Selected Objects", ""},
+               {MAKE_LOCAL_SELECT_OBDATA, "SELECT_OBDATA", 0, "Selected Objects and Data", ""},
+               {MAKE_LOCAL_SELECT_OBDATA_MATERIAL, "SELECT_OBDATA_MATERIAL", 0, "Selected Objects, Data and Materials", ""},
+               {MAKE_LOCAL_ALL, "ALL", 0, "All", ""},
+               {0, NULL, 0, NULL, NULL}
+       };
 
        /* identifiers */
        ot->name = "Make Local";
@@ -1914,9 +2133,8 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot)
        RNA_def_boolean(ot->srna, "animation", 0, "Object Animation", "Make animation data local to each object");
 }
 
-static int drop_named_material_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 {
-       Main *bmain = CTX_data_main(C);
        Base *base = ED_view3d_give_base_under_cursor(C, event->mval);
        Material *ma;
        char name[MAX_ID_NAME - 2];
@@ -1926,11 +2144,10 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, wmEvent *even
        if (base == NULL || ma == NULL)
                return OPERATOR_CANCELLED;
        
-       assign_material(base->object, ma, 1);
+       assign_material(base->object, ma, 1, BKE_MAT_ASSIGN_USERPREF);
        
-       DAG_ids_flush_update(bmain, 0);
        WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C));
-       WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING, ma);
+       WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma);
        
        return OPERATOR_FINISHED;
 }
@@ -1950,7 +2167,7 @@ void OBJECT_OT_drop_named_material(wmOperatorType *ot)
        ot->poll = ED_operator_objectmode;
        
        /* flags */
-       ot->flag = OPTYPE_UNDO;
+       ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
        
        /* properties */
        RNA_def_string(ot->srna, "name", "Material", MAX_ID_NAME - 2, "Name", "Material name to assign");