Merging trunk up to revision 41245.
[blender.git] / source / blender / editors / object / object_select.c
index 20f3ea3df9ec04ed166c6bda3a579f425111d769..d10a6be1988c9b84e3433b15c33627de9c6125e5 100644 (file)
@@ -1,6 +1,4 @@
-/**
- * $Id$
- *
+/*
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
@@ -15,7 +13,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
  * All rights reserved.
  * ***** END GPL LICENSE BLOCK *****
  */
 
+/** \file blender/editors/object/object_select.c
+ *  \ingroup edobj
+ */
+
+
 #include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 
 #include "MEM_guardedalloc.h"
 
+#include "DNA_anim_types.h"
 #include "DNA_group_types.h"
 #include "DNA_material_types.h"
 #include "DNA_modifier_types.h"
-#include "DNA_object_types.h"
 #include "DNA_property_types.h"
 #include "DNA_scene_types.h"
-#include "DNA_texture_types.h"
 
 #include "BLI_math.h"
 #include "BLI_listbase.h"
 #include "BLI_rand.h"
 #include "BLI_string.h"
+#include "BLI_utildefines.h"
 
 #include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_global.h"
 #include "BKE_group.h"
 #include "BKE_main.h"
 #include "BKE_material.h"
 #include "BKE_property.h"
 #include "BKE_report.h"
 #include "BKE_scene.h"
-#include "BKE_utildefines.h"
+#include "BKE_library.h"
+#include "BKE_deform.h"
 
 #include "WM_api.h"
 #include "WM_types.h"
 
 #include "ED_object.h"
 #include "ED_screen.h"
+#include "ED_keyframing.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
 
 #include "RNA_access.h"
 #include "RNA_define.h"
@@ -75,7 +81,8 @@
  * this takes into account the 'restrict selection in 3d view' flag.
  * deselect works always, the restriction just prevents selection */
 
-/* Note: send a NC_SCENE|ND_OB_SELECT notifier yourself! */
+/* Note: send a NC_SCENE|ND_OB_SELECT notifier yourself! (or 
+ * or a NC_SCENE|ND_OB_VISIBLE in case of visibility toggling */
 
 void ED_base_object_select(Base *base, short mode)
 {
@@ -112,6 +119,20 @@ void ED_base_object_activate(bContext *C, Base *base)
 
 /********************** Selection Operators **********************/
 
+static int objects_selectable_poll(bContext *C)
+{
+       /* we don't check for linked scenes here, selection is
+          still allowed then for inspection of scene */
+       Object *obact= CTX_data_active_object(C);
+
+       if(CTX_data_edit_object(C))
+               return 0;
+       if(obact && obact->mode)
+               return 0;
+       
+       return 1;
+}
+
 /************************ Select by Type *************************/
 
 static int object_select_by_type_exec(bContext *C, wmOperator *op)
@@ -144,31 +165,33 @@ void OBJECT_OT_select_by_type(wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Select By Type";
-       ot->description = "Select all visible objects that are of a type.";
+       ot->description = "Select all visible objects that are of a type";
        ot->idname= "OBJECT_OT_select_by_type";
        
        /* api callbacks */
        ot->invoke= WM_menu_invoke;
        ot->exec= object_select_by_type_exec;
-       ot->poll= ED_operator_scene_editable;
+       ot->poll= objects_selectable_poll;
        
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* properties */
-       RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first.");
-       RNA_def_enum(ot->srna, "type", object_type_items, 1, "Type", "");
+       RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
+       ot->prop= RNA_def_enum(ot->srna, "type", object_type_items, 1, "Type", "");
 }
 
 /*********************** Selection by Links *********************/
 
 static EnumPropertyItem prop_select_linked_types[] = {
        //{1, "IPO", 0, "Object IPO", ""}, // XXX depreceated animation system stuff...
-       {2, "OBDATA", 0, "Ob Data", ""},
+       {2, "OBDATA", 0, "Object Data", ""},
        {3, "MATERIAL", 0, "Material", ""},
        {4, "TEXTURE", 0, "Texture", ""},
        {5, "DUPGROUP", 0, "Dupligroup", ""},
        {6, "PARTICLE", 0, "Particle System", ""},
+       {7, "LIBRARY", 0, "Library", ""},
+       {8, "LIBRARY_OBDATA", 0, "Library (Object Data)", ""},
        {0, NULL, 0, NULL, NULL}
 };
 
@@ -178,7 +201,7 @@ static int object_select_linked_exec(bContext *C, wmOperator *op)
        Object *ob;
        void *obdata = NULL;
        Material *mat = NULL, *mat1;
-       Tex *tex=0;
+       Tex *tex= NULL;
        int a, b;
        int nr = RNA_enum_get(op->ptr, "type");
        short changed = 0, extend;
@@ -201,7 +224,7 @@ static int object_select_linked_exec(bContext *C, wmOperator *op)
        }
        
        ob= OBACT;
