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