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