-       if(ob==0){ 
+       if(ob==NULL){ 
                BKE_report(op->reports, RPT_ERROR, "No Active Object");
                return OPERATOR_CANCELLED;
        }
@@ -213,15 +236,15 @@ static int object_select_linked_exec(bContext *C, wmOperator *op)
                return OPERATOR_CANCELLED;
        }
        else if(nr==2) {
-               if(ob->data==0) return OPERATOR_CANCELLED;
+               if(ob->data==NULL) return OPERATOR_CANCELLED;
                obdata= ob->data;
        }
        else if(nr==3 || nr==4) {
                mat= give_current_material(ob, ob->actcol);
-               if(mat==0) return OPERATOR_CANCELLED;
+               if(mat==NULL) return OPERATOR_CANCELLED;
                if(nr==4) {
                        if(mat->mtex[ (int)mat->texact ]) tex= mat->mtex[ (int)mat->texact ]->tex;
-                       if(tex==0) return OPERATOR_CANCELLED;
+                       if(tex==NULL) return OPERATOR_CANCELLED;
                }
        }
        else if(nr==5) {
@@ -230,7 +253,14 @@ static int object_select_linked_exec(bContext *C, wmOperator *op)
        else if(nr==6) {
                if(ob->particlesystem.first==NULL) return OPERATOR_CANCELLED;
        }
-       else return OPERATOR_CANCELLED;
+       else if(nr==7) {
+               /* do nothing */
+       }
+       else if(nr==8) {
+               if(ob->data==NULL) return OPERATOR_CANCELLED;
+       }
+       else
+               return OPERATOR_CANCELLED;
        
        CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
                if(nr==1) {
@@ -289,6 +319,18 @@ static int object_select_linked_exec(bContext *C, wmOperator *op)
                                }
                        }
                }
+               else if(nr==7) {
+                       if(ob->id.lib == base->object->id.lib) {
+                               base->flag |= SELECT;
+                               changed= 1;
+                       }
+               }
+               else if(nr==8) {
+                       if(base->object->data && ((ID *)ob->data)->lib == ((ID *)base->object->data)->lib) {
+                               base->flag |= SELECT;
+                               changed= 1;
+                       }
+               }
                base->object->flag= base->flag;
        }
        CTX_DATA_END;
@@ -305,20 +347,20 @@ void OBJECT_OT_select_linked(wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Select Linked";
-       ot->description = "Select all visible objects that are linked.";
+       ot->description = "Select all visible objects that are linked";
        ot->idname= "OBJECT_OT_select_linked";
        
        /* api callbacks */
        ot->invoke= WM_menu_invoke;
        ot->exec= object_select_linked_exec;
-       ot->poll= ED_operator_scene_editable;
+       ot->poll= objects_selectable_poll;
        
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* properties */
-       RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first.");
-       RNA_def_enum(ot->srna, "type", prop_select_linked_types, 0, "Type", "");
+       RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
+       ot->prop= RNA_def_enum(ot->srna, "type", prop_select_linked_types, 0, "Type", "");
 }
 
 /*********************** Selected Grouped ********************/
@@ -335,6 +377,7 @@ static EnumPropertyItem prop_select_grouped_types[] = {
        {9, "PASS", 0, "Pass", "Render pass Index"},
        {10, "COLOR", 0, "Color", "Object Color"},
        {11, "PROPERTIES", 0, "Properties", "Game Properties"},
+       {12, "KEYINGSET", 0, "Keying Set", "Objects included in active Keying Set"},
        {0, NULL, 0, NULL, NULL}
 };
 
