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