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