@@ -385,14 +428,11 @@ static short select_grouped_group(bContext *C, Object *ob)        /* Select objects in
 {
        short changed = 0;
        Group *group, *ob_groups[GROUP_MENU_MAX];
-       //char str[10 + (24*GROUP_MENU_MAX)];
-       //char *p = str;
-       int group_count=0; //, menu, i;
-
-       for (   group=G.main->group.first;
-                       group && group_count < GROUP_MENU_MAX;
-                       group=group->id.next
-               ) {
+       int group_count=0, i;
+       uiPopupMenu *pup;
+       uiLayout *layout;
+
+       for (group=CTX_data_main(C)->group.first; group && group_count < GROUP_MENU_MAX; group=group->id.next) {
                if (object_in_group (ob, group)) {
                        ob_groups[group_count] = group;
                        group_count++;
@@ -401,7 +441,6 @@ static short select_grouped_group(bContext *C, Object *ob)  /* Select objects in
 
        if (!group_count)
                return 0;
-
        else if (group_count == 1) {
                group = ob_groups[0];
                CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
@@ -413,27 +452,18 @@ static short select_grouped_group(bContext *C, Object *ob)        /* Select objects in
                CTX_DATA_END;
                return changed;
        }
-#if 0 // XXX hows this work in 2.5?
+
        /* build the menu. */
-       p += sprintf(str, "Groups%%t");
+       pup= uiPupMenuBegin(C, "Select Group", ICON_NONE);
+       layout= uiPupMenuLayout(pup);
+
        for (i=0; i<group_count; i++) {
                group = ob_groups[i];
-               p += sprintf (p, "|%s%%x%i", group->id.name+2, i);
+               uiItemStringO(layout, group->id.name+2, 0, "OBJECT_OT_select_same_group", "group", group->id.name);
        }
 
-       menu = pupmenu (str);
-       if (menu == -1)
-               return 0;
-
-       group = ob_groups[menu];
-       for (base= FIRSTBASE; base; base= base->next) {
-               if (!(base->flag & SELECT) && object_in_group(base->object, group)) {
-                       ED_base_object_select(base, BA_SELECT);
-                       changed = 1;
-               }
-       }
-#endif
-       return changed;
+       uiPupMenuEnd(C, pup);
+       return changed; // The operator already handle this!
 }
 
 static short select_grouped_object_hooks(bContext *C, Object *ob)
@@ -559,6 +589,42 @@ static short select_grouped_gameprops(bContext *C, Object *ob)
        return changed;
 }
 
+static short select_grouped_keyingset(bContext *C, Object *UNUSED(ob))
+{
+       KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C));
+       short changed = 0;
+       
+       /* firstly, validate KeyingSet */
+       if ((ks == NULL) || (ANIM_validate_keyingset(C, NULL, ks) != 0))
+               return 0;
+       
+       /* select each object that Keying Set refers to */
+       // TODO: perhaps to be more in line with the rest of these, we should only take objects 
+       // if the passed in object is included in this too
+       CTX_DATA_BEGIN(C, Base*, base, selectable_bases) 
+       {
+               /* only check for this object if it isn't selected already, to limit time wasted */
+               if ((base->flag & SELECT) == 0) {
+                       KS_Path *ksp;
+                       
+                       /* this is the slow way... we could end up with > 500 items here, 
+                        * with none matching, but end up doing this on 1000 objects...
+                        */
+                       for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
+                               /* if id matches, select then stop looping (match found) */
+                               if (ksp->id == (ID *)base->object) {
+                                       ED_base_object_select(base, BA_SELECT);
+                                       changed = 1;
+                                       break;
+                               }
+                       }
+               }
+       }
+       CTX_DATA_END;
+               
+       return changed;
+}
+
 static int object_select_grouped_exec(bContext *C, wmOperator *op)
 {
        Scene *scene= CTX_data_scene(C);
@@ -571,27 +637,29 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op)
        if (extend == 0) {
                CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
                        ED_base_object_select(base, BA_DESELECT);
+                       changed = 1;
                }
                CTX_DATA_END;
        }
        
        ob= OBACT;
