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