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