-       if(ob==0)
+       if(ob==NULL) 
                BKE_report(op->reports, RPT_ERROR, "No Active Object");
                return OPERATOR_CANCELLED;
        }
        
-       if(nr==1)               changed = select_grouped_children(C, ob, 1);
-       else if(nr==2)  changed = select_grouped_children(C, ob, 0);
-       else if(nr==3)  changed = select_grouped_parent(C);
-       else if(nr==4)  changed = select_grouped_siblings(C, ob);
-       else if(nr==5)  changed = select_grouped_type(C, ob);
-       else if(nr==6)  changed = select_grouped_layer(C, ob);
-       else if(nr==7)  changed = select_grouped_group(C, ob);
-       else if(nr==8)  changed = select_grouped_object_hooks(C, ob);
-       else if(nr==9)  changed = select_grouped_index_object(C, ob);
-       else if(nr==10) changed = select_grouped_color(C, ob);
-       else if(nr==11) changed = select_grouped_gameprops(C, ob);
+       if(nr==1)               changed |= select_grouped_children(C, ob, 1);
+       else if(nr==2)  changed |= select_grouped_children(C, ob, 0);
+       else if(nr==3)  changed |= select_grouped_parent(C);
+       else if(nr==4)  changed |= select_grouped_siblings(C, ob);
+       else if(nr==5)  changed |= select_grouped_type(C, ob);
+       else if(nr==6)  changed |= select_grouped_layer(C, ob);
+       else if(nr==7)  changed |= select_grouped_group(C, ob);
+       else if(nr==8)  changed |= select_grouped_object_hooks(C, ob);
+       else if(nr==9)  changed |= select_grouped_index_object(C, ob);
+       else if(nr==10) changed |= select_grouped_color(C, ob);
+       else if(nr==11) changed |= select_grouped_gameprops(C, ob);
+       else if(nr==12) changed |= select_grouped_keyingset(C, ob);
        
        if (changed) {
                WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
@@ -605,20 +673,20 @@ void OBJECT_OT_select_grouped(wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Select Grouped";
-       ot->description = "Select all visible objects grouped by various properties.";
+       ot->description = "Select all visible objects grouped by various properties";
        ot->idname= "OBJECT_OT_select_grouped";
        
        /* api callbacks */
        ot->invoke= WM_menu_invoke;
        ot->exec= object_select_grouped_exec;
-       ot->poll= ED_operator_scene_editable;
+       ot->poll= objects_selectable_poll;
        
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* properties */
-       RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first.");
-       RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
+       RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
+       ot->prop= RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
 }
 
 /************************* Select by Layer **********************/
@@ -629,7 +697,7 @@ static int object_select_by_layer_exec(bContext *C, wmOperator *op)
        short extend;
        
        extend= RNA_boolean_get(op->ptr, "extend");
-       layernum = RNA_int_get(op->ptr, "layer");
+       layernum = RNA_int_get(op->ptr, "layers");
        
        if (extend == 0) {
                CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
@@ -653,26 +721,26 @@ static int object_select_by_layer_exec(bContext *C, wmOperator *op)
 void OBJECT_OT_select_by_layer(wmOperatorType *ot)
 {
        /* identifiers */
-       ot->name= "select by layer";
-       ot->description = "Select all visible objects on a layer.";
+       ot->name= "Select by Layer";
+       ot->description = "Select all visible objects on a layer";
        ot->idname= "OBJECT_OT_select_by_layer";
        
        /* api callbacks */
        /*ot->invoke = XXX - need a int grid popup*/
        ot->exec= object_select_by_layer_exec;
-       ot->poll= ED_operator_scene_editable;
+       ot->poll= objects_selectable_poll;
        
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* properties */
-       RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first.");
-       RNA_def_int(ot->srna, "layer", 1, 1, 20, "Layer", "", 1, 20);
+       RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
+       RNA_def_int(ot->srna, "layers", 1, 1, 20, "Layer", "", 1, 20);
 }
 
 /************************** Select Inverse *************************/
 
-static int object_select_inverse_exec(bContext *C, wmOperator *op)
+static int object_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
 {
        CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
                if (base->flag & SELECT)
@@ -693,12 +761,12 @@ void OBJECT_OT_select_inverse(wmOperatorType *ot)
        
        /* identifiers */
        ot->name= "Select Inverse";
-       ot->description = "Invert selection of all visible objects.";
+       ot->description = "Invert selection of all visible objects";
        ot->idname= "OBJECT_OT_select_inverse";
        
        /* api callbacks */
        ot->exec= object_select_inverse_exec;
-       ot->poll= ED_operator_scene_editable;
+       ot->poll= objects_selectable_poll;
        
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@@ -707,182 +775,138 @@ void OBJECT_OT_select_inverse(wmOperatorType *ot)
 
 /**************************** (De)select All ****************************/
 
-static int object_select_de_select_all_exec(bContext *C, wmOperator *op)
+static int object_select_all_exec(bContext *C, wmOperator *op)
 {
+       int action = RNA_enum_get(op->ptr, "action");
        
-       int a=0, ok=0; 
-       
-       CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
-               if (base->flag & SELECT) {
-                       ok= a= 1;
-                       break;
+       /* passthrough if no objects are visible */
+       if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH;
+
+       if (action == SEL_TOGGLE) {
+               action = SEL_SELECT;
+               CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
+                       if (base->flag & SELECT) {
+                               action = SEL_DESELECT;
+                               break;
+                       }
                }
-               else ok=1;
+               CTX_DATA_END;
        }
-       CTX_DATA_END;
-       
-       if (!ok) return OPERATOR_PASS_THROUGH;
-       
+
        CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
-               if (a) ED_base_object_select(base, BA_DESELECT);
-               else ED_base_object_select(base, BA_SELECT);
+               switch (action) {
+               case SEL_SELECT:
+                       ED_base_object_select(base, BA_SELECT);
+                       break;
+               case SEL_DESELECT:
+                       ED_base_object_select(base, BA_DESELECT);
+                       break;
+               case SEL_INVERT:
+                       if (base->flag & SELECT) {
+                               ED_base_object_select(base, BA_DESELECT);
+                       } else {
+                               ED_base_object_select(base, BA_SELECT);
+                       }
+                       break;
+               }
        }
        CTX_DATA_END;
        
-       /* undo? */
        WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
        
        return OPERATOR_FINISHED;
 }
 
-void OBJECT_OT_select_all_toggle(wmOperatorType *ot)
+void OBJECT_OT_select_all(wmOperatorType *ot)
 {
        
        /* identifiers */
-       ot->name= "deselect all";
-       ot->description = "(de)select all visible objects in scene.";
-       ot->idname= "OBJECT_OT_select_all_toggle";
+       ot->name= "Select or Deselect All";
+       ot->description = "Change selection of all visible objects in scene";
+       ot->idname= "OBJECT_OT_select_all";
        
        /* api callbacks */
-       ot->exec= object_select_de_select_all_exec;
-       ot->poll= ED_operator_scene_editable;
+       ot->exec= object_select_all_exec;
+       ot->poll= objects_selectable_poll;
        
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-       
+
+       WM_operator_properties_select_all(ot);
 }
 
-/**************************** Select Mirror ****************************/
+/**************************** Select In The Same Group ****************************/
 
-/* finds the best possible flipped name. For renaming; check for unique names afterwards */
-/* if strip_number: removes number extensions */
-void object_flip_name (char *name)
+static int object_select_same_group_exec(bContext *C, wmOperator *op)
 {
-       int     len;
-       char    prefix[128]={""};   /* The part before the facing */
-       char    suffix[128]={""};   /* The part after the facing */
-       char    replace[128]={""};  /* The replacement string */
-       char    number[128]={""};   /* The number extension string */
-       char    *index=NULL;
+       Group *group;
+       char group_name[32];
 
-       len= strlen(name);
-       if(len<3) return; // we don't do names like .R or .L
+       /* passthrough if no objects are visible */
+       if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH;
 
-       /* We first check the case with a .### extension, let's find the last period */
-       if(isdigit(name[len-1])) {
-               index= strrchr(name, '.'); // last occurrance
-               if (index && isdigit(index[1]) ) { // doesnt handle case bone.1abc2 correct..., whatever!
-                       strcpy(number, index);
-                       *index= 0;
-                       len= strlen(name);
-               }
-       }
+       RNA_string_get(op->ptr, "group", group_name);
 
-       strcpy (prefix, name);
+       for (group=CTX_data_main(C)->group.first;       group; group=group->id.next) {
+               if (!strcmp(group->id.name, group_name))
+                       break;
+       }
 
-#define IS_SEPARATOR(a) ((a)=='.' || (a)==' ' || (a)=='-' || (a)=='_')
+       if (!group)
+               return OPERATOR_PASS_THROUGH;
 
-       /* first case; separator . - _ with extensions r R l L  */
-       if( IS_SEPARATOR(name[len-2]) ) {
-               switch(name[len-1]) {
-                       case 'l':
-                               prefix[len-1]= 0;
-                               strcpy(replace, "r");
-                               break;
-                       case 'r':
-                               prefix[len-1]= 0;
-                               strcpy(replace, "l");
-                               break;
-                       case 'L':
-                               prefix[len-1]= 0;
-                               strcpy(replace, "R");
-                               break;
-                       case 'R':
-                               prefix[len-1]= 0;
-                               strcpy(replace, "L");
-                               break;
-               }
-       }
-       /* case; beginning with r R l L , with separator after it */
-       else if( IS_SEPARATOR(name[1]) ) {
-               switch(name[0]) {
-                       case 'l':
-                               strcpy(replace, "r");
-                               strcpy(suffix, name+1);
-                               prefix[0]= 0;
-                               break;
-                       case 'r':
-                               strcpy(replace, "l");
-                               strcpy(suffix, name+1);
-                               prefix[0]= 0;
-                               break;
-                       case 'L':
-                               strcpy(replace, "R");
-                               strcpy(suffix, name+1);
-                               prefix[0]= 0;
-                               break;
-                       case 'R':
-                               strcpy(replace, "L");
-                               strcpy(suffix, name+1);
-                               prefix[0]= 0;
-                               break;
-               }
-       }
-       else if(len > 5) {
-               /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
-               index = BLI_strcasestr(prefix, "right");
-               if (index==prefix || index==prefix+len-5) {
-                       if(index[0]=='r') 
-                               strcpy (replace, "left");
-                       else {
-                               if(index[1]=='I') 
-                                       strcpy (replace, "LEFT");
-                               else
-                                       strcpy (replace, "Left");
-                       }
-                       *index= 0;
-                       strcpy (suffix, index+5);
-               }
-               else {
-                       index = BLI_strcasestr(prefix, "left");
-                       if (index==prefix || index==prefix+len-4) {
-                               if(index[0]=='l') 
-                                       strcpy (replace, "right");
-                               else {
-                                       if(index[1]=='E') 
-                                               strcpy (replace, "RIGHT");
-                                       else
-                                               strcpy (replace, "Right");
-                               }
-                               *index= 0;
-                               strcpy (suffix, index+4);
-                       }
-               }
+       CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
+               if (!(base->flag & SELECT) && object_in_group(base->object, group))
+                       ED_base_object_select(base, BA_SELECT);
        }
+       CTX_DATA_END;
 
-#undef IS_SEPARATOR
+       WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
+       
+       return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_select_same_group(wmOperatorType *ot)
+{
+       
+       /* identifiers */
+       ot->name= "Select Same Group";
+       ot->description = "Select object in the same group";
+       ot->idname= "OBJECT_OT_select_same_group";
+       
+       /* api callbacks */
+       ot->exec= object_select_same_group_exec;
+       ot->poll= objects_selectable_poll;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 
-       sprintf (name, "%s%s%s%s", prefix, replace, suffix, number);
+       RNA_def_string(ot->srna, "group", "", 32, "Group", "Name of the group to select");
 }
 
+/**************************** Select Mirror ****************************/
 static int object_select_mirror_exec(bContext *C, wmOperator *op)
 {
-       char tmpname[32];
+       Scene *scene= CTX_data_scene(C);
        short extend;
        
        extend= RNA_boolean_get(op->ptr, "extend");
        
        CTX_DATA_BEGIN(C, Base*, primbase, selected_bases) {
+               char tmpname[32];
 
-               strcpy(tmpname, primbase->object->id.name+2);
-               object_flip_name(tmpname);
+               flip_side_name(tmpname, primbase->object->id.name+2, TRUE);
                
-               CTX_DATA_BEGIN(C, Base*, secbase, visible_bases) {
-                       if(!strcmp(secbase->object->id.name+2, tmpname)) {
-                               ED_base_object_select(secbase, BA_SELECT);
+               if(strcmp(tmpname, primbase->object->id.name+2)!=0) { /* names differ */
+                       Object *ob= (Object *)find_id("OB", tmpname);
+                       if(ob) {
+                               Base *secbase= object_in_scene(ob, scene);
+
+                               if(secbase) {
+                                       ED_base_object_select(secbase, BA_SELECT);
+                               }
                        }
                }
-               CTX_DATA_END;
                
                if (extend == 0) ED_base_object_select(primbase, BA_DESELECT);
                
@@ -905,12 +929,12 @@ void OBJECT_OT_select_mirror(wmOperatorType *ot)
        
        /* api callbacks */
        ot->exec= object_select_mirror_exec;
-       ot->poll= ED_operator_scene_editable;
+       ot->poll= objects_selectable_poll;
        
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
-       RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first.");
+       RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first");
 }
 
 
@@ -921,14 +945,19 @@ static int object_select_name_exec(bContext *C, wmOperator *op)
        short changed = 0;
 
        if(!extend) {
-               CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
-                       ED_base_object_select(base, BA_DESELECT);
+               CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
+                       if(base->flag & SELECT) {
+                               ED_base_object_select(base, BA_DESELECT);
+                               changed= 1;
+                       }
                }
                CTX_DATA_END;
        }
 
        CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
+               /* this is a bit dodjy, there should only be ONE object with this name, but library objects can mess this up */
                if(strcmp(name, base->object->id.name+2)==0) {
+                       ED_base_object_activate(C, base);
                        ED_base_object_select(base, BA_SELECT);
                        changed= 1;
                }
@@ -957,13 +986,13 @@ void OBJECT_OT_select_name(wmOperatorType *ot)
 
        /* api callbacks */
        ot->exec= object_select_name_exec;
-       ot->poll= ED_operator_scene_editable;
+       ot->poll= objects_selectable_poll;
 
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 
-       RNA_def_string(ot->srna, "name", "", 0, "Name", "Object name to select.");
-       RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first.");
+       RNA_def_string(ot->srna, "name", "", 0, "Name", "Object name to select");
+       RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first");
 }
 
 /**************************** Select Random ****************************/
@@ -981,11 +1010,11 @@ static int object_select_random_exec(bContext *C, wmOperator *op)
                }
                CTX_DATA_END;
        }
-       percent = RNA_float_get(op->ptr, "percent");
+       percent = RNA_float_get(op->ptr, "percent")/100.0f;
                
        CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
                if (BLI_frand() < percent) {
-                               ED_base_object_select(base, BA_SELECT);
+                       ED_base_object_select(base, BA_SELECT);
                }
        }
        CTX_DATA_END;
@@ -998,21 +1027,21 @@ static int object_select_random_exec(bContext *C, wmOperator *op)
 void OBJECT_OT_select_random(wmOperatorType *ot)
 {
        /* identifiers */
-       ot->name= "Random select";
-       ot->description = "Set select on random visible objects.";
+       ot->name= "Select Random";
+       ot->description = "Set select on random visible objects";
        ot->idname= "OBJECT_OT_select_random";
        
        /* api callbacks */
        /*ot->invoke= object_select_random_invoke XXX - need a number popup ;*/
        ot->exec = object_select_random_exec;
-       ot->poll= ED_operator_scene_editable;
+       ot->poll= objects_selectable_poll;
        
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* properties */
-       RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first.");
-       RNA_def_float_percentage(ot->srna, "percent", 0.5f, 0.0f, 1.0f, "Percent", "percentage of objects to randomly select", 0.0001f, 1.0f);
+       RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, "Percent", "Percentage of objects to select randomly", 0.f, 100.0f);
+       RNA_def_boolean(ot->srna, "extend", FALSE, "Extend Selection", "Extend selection instead of deselecting everything first");
 }