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