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