Blender V2.61 - r43446

object_select.c

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