Blender  V2.59
object_select.c
Go to the documentation of this file.
00001 /*
00002  * $Id: object_select.c 36525 2011-05-06 23:46:24Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * Contributor(s): Blender Foundation, 2002-2008 full recode
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include <ctype.h>
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <string.h>
00037 
00038 #include "MEM_guardedalloc.h"
00039 
00040 #include "DNA_group_types.h"
00041 #include "DNA_material_types.h"
00042 #include "DNA_modifier_types.h"
00043 #include "DNA_property_types.h"
00044 #include "DNA_scene_types.h"
00045 
00046 #include "BLI_math.h"
00047 #include "BLI_listbase.h"
00048 #include "BLI_rand.h"
00049 #include "BLI_string.h"
00050 #include "BLI_utildefines.h"
00051 
00052 #include "BKE_context.h"
00053 #include "BKE_group.h"
00054 #include "BKE_main.h"
00055 #include "BKE_material.h"
00056 #include "BKE_particle.h"
00057 #include "BKE_property.h"
00058 #include "BKE_report.h"
00059 #include "BKE_scene.h"
00060 #include "BKE_library.h"
00061 #include "BKE_deform.h"
00062 
00063 #include "WM_api.h"
00064 #include "WM_types.h"
00065 
00066 #include "ED_object.h"
00067 #include "ED_screen.h"
00068 
00069 #include "UI_interface.h"
00070 #include "UI_resources.h"
00071 
00072 #include "RNA_access.h"
00073 #include "RNA_define.h"
00074 #include "RNA_enum_types.h"
00075 
00076 #include "object_intern.h"
00077 
00078 /************************ Exported **************************/
00079 
00080 /* simple API for object selection, rather than just using the flag
00081  * this takes into account the 'restrict selection in 3d view' flag.
00082  * deselect works always, the restriction just prevents selection */
00083 
00084 /* Note: send a NC_SCENE|ND_OB_SELECT notifier yourself! (or 
00085  * or a NC_SCENE|ND_OB_VISIBLE in case of visibility toggling */
00086 
00087 void ED_base_object_select(Base *base, short mode)
00088 {
00089         if (base) {
00090                 if (mode==BA_SELECT) {
00091                         if (!(base->object->restrictflag & OB_RESTRICT_SELECT))
00092                                 base->flag |= SELECT;
00093                 }
00094                 else if (mode==BA_DESELECT) {
00095                         base->flag &= ~SELECT;
00096                 }
00097                 base->object->flag= base->flag;
00098         }
00099 }
00100 
00101 /* also to set active NULL */
00102 void ED_base_object_activate(bContext *C, Base *base)
00103 {
00104         Scene *scene= CTX_data_scene(C);
00105         
00106         /* sets scene->basact */
00107         BASACT= base;
00108         
00109         if(base) {
00110                 
00111                 /* XXX old signals, remember to handle notifiers now! */
00112                 //              select_actionchannel_by_name(base->object->action, "Object", 1);
00113                 
00114                 WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);
00115         }
00116         else
00117                 WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, NULL);
00118 }
00119 
00120 /********************** Selection Operators **********************/
00121 
00122 /************************ Select by Type *************************/
00123 
00124 static int object_select_by_type_exec(bContext *C, wmOperator *op)
00125 {
00126         short obtype, extend;
00127         
00128         obtype = RNA_enum_get(op->ptr, "type");
00129         extend= RNA_boolean_get(op->ptr, "extend");
00130                 
00131         if (extend == 0) {
00132                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
00133                         ED_base_object_select(base, BA_DESELECT);
00134                 }
00135                 CTX_DATA_END;
00136         }
00137         
00138         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
00139                 if(base->object->type==obtype) {
00140                         ED_base_object_select(base, BA_SELECT);
00141                 }
00142         }
00143         CTX_DATA_END;
00144         
00145         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
00146         
00147         return OPERATOR_FINISHED;
00148 }
00149 
00150 void OBJECT_OT_select_by_type(wmOperatorType *ot)
00151 {
00152         /* identifiers */
00153         ot->name= "Select By Type";
00154         ot->description = "Select all visible objects that are of a type";
00155         ot->idname= "OBJECT_OT_select_by_type";
00156         
00157         /* api callbacks */
00158         ot->invoke= WM_menu_invoke;
00159         ot->exec= object_select_by_type_exec;
00160         ot->poll= ED_operator_objectmode;
00161         
00162         /* flags */
00163         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00164         
00165         /* properties */
00166         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first.");
00167         ot->prop= RNA_def_enum(ot->srna, "type", object_type_items, 1, "Type", "");
00168 }
00169 
00170 /*********************** Selection by Links *********************/
00171 
00172 static EnumPropertyItem prop_select_linked_types[] = {
00173         //{1, "IPO", 0, "Object IPO", ""}, // XXX depreceated animation system stuff...
00174         {2, "OBDATA", 0, "Object Data", ""},
00175         {3, "MATERIAL", 0, "Material", ""},
00176         {4, "TEXTURE", 0, "Texture", ""},
00177         {5, "DUPGROUP", 0, "Dupligroup", ""},
00178         {6, "PARTICLE", 0, "Particle System", ""},
00179         {7, "LIBRARY", 0, "Library", ""},
00180         {8, "LIBRARY_OBDATA", 0, "Library (Object Data)", ""},
00181         {0, NULL, 0, NULL, NULL}
00182 };
00183 
00184 static int object_select_linked_exec(bContext *C, wmOperator *op)
00185 {
00186         Scene *scene= CTX_data_scene(C);
00187         Object *ob;
00188         void *obdata = NULL;
00189         Material *mat = NULL, *mat1;
00190         Tex *tex= NULL;
00191         int a, b;
00192         int nr = RNA_enum_get(op->ptr, "type");
00193         short changed = 0, extend;
00194         /* events (nr):
00195          * Object Ipo: 1
00196          * ObData: 2
00197          * Current Material: 3
00198          * Current Texture: 4
00199          * DupliGroup: 5
00200          * PSys: 6
00201          */
00202 
00203         extend= RNA_boolean_get(op->ptr, "extend");
00204         
00205         if (extend == 0) {
00206                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
00207                         ED_base_object_select(base, BA_DESELECT);
00208                 }
00209                 CTX_DATA_END;
00210         }
00211         
00212         ob= OBACT;
00213         if(ob==NULL){ 
00214                 BKE_report(op->reports, RPT_ERROR, "No Active Object");
00215                 return OPERATOR_CANCELLED;
00216         }
00217         
00218         if(nr==1) {     
00219                         // XXX old animation system
00220                 //ipo= ob->ipo;
00221                 //if(ipo==0) return OPERATOR_CANCELLED;
00222                 return OPERATOR_CANCELLED;
00223         }
00224         else if(nr==2) {
00225                 if(ob->data==NULL) return OPERATOR_CANCELLED;
00226                 obdata= ob->data;
00227         }
00228         else if(nr==3 || nr==4) {
00229                 mat= give_current_material(ob, ob->actcol);
00230                 if(mat==NULL) return OPERATOR_CANCELLED;
00231                 if(nr==4) {
00232                         if(mat->mtex[ (int)mat->texact ]) tex= mat->mtex[ (int)mat->texact ]->tex;
00233                         if(tex==NULL) return OPERATOR_CANCELLED;
00234                 }
00235         }
00236         else if(nr==5) {
00237                 if(ob->dup_group==NULL) return OPERATOR_CANCELLED;
00238         }
00239         else if(nr==6) {
00240                 if(ob->particlesystem.first==NULL) return OPERATOR_CANCELLED;
00241         }
00242         else if(nr==7) {
00243                 /* do nothing */
00244         }
00245         else if(nr==8) {
00246                 if(ob->data==NULL) return OPERATOR_CANCELLED;
00247         }
00248         else
00249                 return OPERATOR_CANCELLED;
00250         
00251         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
00252                 if(nr==1) {
00253                                 // XXX old animation system
00254                         //if(base->object->ipo==ipo) base->flag |= SELECT;
00255                         //changed = 1;
00256                 }
00257                 else if(nr==2) {
00258                         if(base->object->data==obdata) base->flag |= SELECT;
00259                         changed = 1;
00260                 }
00261                 else if(nr==3 || nr==4) {
00262                         ob= base->object;
00263                         
00264                         for(a=1; a<=ob->totcol; a++) {
00265                                 mat1= give_current_material(ob, a);
00266                                 if(nr==3) {
00267                                         if(mat1==mat) base->flag |= SELECT;
00268                                         changed = 1;
00269                                 }
00270                                 else if(mat1 && nr==4) {
00271                                         for(b=0; b<MAX_MTEX; b++) {
00272                                                 if(mat1->mtex[b]) {
00273                                                         if(tex==mat1->mtex[b]->tex) {
00274                                                                 base->flag |= SELECT;
00275                                                                 changed = 1;
00276                                                                 break;
00277                                                         }
00278                                                 }
00279                                         }
00280                                 }
00281                         }
00282                 }
00283                 else if(nr==5) {
00284                         if(base->object->dup_group==ob->dup_group) {
00285                                  base->flag |= SELECT;
00286                                  changed = 1;
00287                         }
00288                 }
00289                 else if(nr==6) {
00290                         /* loop through other, then actives particles*/
00291                         ParticleSystem *psys;
00292                         ParticleSystem *psys_act;
00293                         
00294                         for(psys=base->object->particlesystem.first; psys; psys=psys->next) {
00295                                 for(psys_act=ob->particlesystem.first; psys_act; psys_act=psys_act->next) {
00296                                         if (psys->part == psys_act->part) {
00297                                                 base->flag |= SELECT;
00298                                                 changed = 1;
00299                                                 break;
00300                                         }
00301                                 }
00302                                 
00303                                 if (base->flag & SELECT) {
00304                                         break;
00305                                 }
00306                         }
00307                 }
00308                 else if(nr==7) {
00309                         if(ob->id.lib == base->object->id.lib) {
00310                                 base->flag |= SELECT;
00311                                 changed= 1;
00312                         }
00313                 }
00314                 else if(nr==8) {
00315                         if(base->object->data && ((ID *)ob->data)->lib == ((ID *)base->object->data)->lib) {
00316                                 base->flag |= SELECT;
00317                                 changed= 1;
00318                         }
00319                 }
00320                 base->object->flag= base->flag;
00321         }
00322         CTX_DATA_END;
00323         
00324         if (changed) {
00325                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
00326                 return OPERATOR_FINISHED;
00327         }
00328         
00329         return OPERATOR_CANCELLED;
00330 }
00331 
00332 void OBJECT_OT_select_linked(wmOperatorType *ot)
00333 {
00334         /* identifiers */
00335         ot->name= "Select Linked";
00336         ot->description = "Select all visible objects that are linked";
00337         ot->idname= "OBJECT_OT_select_linked";
00338         
00339         /* api callbacks */
00340         ot->invoke= WM_menu_invoke;
00341         ot->exec= object_select_linked_exec;
00342         ot->poll= ED_operator_objectmode;
00343         
00344         /* flags */
00345         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00346         
00347         /* properties */
00348         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first.");
00349         ot->prop= RNA_def_enum(ot->srna, "type", prop_select_linked_types, 0, "Type", "");
00350 }
00351 
00352 /*********************** Selected Grouped ********************/
00353 
00354 static EnumPropertyItem prop_select_grouped_types[] = {
00355         {1, "CHILDREN_RECURSIVE", 0, "Children", ""},
00356         {2, "CHILDREN", 0, "Immediate Children", ""},
00357         {3, "PARENT", 0, "Parent", ""},
00358         {4, "SIBLINGS", 0, "Siblings", "Shared Parent"},
00359         {5, "TYPE", 0, "Type", "Shared object type"},
00360         {6, "LAYER", 0, "Layer", "Shared layers"},
00361         {7, "GROUP", 0, "Group", "Shared group"},
00362         {8, "HOOK", 0, "Hook", ""},
00363         {9, "PASS", 0, "Pass", "Render pass Index"},
00364         {10, "COLOR", 0, "Color", "Object Color"},
00365         {11, "PROPERTIES", 0, "Properties", "Game Properties"},
00366         {0, NULL, 0, NULL, NULL}
00367 };
00368 
00369 static short select_grouped_children(bContext *C, Object *ob, int recursive)
00370 {
00371         short changed = 0;
00372 
00373         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
00374                 if (ob == base->object->parent) {
00375                         if (!(base->flag & SELECT)) {
00376                                 ED_base_object_select(base, BA_SELECT);
00377                                 changed = 1;
00378                         }
00379 
00380                         if (recursive)
00381                                 changed |= select_grouped_children(C, base->object, 1);
00382                 }
00383         }
00384         CTX_DATA_END;
00385         return changed;
00386 }
00387 
00388 static short select_grouped_parent(bContext *C) /* Makes parent active and de-selected OBACT */
00389 {
00390         Scene *scene= CTX_data_scene(C);
00391         View3D *v3d= CTX_wm_view3d(C);
00392 
00393         short changed = 0;
00394         Base *baspar, *basact= CTX_data_active_base(C);
00395 
00396         if (!basact || !(basact->object->parent)) return 0; /* we know OBACT is valid */
00397 
00398         baspar= object_in_scene(basact->object->parent, scene);
00399 
00400         /* can be NULL if parent in other scene */
00401         if(baspar && BASE_SELECTABLE(v3d, baspar)) {
00402                 ED_base_object_select(basact, BA_DESELECT);
00403                 ED_base_object_select(baspar, BA_SELECT);
00404                 ED_base_object_activate(C, baspar);
00405                 changed = 1;
00406         }
00407         return changed;
00408 }
00409 
00410 
00411 #define GROUP_MENU_MAX  24
00412 static short select_grouped_group(bContext *C, Object *ob)      /* Select objects in the same group as the active */
00413 {
00414         short changed = 0;
00415         Group *group, *ob_groups[GROUP_MENU_MAX];
00416         int group_count=0, i;
00417         uiPopupMenu *pup;
00418         uiLayout *layout;
00419 
00420         for (group=CTX_data_main(C)->group.first; group && group_count < GROUP_MENU_MAX; group=group->id.next) {
00421                 if (object_in_group (ob, group)) {
00422                         ob_groups[group_count] = group;
00423                         group_count++;
00424                 }
00425         }
00426 
00427         if (!group_count)
00428                 return 0;
00429         else if (group_count == 1) {
00430                 group = ob_groups[0];
00431                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
00432                         if (!(base->flag & SELECT) && object_in_group(base->object, group)) {
00433                                 ED_base_object_select(base, BA_SELECT);
00434                                 changed = 1;
00435                         }
00436                 }
00437                 CTX_DATA_END;
00438                 return changed;
00439         }
00440 
00441         /* build the menu. */
00442         pup= uiPupMenuBegin(C, "Select Group", ICON_NONE);
00443         layout= uiPupMenuLayout(pup);
00444 
00445         for (i=0; i<group_count; i++) {
00446                 group = ob_groups[i];
00447                 uiItemStringO(layout, group->id.name+2, 0, "OBJECT_OT_select_same_group", "group", group->id.name);
00448         }
00449 
00450         uiPupMenuEnd(C, pup);
00451         return changed; // The operator already handle this!
00452 }
00453 
00454 static short select_grouped_object_hooks(bContext *C, Object *ob)
00455 {
00456         Scene *scene= CTX_data_scene(C);
00457         View3D *v3d= CTX_wm_view3d(C);
00458 
00459         short changed = 0;
00460         Base *base;
00461         ModifierData *md;
00462         HookModifierData *hmd;
00463 
00464         for (md = ob->modifiers.first; md; md=md->next) {
00465                 if (md->type==eModifierType_Hook) {
00466                         hmd= (HookModifierData*) md;
00467                         if (hmd->object && !(hmd->object->flag & SELECT)) {
00468                                 base= object_in_scene(hmd->object, scene);
00469                                 if (base && (BASE_SELECTABLE(v3d, base))) {
00470                                         ED_base_object_select(base, BA_SELECT);
00471                                         changed = 1;
00472                                 }
00473                         }
00474                 }
00475         }
00476         return changed;
00477 }
00478 
00479 /* Select objects woth the same parent as the active (siblings),
00480  * parent can be NULL also */
00481 static short select_grouped_siblings(bContext *C, Object *ob)
00482 {
00483         short changed = 0;
00484 
00485         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
00486                 if ((base->object->parent==ob->parent)  && !(base->flag & SELECT)) {
00487                         ED_base_object_select(base, BA_SELECT);
00488                         changed = 1;
00489                 }
00490         }
00491         CTX_DATA_END;
00492         return changed;
00493 }
00494 
00495 static short select_grouped_type(bContext *C, Object *ob)
00496 {
00497         short changed = 0;
00498 
00499         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
00500                 if ((base->object->type == ob->type) && !(base->flag & SELECT)) {
00501                         ED_base_object_select(base, BA_SELECT);
00502                         changed = 1;
00503                 }
00504         }
00505         CTX_DATA_END;
00506         return changed;
00507 }
00508 
00509 static short select_grouped_layer(bContext *C, Object *ob)
00510 {
00511         char changed = 0;
00512 
00513         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
00514                 if ((base->lay & ob->lay) && !(base->flag & SELECT)) {
00515                         ED_base_object_select(base, BA_SELECT);
00516                         changed = 1;
00517                 }
00518         }
00519         CTX_DATA_END;
00520         return changed;
00521 }
00522 
00523 static short select_grouped_index_object(bContext *C, Object *ob)
00524 {
00525         char changed = 0;
00526 
00527         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
00528                 if ((base->object->index == ob->index) && !(base->flag & SELECT)) {
00529                         ED_base_object_select(base, BA_SELECT);
00530                         changed = 1;
00531                 }
00532         }
00533         CTX_DATA_END;
00534         return changed;
00535 }
00536 
00537 static short select_grouped_color(bContext *C, Object *ob)
00538 {
00539         char changed = 0;
00540 
00541         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
00542                 if (!(base->flag & SELECT) && (compare_v3v3(base->object->col, ob->col, 0.005f))) {
00543                         ED_base_object_select(base, BA_SELECT);
00544                         changed = 1;
00545                 }
00546         }
00547         CTX_DATA_END;
00548         return changed;
00549 }
00550 
00551 static short objects_share_gameprop(Object *a, Object *b)
00552 {
00553         bProperty *prop;
00554         /*make a copy of all its properties*/
00555 
00556         for( prop= a->prop.first; prop; prop = prop->next ) {
00557                 if ( get_ob_property(b, prop->name) )
00558                         return 1;
00559         }
00560         return 0;
00561 }
00562 
00563 static short select_grouped_gameprops(bContext *C, Object *ob)
00564 {
00565         char changed = 0;
00566 
00567         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
00568                 if (!(base->flag & SELECT) && (objects_share_gameprop(base->object, ob))) {
00569                         ED_base_object_select(base, BA_SELECT);
00570                         changed = 1;
00571                 }
00572         }
00573         CTX_DATA_END;
00574         return changed;
00575 }
00576 
00577 static int object_select_grouped_exec(bContext *C, wmOperator *op)
00578 {
00579         Scene *scene= CTX_data_scene(C);
00580         Object *ob;
00581         int nr = RNA_enum_get(op->ptr, "type");
00582         short changed = 0, extend;
00583 
00584         extend= RNA_boolean_get(op->ptr, "extend");
00585         
00586         if (extend == 0) {
00587                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
00588                         ED_base_object_select(base, BA_DESELECT);
00589                         changed = 1;
00590                 }
00591                 CTX_DATA_END;
00592         }
00593         
00594         ob= OBACT;
00595         if(ob==NULL) { 
00596                 BKE_report(op->reports, RPT_ERROR, "No Active Object");
00597                 return OPERATOR_CANCELLED;
00598         }
00599         
00600         if(nr==1)               changed |= select_grouped_children(C, ob, 1);
00601         else if(nr==2)  changed |= select_grouped_children(C, ob, 0);
00602         else if(nr==3)  changed |= select_grouped_parent(C);
00603         else if(nr==4)  changed |= select_grouped_siblings(C, ob);
00604         else if(nr==5)  changed |= select_grouped_type(C, ob);
00605         else if(nr==6)  changed |= select_grouped_layer(C, ob);
00606         else if(nr==7)  changed |= select_grouped_group(C, ob);
00607         else if(nr==8)  changed |= select_grouped_object_hooks(C, ob);
00608         else if(nr==9)  changed |= select_grouped_index_object(C, ob);
00609         else if(nr==10) changed |= select_grouped_color(C, ob);
00610         else if(nr==11) changed |= select_grouped_gameprops(C, ob);
00611         
00612         if (changed) {
00613                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
00614                 return OPERATOR_FINISHED;
00615         }
00616         
00617         return OPERATOR_CANCELLED;
00618 }
00619 
00620 void OBJECT_OT_select_grouped(wmOperatorType *ot)
00621 {
00622         /* identifiers */
00623         ot->name= "Select Grouped";
00624         ot->description = "Select all visible objects grouped by various properties";
00625         ot->idname= "OBJECT_OT_select_grouped";
00626         
00627         /* api callbacks */
00628         ot->invoke= WM_menu_invoke;
00629         ot->exec= object_select_grouped_exec;
00630         ot->poll= ED_operator_objectmode;
00631         
00632         /* flags */
00633         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00634         
00635         /* properties */
00636         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first.");
00637         ot->prop= RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
00638 }
00639 
00640 /************************* Select by Layer **********************/
00641 
00642 static int object_select_by_layer_exec(bContext *C, wmOperator *op)
00643 {
00644         unsigned int layernum;
00645         short extend;
00646         
00647         extend= RNA_boolean_get(op->ptr, "extend");
00648         layernum = RNA_int_get(op->ptr, "layers");
00649         
00650         if (extend == 0) {
00651                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
00652                         ED_base_object_select(base, BA_DESELECT);
00653                 }
00654                 CTX_DATA_END;
00655         }
00656                 
00657         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
00658                 if(base->lay == (1<< (layernum -1)))
00659                         ED_base_object_select(base, BA_SELECT);
00660         }
00661         CTX_DATA_END;
00662         
00663         /* undo? */
00664         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
00665         
00666         return OPERATOR_FINISHED;
00667 }
00668 
00669 void OBJECT_OT_select_by_layer(wmOperatorType *ot)
00670 {
00671         /* identifiers */
00672         ot->name= "Select by Layer";
00673         ot->description = "Select all visible objects on a layer";
00674         ot->idname= "OBJECT_OT_select_by_layer";
00675         
00676         /* api callbacks */
00677         /*ot->invoke = XXX - need a int grid popup*/
00678         ot->exec= object_select_by_layer_exec;
00679         ot->poll= ED_operator_objectmode;
00680         
00681         /* flags */
00682         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00683         
00684         /* properties */
00685         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first.");
00686         RNA_def_int(ot->srna, "layers", 1, 1, 20, "Layer", "", 1, 20);
00687 }
00688 
00689 /************************** Select Inverse *************************/
00690 
00691 static int object_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
00692 {
00693         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
00694                 if (base->flag & SELECT)
00695                         ED_base_object_select(base, BA_DESELECT);
00696                 else
00697                         ED_base_object_select(base, BA_SELECT);
00698         }
00699         CTX_DATA_END;
00700         
00701         /* undo? */
00702         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
00703         
00704         return OPERATOR_FINISHED;
00705 }
00706 
00707 void OBJECT_OT_select_inverse(wmOperatorType *ot)
00708 {
00709         
00710         /* identifiers */
00711         ot->name= "Select Inverse";
00712         ot->description = "Invert selection of all visible objects";
00713         ot->idname= "OBJECT_OT_select_inverse";
00714         
00715         /* api callbacks */
00716         ot->exec= object_select_inverse_exec;
00717         ot->poll= ED_operator_objectmode;
00718         
00719         /* flags */
00720         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00721         
00722 }
00723 
00724 /**************************** (De)select All ****************************/
00725 
00726 static int object_select_all_exec(bContext *C, wmOperator *op)
00727 {
00728         int action = RNA_enum_get(op->ptr, "action");
00729         
00730         /* passthrough if no objects are visible */
00731         if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH;
00732 
00733         if (action == SEL_TOGGLE) {
00734                 action = SEL_SELECT;
00735                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
00736                         if (base->flag & SELECT) {
00737                                 action = SEL_DESELECT;
00738                                 break;
00739                         }
00740                 }
00741                 CTX_DATA_END;
00742         }
00743 
00744         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
00745                 switch (action) {
00746                 case SEL_SELECT:
00747                         ED_base_object_select(base, BA_SELECT);
00748                         break;
00749                 case SEL_DESELECT:
00750                         ED_base_object_select(base, BA_DESELECT);
00751                         break;
00752                 case SEL_INVERT:
00753                         if (base->flag & SELECT) {
00754                                 ED_base_object_select(base, BA_DESELECT);
00755                         } else {
00756                                 ED_base_object_select(base, BA_SELECT);
00757                         }
00758                         break;
00759                 }
00760         }
00761         CTX_DATA_END;
00762         
00763         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
00764         
00765         return OPERATOR_FINISHED;
00766 }
00767 
00768 void OBJECT_OT_select_all(wmOperatorType *ot)
00769 {
00770         
00771         /* identifiers */
00772         ot->name= "Select or Deselect All";
00773         ot->description = "Change selection of all visible objects in scene";
00774         ot->idname= "OBJECT_OT_select_all";
00775         
00776         /* api callbacks */
00777         ot->exec= object_select_all_exec;
00778         ot->poll= ED_operator_objectmode;
00779         
00780         /* flags */
00781         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00782 
00783         WM_operator_properties_select_all(ot);
00784 }
00785 
00786 /**************************** Select In The Same Group ****************************/
00787 
00788 static int object_select_same_group_exec(bContext *C, wmOperator *op)
00789 {
00790         Group *group;
00791         char group_name[32];
00792 
00793         /* passthrough if no objects are visible */
00794         if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH;
00795 
00796         RNA_string_get(op->ptr, "group", group_name);
00797 
00798         for (group=CTX_data_main(C)->group.first;       group; group=group->id.next) {
00799                 if (!strcmp(group->id.name, group_name))
00800                         break;
00801         }
00802 
00803         if (!group)
00804                 return OPERATOR_PASS_THROUGH;
00805 
00806         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
00807                 if (!(base->flag & SELECT) && object_in_group(base->object, group))
00808                         ED_base_object_select(base, BA_SELECT);
00809         }
00810         CTX_DATA_END;
00811 
00812         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
00813         
00814         return OPERATOR_FINISHED;
00815 }
00816 
00817 void OBJECT_OT_select_same_group(wmOperatorType *ot)
00818 {
00819         
00820         /* identifiers */
00821         ot->name= "Select Same Group";
00822         ot->description = "Select object in the same group";
00823         ot->idname= "OBJECT_OT_select_same_group";
00824         
00825         /* api callbacks */
00826         ot->exec= object_select_same_group_exec;
00827         ot->poll= ED_operator_objectmode;
00828         
00829         /* flags */
00830         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00831 
00832         RNA_def_string(ot->srna, "group", "", 32, "Group", "Name of the group to select.");
00833 }
00834 
00835 /**************************** Select Mirror ****************************/
00836 static int object_select_mirror_exec(bContext *C, wmOperator *op)
00837 {
00838         Scene *scene= CTX_data_scene(C);
00839         short extend;
00840         
00841         extend= RNA_boolean_get(op->ptr, "extend");
00842         
00843         CTX_DATA_BEGIN(C, Base*, primbase, selected_bases) {
00844                 char tmpname[32];
00845 
00846                 flip_side_name(tmpname, primbase->object->id.name+2, TRUE);
00847                 
00848                 if(strcmp(tmpname, primbase->object->id.name+2)!=0) { /* names differ */
00849                         Object *ob= (Object *)find_id("OB", tmpname);
00850                         if(ob) {
00851                                 Base *secbase= object_in_scene(ob, scene);
00852 
00853                                 if(secbase) {
00854                                         ED_base_object_select(secbase, BA_SELECT);
00855                                 }
00856                         }
00857                 }
00858                 
00859                 if (extend == 0) ED_base_object_select(primbase, BA_DESELECT);
00860                 
00861         }
00862         CTX_DATA_END;
00863         
00864         /* undo? */
00865         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
00866         
00867         return OPERATOR_FINISHED;
00868 }
00869 
00870 void OBJECT_OT_select_mirror(wmOperatorType *ot)
00871 {
00872         
00873         /* identifiers */
00874         ot->name= "Select Mirror";
00875         ot->description = "Select the Mirror objects of the selected object eg. L.sword -> R.sword";
00876         ot->idname= "OBJECT_OT_select_mirror";
00877         
00878         /* api callbacks */
00879         ot->exec= object_select_mirror_exec;
00880         ot->poll= ED_operator_objectmode;
00881         
00882         /* flags */
00883         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00884         
00885         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first.");
00886 }
00887 
00888 
00889 static int object_select_name_exec(bContext *C, wmOperator *op)
00890 {
00891         char *name= RNA_string_get_alloc(op->ptr, "name", NULL, 0);
00892         short extend= RNA_boolean_get(op->ptr, "extend");
00893         short changed = 0;
00894 
00895         if(!extend) {
00896                 CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
00897                         if(base->flag & SELECT) {
00898                                 ED_base_object_select(base, BA_DESELECT);
00899                                 changed= 1;
00900                         }
00901                 }
00902                 CTX_DATA_END;
00903         }
00904 
00905         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
00906                 /* this is a bit dodjy, there should only be ONE object with this name, but library objects can mess this up */
00907                 if(strcmp(name, base->object->id.name+2)==0) {
00908                         ED_base_object_activate(C, base);
00909                         ED_base_object_select(base, BA_SELECT);
00910                         changed= 1;
00911                 }
00912         }
00913         CTX_DATA_END;
00914 
00915         MEM_freeN(name);
00916 
00917         /* undo? */
00918         if(changed) {
00919                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
00920                 return OPERATOR_FINISHED;
00921         }
00922         else {
00923                 return OPERATOR_CANCELLED;
00924         }
00925 }
00926 
00927 void OBJECT_OT_select_name(wmOperatorType *ot)
00928 {
00929 
00930         /* identifiers */
00931         ot->name= "Select Name";
00932         ot->description = "Select an object with this name";
00933         ot->idname= "OBJECT_OT_select_name";
00934 
00935         /* api callbacks */
00936         ot->exec= object_select_name_exec;
00937         ot->poll= ED_operator_objectmode;
00938 
00939         /* flags */
00940         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00941 
00942         RNA_def_string(ot->srna, "name", "", 0, "Name", "Object name to select.");
00943         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first.");
00944 }
00945 
00946 /**************************** Select Random ****************************/
00947 
00948 static int object_select_random_exec(bContext *C, wmOperator *op)
00949 {       
00950         float percent;
00951         short extend;
00952         
00953         extend= RNA_boolean_get(op->ptr, "extend");
00954         
00955         if (extend == 0) {
00956                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
00957                         ED_base_object_select(base, BA_DESELECT);
00958                 }
00959                 CTX_DATA_END;
00960         }
00961         percent = RNA_float_get(op->ptr, "percent")/100.0f;
00962                 
00963         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
00964                 if (BLI_frand() < percent) {
00965                         ED_base_object_select(base, BA_SELECT);
00966                 }
00967         }
00968         CTX_DATA_END;
00969         
00970         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
00971         
00972         return OPERATOR_FINISHED;
00973 }
00974 
00975 void OBJECT_OT_select_random(wmOperatorType *ot)
00976 {
00977         /* identifiers */
00978         ot->name= "Select Random";
00979         ot->description = "Set select on random visible objects";
00980         ot->idname= "OBJECT_OT_select_random";
00981         
00982         /* api callbacks */
00983         /*ot->invoke= object_select_random_invoke XXX - need a number popup ;*/
00984         ot->exec = object_select_random_exec;
00985         ot->poll= ED_operator_objectmode;
00986         
00987         /* flags */
00988         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00989         
00990         /* properties */
00991         RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, "Percent", "Percentage of objects to select randomly", 0.f, 100.0f);
00992         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend Selection", "Extend selection instead of deselecting everything first.");
00993 }
00994 
00995