Longer names support for all ID and other object names
[blender.git] / source / blender / editors / object / object_select.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation, 2002-2008 full recode
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/object/object_select.c
27  *  \ingroup edobj
28  */
29
30
31 #include <ctype.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "DNA_anim_types.h"
39 #include "DNA_group_types.h"
40 #include "DNA_material_types.h"
41 #include "DNA_modifier_types.h"
42 #include "DNA_property_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_armature_types.h"
45
46 #include "BLI_math.h"
47 #include "BLI_listbase.h"
48 #include "BLI_rand.h"
49 #include "BLI_string.h"
50 #include "BLI_utildefines.h"
51
52 #include "BKE_context.h"
53 #include "BKE_group.h"
54 #include "BKE_main.h"
55 #include "BKE_material.h"
56 #include "BKE_particle.h"
57 #include "BKE_property.h"
58 #include "BKE_report.h"
59 #include "BKE_scene.h"
60 #include "BKE_library.h"
61 #include "BKE_deform.h"
62
63 #include "WM_api.h"
64 #include "WM_types.h"
65
66 #include "ED_object.h"
67 #include "ED_screen.h"
68 #include "ED_keyframing.h"
69
70 #include "UI_interface.h"
71 #include "UI_resources.h"
72
73 #include "RNA_access.h"
74 #include "RNA_define.h"
75 #include "RNA_enum_types.h"
76
77 #include "object_intern.h"
78
79 /************************ Exported **************************/
80
81 /* simple API for object selection, rather than just using the flag
82  * this takes into account the 'restrict selection in 3d view' flag.
83  * deselect works always, the restriction just prevents selection */
84
85 /* Note: send a NC_SCENE|ND_OB_SELECT notifier yourself! (or 
86  * or a NC_SCENE|ND_OB_VISIBLE in case of visibility toggling */
87
88 void ED_base_object_select(Base *base, short mode)
89 {
90         if (base) {
91                 if (mode==BA_SELECT) {
92                         if (!(base->object->restrictflag & OB_RESTRICT_SELECT))
93                                 base->flag |= SELECT;
94                 }
95                 else if (mode==BA_DESELECT) {
96                         base->flag &= ~SELECT;
97                 }
98                 base->object->flag= base->flag;
99         }
100 }
101
102 /* also to set active NULL */
103 void ED_base_object_activate(bContext *C, Base *base)
104 {
105         Scene *scene= CTX_data_scene(C);
106         
107         /* sets scene->basact */
108         BASACT= base;
109         
110         if(base) {
111                 
112                 /* XXX old signals, remember to handle notifiers now! */
113                 //              select_actionchannel_by_name(base->object->action, "Object", 1);
114                 
115                 WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);
116         }
117         else
118                 WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, NULL);
119 }
120
121 /********************** Selection Operators **********************/
122
123 static int objects_selectable_poll(bContext *C)
124 {
125         /* we don't check for linked scenes here, selection is
126            still allowed then for inspection of scene */
127         Object *obact= CTX_data_active_object(C);
128
129         if(CTX_data_edit_object(C))
130                 return 0;
131         if(obact && obact->mode)
132                 return 0;
133         
134         return 1;
135 }
136
137 /************************ Select by Type *************************/
138
139 static int object_select_by_type_exec(bContext *C, wmOperator *op)
140 {
141         short obtype, extend;
142         
143         obtype = RNA_enum_get(op->ptr, "type");
144         extend= RNA_boolean_get(op->ptr, "extend");
145                 
146         if (extend == 0) {
147                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
148                         ED_base_object_select(base, BA_DESELECT);
149                 }
150                 CTX_DATA_END;
151         }
152         
153         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
154                 if(base->object->type==obtype) {
155                         ED_base_object_select(base, BA_SELECT);
156                 }
157         }
158         CTX_DATA_END;
159         
160         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
161         
162         return OPERATOR_FINISHED;
163 }
164
165 void OBJECT_OT_select_by_type(wmOperatorType *ot)
166 {
167         /* identifiers */
168         ot->name= "Select By Type";
169         ot->description = "Select all visible objects that are of a type";
170         ot->idname= "OBJECT_OT_select_by_type";
171         
172         /* api callbacks */
173         ot->invoke= WM_menu_invoke;
174         ot->exec= object_select_by_type_exec;
175         ot->poll= objects_selectable_poll;
176         
177         /* flags */
178         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
179         
180         /* properties */
181         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
182         ot->prop= RNA_def_enum(ot->srna, "type", object_type_items, 1, "Type", "");
183 }
184
185 /*********************** Selection by Links *********************/
186
187 static EnumPropertyItem prop_select_linked_types[] = {
188         //{1, "IPO", 0, "Object IPO", ""}, // XXX depreceated animation system stuff...
189         {2, "OBDATA", 0, "Object Data", ""},
190         {3, "MATERIAL", 0, "Material", ""},
191         {4, "TEXTURE", 0, "Texture", ""},
192         {5, "DUPGROUP", 0, "Dupligroup", ""},
193         {6, "PARTICLE", 0, "Particle System", ""},
194         {7, "LIBRARY", 0, "Library", ""},
195         {8, "LIBRARY_OBDATA", 0, "Library (Object Data)", ""},
196         {0, NULL, 0, NULL, NULL}
197 };
198
199 static int object_select_linked_exec(bContext *C, wmOperator *op)
200 {
201         Scene *scene= CTX_data_scene(C);
202         Object *ob;
203         void *obdata = NULL;
204         Material *mat = NULL, *mat1;
205         Tex *tex= NULL;
206         int a, b;
207         int nr = RNA_enum_get(op->ptr, "type");
208         short changed = 0, extend;
209         /* events (nr):
210          * Object Ipo: 1
211          * ObData: 2
212          * Current Material: 3
213          * Current Texture: 4
214          * DupliGroup: 5
215          * PSys: 6
216          */
217
218         extend= RNA_boolean_get(op->ptr, "extend");
219         
220         if (extend == 0) {
221                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
222                         ED_base_object_select(base, BA_DESELECT);
223                 }
224                 CTX_DATA_END;
225         }
226         
227         ob= OBACT;
228         if(ob==NULL){ 
229                 BKE_report(op->reports, RPT_ERROR, "No Active Object");
230                 return OPERATOR_CANCELLED;
231         }
232         
233         if(nr==1) {     
234                         // XXX old animation system
235                 //ipo= ob->ipo;
236                 //if(ipo==0) return OPERATOR_CANCELLED;
237                 return OPERATOR_CANCELLED;
238         }
239         else if(nr==2) {
240                 if(ob->data==NULL) return OPERATOR_CANCELLED;
241                 obdata= ob->data;
242         }
243         else if(nr==3 || nr==4) {
244                 mat= give_current_material(ob, ob->actcol);
245                 if(mat==NULL) return OPERATOR_CANCELLED;
246                 if(nr==4) {
247                         if(mat->mtex[ (int)mat->texact ]) tex= mat->mtex[ (int)mat->texact ]->tex;
248                         if(tex==NULL) return OPERATOR_CANCELLED;
249                 }
250         }
251         else if(nr==5) {
252                 if(ob->dup_group==NULL) return OPERATOR_CANCELLED;
253         }
254         else if(nr==6) {
255                 if(ob->particlesystem.first==NULL) return OPERATOR_CANCELLED;
256         }
257         else if(nr==7) {
258                 /* do nothing */
259         }
260         else if(nr==8) {
261                 if(ob->data==NULL) return OPERATOR_CANCELLED;
262         }
263         else
264                 return OPERATOR_CANCELLED;
265         
266         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
267                 if(nr==1) {
268                                 // XXX old animation system
269                         //if(base->object->ipo==ipo) base->flag |= SELECT;
270                         //changed = 1;
271                 }
272                 else if(nr==2) {
273                         if(base->object->data==obdata) base->flag |= SELECT;
274                         changed = 1;
275                 }
276                 else if(nr==3 || nr==4) {
277                         ob= base->object;
278                         
279                         for(a=1; a<=ob->totcol; a++) {
280                                 mat1= give_current_material(ob, a);
281                                 if(nr==3) {
282                                         if(mat1==mat) base->flag |= SELECT;
283                                         changed = 1;
284                                 }
285                                 else if(mat1 && nr==4) {
286                                         for(b=0; b<MAX_MTEX; b++) {
287                                                 if(mat1->mtex[b]) {
288                                                         if(tex==mat1->mtex[b]->tex) {
289                                                                 base->flag |= SELECT;
290                                                                 changed = 1;
291                                                                 break;
292                                                         }
293                                                 }
294                                         }
295                                 }
296                         }
297                 }
298                 else if(nr==5) {
299                         if(base->object->dup_group==ob->dup_group) {
300                                 base->flag |= SELECT;
301                                 changed = 1;
302                         }
303                 }
304                 else if(nr==6) {
305                         /* loop through other, then actives particles*/
306                         ParticleSystem *psys;
307                         ParticleSystem *psys_act;
308                         
309                         for(psys=base->object->particlesystem.first; psys; psys=psys->next) {
310                                 for(psys_act=ob->particlesystem.first; psys_act; psys_act=psys_act->next) {
311                                         if (psys->part == psys_act->part) {
312                                                 base->flag |= SELECT;
313                                                 changed = 1;
314                                                 break;
315                                         }
316                                 }
317                                 
318                                 if (base->flag & SELECT) {
319                                         break;
320                                 }
321                         }
322                 }
323                 else if(nr==7) {
324                         if(ob->id.lib == base->object->id.lib) {
325                                 base->flag |= SELECT;
326                                 changed= 1;
327                         }
328                 }
329                 else if(nr==8) {
330                         if(base->object->data && ((ID *)ob->data)->lib == ((ID *)base->object->data)->lib) {
331                                 base->flag |= SELECT;
332                                 changed= 1;
333                         }
334                 }
335                 base->object->flag= base->flag;
336         }
337         CTX_DATA_END;
338         
339         if (changed) {
340                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
341                 return OPERATOR_FINISHED;
342         }
343         
344         return OPERATOR_CANCELLED;
345 }
346
347 void OBJECT_OT_select_linked(wmOperatorType *ot)
348 {
349         /* identifiers */
350         ot->name= "Select Linked";
351         ot->description = "Select all visible objects that are linked";
352         ot->idname= "OBJECT_OT_select_linked";
353         
354         /* api callbacks */
355         ot->invoke= WM_menu_invoke;
356         ot->exec= object_select_linked_exec;
357         ot->poll= objects_selectable_poll;
358         
359         /* flags */
360         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
361         
362         /* properties */
363         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
364         ot->prop= RNA_def_enum(ot->srna, "type", prop_select_linked_types, 0, "Type", "");
365 }
366
367 /*********************** Selected Grouped ********************/
368
369 static EnumPropertyItem prop_select_grouped_types[] = {
370         {1, "CHILDREN_RECURSIVE", 0, "Children", ""},
371         {2, "CHILDREN", 0, "Immediate Children", ""},
372         {3, "PARENT", 0, "Parent", ""},
373         {4, "SIBLINGS", 0, "Siblings", "Shared Parent"},
374         {5, "TYPE", 0, "Type", "Shared object type"},
375         {6, "LAYER", 0, "Layer", "Shared layers"},
376         {7, "GROUP", 0, "Group", "Shared group"},
377         {8, "HOOK", 0, "Hook", ""},
378         {9, "PASS", 0, "Pass", "Render pass Index"},
379         {10, "COLOR", 0, "Color", "Object Color"},
380         {11, "PROPERTIES", 0, "Properties", "Game Properties"},
381         {12, "KEYINGSET", 0, "Keying Set", "Objects included in active Keying Set"},
382         {0, NULL, 0, NULL, NULL}
383 };
384
385 static short select_grouped_children(bContext *C, Object *ob, int recursive)
386 {
387         short changed = 0;
388
389         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
390                 if (ob == base->object->parent) {
391                         if (!(base->flag & SELECT)) {
392                                 ED_base_object_select(base, BA_SELECT);
393                                 changed = 1;
394                         }
395
396                         if (recursive)
397                                 changed |= select_grouped_children(C, base->object, 1);
398                 }
399         }
400         CTX_DATA_END;
401         return changed;
402 }
403
404 static short select_grouped_parent(bContext *C) /* Makes parent active and de-selected OBACT */
405 {
406         Scene *scene= CTX_data_scene(C);
407         View3D *v3d= CTX_wm_view3d(C);
408
409         short changed = 0;
410         Base *baspar, *basact= CTX_data_active_base(C);
411
412         if (!basact || !(basact->object->parent)) return 0; /* we know OBACT is valid */
413
414         baspar= object_in_scene(basact->object->parent, scene);
415
416         /* can be NULL if parent in other scene */
417         if(baspar && BASE_SELECTABLE(v3d, baspar)) {
418                 ED_base_object_select(basact, BA_DESELECT);
419                 ED_base_object_select(baspar, BA_SELECT);
420                 ED_base_object_activate(C, baspar);
421                 changed = 1;
422         }
423         return changed;
424 }
425
426
427 #define GROUP_MENU_MAX  24
428 static short select_grouped_group(bContext *C, Object *ob)      /* Select objects in the same group as the active */
429 {
430         short changed = 0;
431         Group *group, *ob_groups[GROUP_MENU_MAX];
432         int group_count=0, i;
433         uiPopupMenu *pup;
434         uiLayout *layout;
435
436         for (group=CTX_data_main(C)->group.first; group && group_count < GROUP_MENU_MAX; group=group->id.next) {
437                 if (object_in_group (ob, group)) {
438                         ob_groups[group_count] = group;
439                         group_count++;
440                 }
441         }
442
443         if (!group_count)
444                 return 0;
445         else if (group_count == 1) {
446                 group = ob_groups[0];
447                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
448                         if (!(base->flag & SELECT) && object_in_group(base->object, group)) {
449                                 ED_base_object_select(base, BA_SELECT);
450                                 changed = 1;
451                         }
452                 }
453                 CTX_DATA_END;
454                 return changed;
455         }
456
457         /* build the menu. */
458         pup= uiPupMenuBegin(C, "Select Group", ICON_NONE);
459         layout= uiPupMenuLayout(pup);
460
461         for (i=0; i<group_count; i++) {
462                 group = ob_groups[i];
463                 uiItemStringO(layout, group->id.name+2, 0, "OBJECT_OT_select_same_group", "group", group->id.name);
464         }
465
466         uiPupMenuEnd(C, pup);
467         return changed; // The operator already handle this!
468 }
469
470 static short select_grouped_object_hooks(bContext *C, Object *ob)
471 {
472         Scene *scene= CTX_data_scene(C);
473         View3D *v3d= CTX_wm_view3d(C);
474
475         short changed = 0;
476         Base *base;
477         ModifierData *md;
478         HookModifierData *hmd;
479
480         for (md = ob->modifiers.first; md; md=md->next) {
481                 if (md->type==eModifierType_Hook) {
482                         hmd= (HookModifierData*) md;
483                         if (hmd->object && !(hmd->object->flag & SELECT)) {
484                                 base= object_in_scene(hmd->object, scene);
485                                 if (base && (BASE_SELECTABLE(v3d, base))) {
486                                         ED_base_object_select(base, BA_SELECT);
487                                         changed = 1;
488                                 }
489                         }
490                 }
491         }
492         return changed;
493 }
494
495 /* Select objects woth the same parent as the active (siblings),
496  * parent can be NULL also */
497 static short select_grouped_siblings(bContext *C, Object *ob)
498 {
499         short changed = 0;
500
501         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
502                 if ((base->object->parent==ob->parent)  && !(base->flag & SELECT)) {
503                         ED_base_object_select(base, BA_SELECT);
504                         changed = 1;
505                 }
506         }
507         CTX_DATA_END;
508         return changed;
509 }
510
511 static short select_grouped_type(bContext *C, Object *ob)
512 {
513         short changed = 0;
514
515         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
516                 if ((base->object->type == ob->type) && !(base->flag & SELECT)) {
517                         ED_base_object_select(base, BA_SELECT);
518                         changed = 1;
519                 }
520         }
521         CTX_DATA_END;
522         return changed;
523 }
524
525 static short select_grouped_layer(bContext *C, Object *ob)
526 {
527         char changed = 0;
528
529         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
530                 if ((base->lay & ob->lay) && !(base->flag & SELECT)) {
531                         ED_base_object_select(base, BA_SELECT);
532                         changed = 1;
533                 }
534         }
535         CTX_DATA_END;
536         return changed;
537 }
538
539 static short select_grouped_index_object(bContext *C, Object *ob)
540 {
541         char changed = 0;
542
543         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
544                 if ((base->object->index == ob->index) && !(base->flag & SELECT)) {
545                         ED_base_object_select(base, BA_SELECT);
546                         changed = 1;
547                 }
548         }
549         CTX_DATA_END;
550         return changed;
551 }
552
553 static short select_grouped_color(bContext *C, Object *ob)
554 {
555         char changed = 0;
556
557         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
558                 if (!(base->flag & SELECT) && (compare_v3v3(base->object->col, ob->col, 0.005f))) {
559                         ED_base_object_select(base, BA_SELECT);
560                         changed = 1;
561                 }
562         }
563         CTX_DATA_END;
564         return changed;
565 }
566
567 static short objects_share_gameprop(Object *a, Object *b)
568 {
569         bProperty *prop;
570         /*make a copy of all its properties*/
571
572         for( prop= a->prop.first; prop; prop = prop->next ) {
573                 if ( get_ob_property(b, prop->name) )
574                         return 1;
575         }
576         return 0;
577 }
578
579 static short select_grouped_gameprops(bContext *C, Object *ob)
580 {
581         char changed = 0;
582
583         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
584                 if (!(base->flag & SELECT) && (objects_share_gameprop(base->object, ob))) {
585                         ED_base_object_select(base, BA_SELECT);
586                         changed = 1;
587                 }
588         }
589         CTX_DATA_END;
590         return changed;
591 }
592
593 static short select_grouped_keyingset(bContext *C, Object *UNUSED(ob))
594 {
595         KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C));
596         short changed = 0;
597         
598         /* firstly, validate KeyingSet */
599         if ((ks == NULL) || (ANIM_validate_keyingset(C, NULL, ks) != 0))
600                 return 0;
601         
602         /* select each object that Keying Set refers to */
603         // TODO: perhaps to be more in line with the rest of these, we should only take objects 
604         // if the passed in object is included in this too
605         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) 
606         {
607                 /* only check for this object if it isn't selected already, to limit time wasted */
608                 if ((base->flag & SELECT) == 0) {
609                         KS_Path *ksp;
610                         
611                         /* this is the slow way... we could end up with > 500 items here, 
612                          * with none matching, but end up doing this on 1000 objects...
613                          */
614                         for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
615                                 /* if id matches, select then stop looping (match found) */
616                                 if (ksp->id == (ID *)base->object) {
617                                         ED_base_object_select(base, BA_SELECT);
618                                         changed = 1;
619                                         break;
620                                 }
621                         }
622                 }
623         }
624         CTX_DATA_END;
625                 
626         return changed;
627 }
628
629 static int object_select_grouped_exec(bContext *C, wmOperator *op)
630 {
631         Scene *scene= CTX_data_scene(C);
632         Object *ob;
633         int nr = RNA_enum_get(op->ptr, "type");
634         short changed = 0, extend;
635
636         extend= RNA_boolean_get(op->ptr, "extend");
637         
638         if (extend == 0) {
639                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
640                         ED_base_object_select(base, BA_DESELECT);
641                         changed = 1;
642                 }
643                 CTX_DATA_END;
644         }
645         
646         ob= OBACT;
647         if(ob==NULL) { 
648                 BKE_report(op->reports, RPT_ERROR, "No Active Object");
649                 return OPERATOR_CANCELLED;
650         }
651         
652         if(nr==1)               changed |= select_grouped_children(C, ob, 1);
653         else if(nr==2)  changed |= select_grouped_children(C, ob, 0);
654         else if(nr==3)  changed |= select_grouped_parent(C);
655         else if(nr==4)  changed |= select_grouped_siblings(C, ob);
656         else if(nr==5)  changed |= select_grouped_type(C, ob);
657         else if(nr==6)  changed |= select_grouped_layer(C, ob);
658         else if(nr==7)  changed |= select_grouped_group(C, ob);
659         else if(nr==8)  changed |= select_grouped_object_hooks(C, ob);
660         else if(nr==9)  changed |= select_grouped_index_object(C, ob);
661         else if(nr==10) changed |= select_grouped_color(C, ob);
662         else if(nr==11) changed |= select_grouped_gameprops(C, ob);
663         else if(nr==12) changed |= select_grouped_keyingset(C, ob);
664         
665         if (changed) {
666                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
667                 return OPERATOR_FINISHED;
668         }
669         
670         return OPERATOR_CANCELLED;
671 }
672
673 void OBJECT_OT_select_grouped(wmOperatorType *ot)
674 {
675         /* identifiers */
676         ot->name= "Select Grouped";
677         ot->description = "Select all visible objects grouped by various properties";
678         ot->idname= "OBJECT_OT_select_grouped";
679         
680         /* api callbacks */
681         ot->invoke= WM_menu_invoke;
682         ot->exec= object_select_grouped_exec;
683         ot->poll= objects_selectable_poll;
684         
685         /* flags */
686         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
687         
688         /* properties */
689         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
690         ot->prop= RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
691 }
692
693 /************************* Select by Layer **********************/
694
695 static int object_select_by_layer_exec(bContext *C, wmOperator *op)
696 {
697         unsigned int layernum;
698         short extend;
699         
700         extend= RNA_boolean_get(op->ptr, "extend");
701         layernum = RNA_int_get(op->ptr, "layers");
702         
703         if (extend == 0) {
704                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
705                         ED_base_object_select(base, BA_DESELECT);
706                 }
707                 CTX_DATA_END;
708         }
709                 
710         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
711                 if(base->lay == (1<< (layernum -1)))
712                         ED_base_object_select(base, BA_SELECT);
713         }
714         CTX_DATA_END;
715         
716         /* undo? */
717         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
718         
719         return OPERATOR_FINISHED;
720 }
721
722 void OBJECT_OT_select_by_layer(wmOperatorType *ot)
723 {
724         /* identifiers */
725         ot->name= "Select by Layer";
726         ot->description = "Select all visible objects on a layer";
727         ot->idname= "OBJECT_OT_select_by_layer";
728         
729         /* api callbacks */
730         /*ot->invoke = XXX - need a int grid popup*/
731         ot->exec= object_select_by_layer_exec;
732         ot->poll= objects_selectable_poll;
733         
734         /* flags */
735         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
736         
737         /* properties */
738         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
739         RNA_def_int(ot->srna, "layers", 1, 1, 20, "Layer", "", 1, 20);
740 }
741
742 /************************** Select Inverse *************************/
743
744 static int object_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
745 {
746         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
747                 if (base->flag & SELECT)
748                         ED_base_object_select(base, BA_DESELECT);
749                 else
750                         ED_base_object_select(base, BA_SELECT);
751         }
752         CTX_DATA_END;
753         
754         /* undo? */
755         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
756         
757         return OPERATOR_FINISHED;
758 }
759
760 void OBJECT_OT_select_inverse(wmOperatorType *ot)
761 {
762         
763         /* identifiers */
764         ot->name= "Select Inverse";
765         ot->description = "Invert selection of all visible objects";
766         ot->idname= "OBJECT_OT_select_inverse";
767         
768         /* api callbacks */
769         ot->exec= object_select_inverse_exec;
770         ot->poll= objects_selectable_poll;
771         
772         /* flags */
773         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
774         
775 }
776
777 /**************************** (De)select All ****************************/
778
779 static int object_select_all_exec(bContext *C, wmOperator *op)
780 {
781         int action = RNA_enum_get(op->ptr, "action");
782         
783         /* passthrough if no objects are visible */
784         if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH;
785
786         if (action == SEL_TOGGLE) {
787                 action = SEL_SELECT;
788                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
789                         if (base->flag & SELECT) {
790                                 action = SEL_DESELECT;
791                                 break;
792                         }
793                 }
794                 CTX_DATA_END;
795         }
796
797         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
798                 switch (action) {
799                 case SEL_SELECT:
800                         ED_base_object_select(base, BA_SELECT);
801                         break;
802                 case SEL_DESELECT:
803                         ED_base_object_select(base, BA_DESELECT);
804                         break;
805                 case SEL_INVERT:
806                         if (base->flag & SELECT) {
807                                 ED_base_object_select(base, BA_DESELECT);
808                         } else {
809                                 ED_base_object_select(base, BA_SELECT);
810                         }
811                         break;
812                 }
813         }
814         CTX_DATA_END;
815         
816         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
817         
818         return OPERATOR_FINISHED;
819 }
820
821 void OBJECT_OT_select_all(wmOperatorType *ot)
822 {
823         
824         /* identifiers */
825         ot->name= "Select or Deselect All";
826         ot->description = "Change selection of all visible objects in scene";
827         ot->idname= "OBJECT_OT_select_all";
828         
829         /* api callbacks */
830         ot->exec= object_select_all_exec;
831         ot->poll= objects_selectable_poll;
832         
833         /* flags */
834         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
835
836         WM_operator_properties_select_all(ot);
837 }
838
839 /**************************** Select In The Same Group ****************************/
840
841 static int object_select_same_group_exec(bContext *C, wmOperator *op)
842 {
843         Group *group;
844         char group_name[MAX_ID_NAME];
845
846         /* passthrough if no objects are visible */
847         if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH;
848
849         RNA_string_get(op->ptr, "group", group_name);
850
851         for (group=CTX_data_main(C)->group.first;       group; group=group->id.next) {
852                 if (!strcmp(group->id.name, group_name))
853                         break;
854         }
855
856         if (!group)
857                 return OPERATOR_PASS_THROUGH;
858
859         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
860                 if (!(base->flag & SELECT) && object_in_group(base->object, group))
861                         ED_base_object_select(base, BA_SELECT);
862         }
863         CTX_DATA_END;
864
865         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
866         
867         return OPERATOR_FINISHED;
868 }
869
870 void OBJECT_OT_select_same_group(wmOperatorType *ot)
871 {
872         
873         /* identifiers */
874         ot->name= "Select Same Group";
875         ot->description = "Select object in the same group";
876         ot->idname= "OBJECT_OT_select_same_group";
877         
878         /* api callbacks */
879         ot->exec= object_select_same_group_exec;
880         ot->poll= objects_selectable_poll;
881         
882         /* flags */
883         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
884
885         RNA_def_string(ot->srna, "group", "", MAX_ID_NAME, "Group", "Name of the group to select");
886 }
887
888 /**************************** Select Mirror ****************************/
889 static int object_select_mirror_exec(bContext *C, wmOperator *op)
890 {
891         Scene *scene= CTX_data_scene(C);
892         short extend;
893         
894         extend= RNA_boolean_get(op->ptr, "extend");
895         
896         CTX_DATA_BEGIN(C, Base*, primbase, selected_bases) {
897                 char tmpname[MAXBONENAME];
898
899                 flip_side_name(tmpname, primbase->object->id.name+2, TRUE);
900                 
901                 if(strcmp(tmpname, primbase->object->id.name+2)!=0) { /* names differ */
902                         Object *ob= (Object *)find_id("OB", tmpname);
903                         if(ob) {
904                                 Base *secbase= object_in_scene(ob, scene);
905
906                                 if(secbase) {
907                                         ED_base_object_select(secbase, BA_SELECT);
908                                 }
909                         }
910                 }
911                 
912                 if (extend == 0) ED_base_object_select(primbase, BA_DESELECT);
913                 
914         }
915         CTX_DATA_END;
916         
917         /* undo? */
918         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
919         
920         return OPERATOR_FINISHED;
921 }
922
923 void OBJECT_OT_select_mirror(wmOperatorType *ot)
924 {
925         
926         /* identifiers */
927         ot->name= "Select Mirror";
928         ot->description = "Select the Mirror objects of the selected object eg. L.sword -> R.sword";
929         ot->idname= "OBJECT_OT_select_mirror";
930         
931         /* api callbacks */
932         ot->exec= object_select_mirror_exec;
933         ot->poll= objects_selectable_poll;
934         
935         /* flags */
936         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
937         
938         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first");
939 }
940
941
942 /**************************** Select Random ****************************/
943
944 static int object_select_random_exec(bContext *C, wmOperator *op)
945 {       
946         float percent;
947         short extend;
948         
949         extend= RNA_boolean_get(op->ptr, "extend");
950         
951         if (extend == 0) {
952                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
953                         ED_base_object_select(base, BA_DESELECT);
954                 }
955                 CTX_DATA_END;
956         }
957         percent = RNA_float_get(op->ptr, "percent")/100.0f;
958                 
959         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
960                 if (BLI_frand() < percent) {
961                         ED_base_object_select(base, BA_SELECT);
962                 }
963         }
964         CTX_DATA_END;
965         
966         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
967         
968         return OPERATOR_FINISHED;
969 }
970
971 void OBJECT_OT_select_random(wmOperatorType *ot)
972 {
973         /* identifiers */
974         ot->name= "Select Random";
975         ot->description = "Set select on random visible objects";
976         ot->idname= "OBJECT_OT_select_random";
977         
978         /* api callbacks */
979         /*ot->invoke= object_select_random_invoke XXX - need a number popup ;*/
980         ot->exec = object_select_random_exec;
981         ot->poll= objects_selectable_poll;
982         
983         /* flags */
984         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
985         
986         /* properties */
987         RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, "Percent", "Percentage of objects to select randomly", 0.f, 100.0f);
988         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend Selection", "Extend selection instead of deselecting everything first");
989 }
990
991