Merging trunk up to revision 41245.
[blender.git] / source / blender / editors / object / object_select.c
index accdb67fb991d3046a937bfd4fe592710c2bac63..d10a6be1988c9b84e3433b15c33627de9c6125e5 100644 (file)
@@ -1,6 +1,4 @@
-/**
- * $Id$
- *
+/*
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  * ***** END GPL LICENSE BLOCK *****
  */
 
+/** \file blender/editors/object/object_select.c
+ *  \ingroup edobj
+ */
+
+
 #include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -32,6 +35,7 @@
 
 #include "MEM_guardedalloc.h"
 
+#include "DNA_anim_types.h"
 #include "DNA_group_types.h"
 #include "DNA_material_types.h"
 #include "DNA_modifier_types.h"
@@ -42,6 +46,7 @@
 #include "BLI_listbase.h"
 #include "BLI_rand.h"
 #include "BLI_string.h"
+#include "BLI_utildefines.h"
 
 #include "BKE_context.h"
 #include "BKE_group.h"
 #include "BKE_property.h"
 #include "BKE_report.h"
 #include "BKE_scene.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"
@@ -72,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)
 {
@@ -109,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)
@@ -147,13 +171,13 @@ void OBJECT_OT_select_by_type(wmOperatorType *ot)
        /* 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_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", "");
 }
 
@@ -177,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;
@@ -212,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) {
@@ -329,13 +353,13 @@ void OBJECT_OT_select_linked(wmOperatorType *ot)
        /* 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_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", "");
 }
 
@@ -353,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}
 };
 
@@ -429,7 +454,7 @@ static short select_grouped_group(bContext *C, Object *ob)  /* Select objects in
        }
 
        /* build the menu. */
-       pup= uiPupMenuBegin(C, "Select Group", 0);
+       pup= uiPupMenuBegin(C, "Select Group", ICON_NONE);
        layout= uiPupMenuLayout(pup);
 
        for (i=0; i<group_count; i++) {
@@ -564,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);
@@ -582,7 +643,7 @@ static int object_select_grouped_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;
        }
@@ -598,6 +659,7 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op)
        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));
@@ -617,13 +679,13 @@ void OBJECT_OT_select_grouped(wmOperatorType *ot)
        /* 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_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", "");
 }
 
@@ -635,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) {
@@ -659,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->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)
@@ -704,7 +766,7 @@ void OBJECT_OT_select_inverse(wmOperatorType *ot)
        
        /* 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;
@@ -765,7 +827,7 @@ void OBJECT_OT_select_all(wmOperatorType *ot)
        
        /* api callbacks */
        ot->exec= object_select_all_exec;
-       ot->poll= ED_operator_scene_editable;
+       ot->poll= objects_selectable_poll;
        
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@@ -808,38 +870,43 @@ void OBJECT_OT_select_same_group(wmOperatorType *ot)
 {
        
        /* identifiers */
-       ot->name= "select same group";
+       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= ED_operator_scene_editable;
+       ot->poll= objects_selectable_poll;
        
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 
-       RNA_def_string(ot->srna, "group", "", 32, "Group", "Name of the group to select.");
+       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)
 {
+       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];
+
                flip_side_name(tmpname, primbase->object->id.name+2, TRUE);
+               
+               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);
 
-               CTX_DATA_BEGIN(C, Base*, secbase, visible_bases) {
-                       if(!strcmp(secbase->object->id.name+2, tmpname)) {
-                               ED_base_object_select(secbase, BA_SELECT);
+                               if(secbase) {
+                                       ED_base_object_select(secbase, BA_SELECT);
+                               }
                        }
                }
-               CTX_DATA_END;
                
                if (extend == 0) ED_base_object_select(primbase, BA_DESELECT);
                
@@ -862,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");
 }
 
 
@@ -878,8 +945,11 @@ 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;
        }
@@ -916,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 ****************************/
@@ -964,14 +1034,14 @@ void OBJECT_OT_select_random(wmOperatorType *ot)
        /* 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_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.");
+       RNA_def_boolean(ot->srna, "extend", FALSE, "Extend Selection", "Extend selection instead of deselecting everything first");
 }