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