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