- rna/python api object.create_render_mesh(...) support for getting a mesh from metab...
[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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 "DNA_group_types.h"
34 #include "DNA_material_types.h"
35 #include "DNA_modifier_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_property_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_texture_types.h"
40
41 #include "BLI_arithb.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_object.h"
62 #include "ED_screen.h"
63
64 #include "RNA_access.h"
65 #include "RNA_define.h"
66 #include "RNA_enum_types.h"
67
68 #include "object_intern.h"
69
70 /************************ Exported **************************/
71
72 /* simple API for object selection, rather than just using the flag
73  * this takes into account the 'restrict selection in 3d view' flag.
74  * deselect works always, the restriction just prevents selection */
75
76 /* Note: send a NC_SCENE|ND_OB_SELECT notifier yourself! */
77
78 void ED_base_object_select(Base *base, short mode)
79 {
80         if (base) {
81                 if (mode==BA_SELECT) {
82                         if (!(base->object->restrictflag & OB_RESTRICT_SELECT))
83                                 if (mode==BA_SELECT) base->flag |= SELECT;
84                 }
85                 else if (mode==BA_DESELECT) {
86                         base->flag &= ~SELECT;
87                 }
88                 base->object->flag= base->flag;
89         }
90 }
91
92 /* also to set active NULL */
93 void ED_base_object_activate(bContext *C, Base *base)
94 {
95         Scene *scene= CTX_data_scene(C);
96         Base *tbase;
97         
98         /* sets scene->basact */
99         BASACT= base;
100         
101         if(base) {
102                 
103                 /* XXX old signals, remember to handle notifiers now! */
104                 //              select_actionchannel_by_name(base->object->action, "Object", 1);
105                 
106                 /* disable temporal locks */
107                 for(tbase=FIRSTBASE; tbase; tbase= tbase->next) {
108                         if(base!=tbase && (tbase->object->shapeflag & OB_SHAPE_TEMPLOCK)) {
109                                 tbase->object->shapeflag &= ~OB_SHAPE_TEMPLOCK;
110                                 DAG_id_flush_update(&tbase->object->id, OB_RECALC_DATA);
111                         }
112                 }
113                 WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);
114         }
115         else
116                 WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, NULL);
117 }
118
119 /********************** Selection Operators **********************/
120
121 /************************ Select by Type *************************/
122
123 static int object_select_by_type_exec(bContext *C, wmOperator *op)
124 {
125         short obtype, extend;
126         
127         obtype = RNA_enum_get(op->ptr, "type");
128         extend= RNA_boolean_get(op->ptr, "extend");
129                 
130         if (extend == 0) {
131                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
132                         ED_base_object_select(base, BA_DESELECT);
133                 }
134                 CTX_DATA_END;
135         }
136         
137         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
138                 if(base->object->type==obtype) {
139                         ED_base_object_select(base, BA_SELECT);
140                 }
141         }
142         CTX_DATA_END;
143         
144         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
145         
146         return OPERATOR_FINISHED;
147 }
148
149 void OBJECT_OT_select_by_type(wmOperatorType *ot)
150 {
151         /* identifiers */
152         ot->name= "Select By Type";
153         ot->description = "Select all visible objects that are of a type.";
154         ot->idname= "OBJECT_OT_select_by_type";
155         
156         /* api callbacks */
157         ot->invoke= WM_menu_invoke;
158         ot->exec= object_select_by_type_exec;
159         ot->poll= ED_operator_scene_editable;
160         
161         /* flags */
162         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
163         
164         /* properties */
165         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first.");
166         RNA_def_enum(ot->srna, "type", object_type_items, 1, "Type", "");
167 }
168
169 /*********************** Selection by Links *********************/
170
171 static EnumPropertyItem prop_select_linked_types[] = {
172         {1, "IPO", 0, "Object IPO", ""}, // XXX depreceated animation system stuff...
173         {2, "OBDATA", 0, "Ob Data", ""},
174         {3, "MATERIAL", 0, "Material", ""},
175         {4, "TEXTURE", 0, "Texture", ""},
176         {5, "DUPGROUP", 0, "Dupligroup", ""},
177         {6, "PARTICLE", 0, "Particle System", ""},
178         {0, NULL, 0, NULL, NULL}
179 };
180
181 static int object_select_linked_exec(bContext *C, wmOperator *op)
182 {
183         Scene *scene= CTX_data_scene(C);
184         Object *ob;
185         void *obdata = NULL;
186         Material *mat = NULL, *mat1;
187         Tex *tex=0;
188         int a, b;
189         int nr = RNA_enum_get(op->ptr, "type");
190         short changed = 0, extend;
191         /* events (nr):
192          * Object Ipo: 1
193          * ObData: 2
194          * Current Material: 3
195          * Current Texture: 4
196          * DupliGroup: 5
197          * PSys: 6
198          */
199
200         extend= RNA_boolean_get(op->ptr, "extend");
201         
202         if (extend == 0) {
203                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
204                         ED_base_object_select(base, BA_DESELECT);
205                 }
206                 CTX_DATA_END;
207         }
208         
209         ob= OBACT;
210         if(ob==0){ 
211                 BKE_report(op->reports, RPT_ERROR, "No Active Object");
212                 return OPERATOR_CANCELLED;
213         }
214         
215         if(nr==1) {     
216                         // XXX old animation system
217                 //ipo= ob->ipo;
218                 //if(ipo==0) return OPERATOR_CANCELLED;
219                 return OPERATOR_CANCELLED;
220         }
221         else if(nr==2) {
222                 if(ob->data==0) return OPERATOR_CANCELLED;
223                 obdata= ob->data;
224         }
225         else if(nr==3 || nr==4) {
226                 mat= give_current_material(ob, ob->actcol);
227                 if(mat==0) return OPERATOR_CANCELLED;
228                 if(nr==4) {
229                         if(mat->mtex[ (int)mat->texact ]) tex= mat->mtex[ (int)mat->texact ]->tex;
230                         if(tex==0) return OPERATOR_CANCELLED;
231                 }
232         }
233         else if(nr==5) {
234                 if(ob->dup_group==NULL) return OPERATOR_CANCELLED;
235         }
236         else if(nr==6) {
237                 if(ob->particlesystem.first==NULL) return OPERATOR_CANCELLED;
238         }
239         else 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                 base->object->flag= base->flag;
299         }
300         CTX_DATA_END;
301         
302         if (changed) {
303                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
304                 return OPERATOR_FINISHED;
305         }
306         
307         return OPERATOR_CANCELLED;
308 }
309
310 void OBJECT_OT_select_linked(wmOperatorType *ot)
311 {
312         /* identifiers */
313         ot->name= "Select Linked";
314         ot->description = "Select all visible objects that are linked.";
315         ot->idname= "OBJECT_OT_select_linked";
316         
317         /* api callbacks */
318         ot->invoke= WM_menu_invoke;
319         ot->exec= object_select_linked_exec;
320         ot->poll= ED_operator_scene_editable;
321         
322         /* flags */
323         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
324         
325         /* properties */
326         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first.");
327         RNA_def_enum(ot->srna, "type", prop_select_linked_types, 0, "Type", "");
328 }
329
330 /*********************** Selected Grouped ********************/
331
332 static EnumPropertyItem prop_select_grouped_types[] = {
333         {1, "CHILDREN_RECURSIVE", 0, "Children", ""},
334         {2, "CHILDREN", 0, "Immediate Children", ""},
335         {3, "PARENT", 0, "Parent", ""},
336         {4, "SIBLINGS", 0, "Siblings", "Shared Parent"},
337         {5, "TYPE", 0, "Type", "Shared object type"},
338         {6, "LAYER", 0, "Layer", "Shared layers"},
339         {7, "GROUP", 0, "Group", "Shared group"},
340         {8, "HOOK", 0, "Hook", ""},
341         {9, "PASS", 0, "Pass", "Render pass Index"},
342         {10, "COLOR", 0, "Color", "Object Color"},
343         {11, "PROPERTIES", 0, "Properties", "Game Properties"},
344         {0, NULL, 0, NULL, NULL}
345 };
346
347 static short select_grouped_children(bContext *C, Object *ob, int recursive)
348 {
349         short changed = 0;
350
351         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
352                 if (ob == base->object->parent) {
353                         if (!(base->flag & SELECT)) {
354                                 ED_base_object_select(base, BA_SELECT);
355                                 changed = 1;
356                         }
357
358                         if (recursive)
359                                 changed |= select_grouped_children(C, base->object, 1);
360                 }
361         }
362         CTX_DATA_END;
363         return changed;
364 }
365
366 static short select_grouped_parent(bContext *C) /* Makes parent active and de-selected OBACT */
367 {
368         Scene *scene= CTX_data_scene(C);
369         View3D *v3d= CTX_wm_view3d(C);
370
371         short changed = 0;
372         Base *baspar, *basact= CTX_data_active_base(C);
373
374         if (!basact || !(basact->object->parent)) return 0; /* we know OBACT is valid */
375
376         baspar= object_in_scene(basact->object->parent, scene);
377
378         /* can be NULL if parent in other scene */
379         if(baspar && BASE_SELECTABLE(v3d, baspar)) {
380                 ED_base_object_select(basact, BA_DESELECT);
381                 ED_base_object_select(baspar, BA_SELECT);
382                 ED_base_object_activate(C, baspar);
383                 changed = 1;
384         }
385         return changed;
386 }
387
388
389 #define GROUP_MENU_MAX  24
390 static short select_grouped_group(bContext *C, Object *ob)      /* Select objects in the same group as the active */
391 {
392         short changed = 0;
393         Group *group, *ob_groups[GROUP_MENU_MAX];
394         //char str[10 + (24*GROUP_MENU_MAX)];
395         //char *p = str;
396         int group_count=0; //, menu, i;
397
398         for (   group=G.main->group.first;
399                         group && group_count < GROUP_MENU_MAX;
400                         group=group->id.next
401                 ) {
402                 if (object_in_group (ob, group)) {
403                         ob_groups[group_count] = group;
404                         group_count++;
405                 }
406         }
407
408         if (!group_count)
409                 return 0;
410
411         else if (group_count == 1) {
412                 group = ob_groups[0];
413                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
414                         if (!(base->flag & SELECT) && object_in_group(base->object, group)) {
415                                 ED_base_object_select(base, BA_SELECT);
416                                 changed = 1;
417                         }
418                 }
419                 CTX_DATA_END;
420                 return changed;
421         }
422 #if 0 // XXX hows this work in 2.5?
423         /* build the menu. */
424         p += sprintf(str, "Groups%%t");
425         for (i=0; i<group_count; i++) {
426                 group = ob_groups[i];
427                 p += sprintf (p, "|%s%%x%i", group->id.name+2, i);
428         }
429
430         menu = pupmenu (str);
431         if (menu == -1)
432                 return 0;
433
434         group = ob_groups[menu];
435         for (base= FIRSTBASE; base; base= base->next) {
436                 if (!(base->flag & SELECT) && object_in_group(base->object, group)) {
437                         ED_base_object_select(base, BA_SELECT);
438                         changed = 1;
439                 }
440         }
441 #endif
442         return changed;
443 }
444
445 static short select_grouped_object_hooks(bContext *C, Object *ob)
446 {
447         Scene *scene= CTX_data_scene(C);
448         View3D *v3d= CTX_wm_view3d(C);
449
450         short changed = 0;
451         Base *base;
452         ModifierData *md;
453         HookModifierData *hmd;
454
455         for (md = ob->modifiers.first; md; md=md->next) {
456                 if (md->type==eModifierType_Hook) {
457                         hmd= (HookModifierData*) md;
458                         if (hmd->object && !(hmd->object->flag & SELECT)) {
459                                 base= object_in_scene(hmd->object, scene);
460                                 if (base && (BASE_SELECTABLE(v3d, base))) {
461                                         ED_base_object_select(base, BA_SELECT);
462                                         changed = 1;
463                                 }
464                         }
465                 }
466         }
467         return changed;
468 }
469
470 /* Select objects woth the same parent as the active (siblings),
471  * parent can be NULL also */
472 static short select_grouped_siblings(bContext *C, Object *ob)
473 {
474         short changed = 0;
475
476         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
477                 if ((base->object->parent==ob->parent)  && !(base->flag & SELECT)) {
478                         ED_base_object_select(base, BA_SELECT);
479                         changed = 1;
480                 }
481         }
482         CTX_DATA_END;
483         return changed;
484 }
485
486 static short select_grouped_type(bContext *C, Object *ob)
487 {
488         short changed = 0;
489
490         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
491                 if ((base->object->type == ob->type) && !(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_layer(bContext *C, Object *ob)
501 {
502         char changed = 0;
503
504         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
505                 if ((base->lay & ob->lay) && !(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_index_object(bContext *C, Object *ob)
515 {
516         char changed = 0;
517
518         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
519                 if ((base->object->index == ob->index) && !(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_color(bContext *C, Object *ob)
529 {
530         char changed = 0;
531
532         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
533                 if (!(base->flag & SELECT) && (FloatCompare(base->object->col, ob->col, 0.005f))) {
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 objects_share_gameprop(Object *a, Object *b)
543 {
544         bProperty *prop;
545         /*make a copy of all its properties*/
546
547         for( prop= a->prop.first; prop; prop = prop->next ) {
548                 if ( get_ob_property(b, prop->name) )
549                         return 1;
550         }
551         return 0;
552 }
553
554 static short select_grouped_gameprops(bContext *C, Object *ob)
555 {
556         char changed = 0;
557
558         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
559                 if (!(base->flag & SELECT) && (objects_share_gameprop(base->object, ob))) {
560                         ED_base_object_select(base, BA_SELECT);
561                         changed = 1;
562                 }
563         }
564         CTX_DATA_END;
565         return changed;
566 }
567
568 static int object_select_grouped_exec(bContext *C, wmOperator *op)
569 {
570         Scene *scene= CTX_data_scene(C);
571         Object *ob;
572         int nr = RNA_enum_get(op->ptr, "type");
573         short changed = 0, extend;
574
575         extend= RNA_boolean_get(op->ptr, "extend");
576         
577         if (extend == 0) {
578                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
579                         ED_base_object_select(base, BA_DESELECT);
580                 }
581                 CTX_DATA_END;
582         }
583         
584         ob= OBACT;
585         if(ob==0){ 
586                 BKE_report(op->reports, RPT_ERROR, "No Active Object");
587                 return OPERATOR_CANCELLED;
588         }
589         
590         if(nr==1)               changed = select_grouped_children(C, ob, 1);
591         else if(nr==2)  changed = select_grouped_children(C, ob, 0);
592         else if(nr==3)  changed = select_grouped_parent(C);
593         else if(nr==4)  changed = select_grouped_siblings(C, ob);
594         else if(nr==5)  changed = select_grouped_type(C, ob);
595         else if(nr==6)  changed = select_grouped_layer(C, ob);
596         else if(nr==7)  changed = select_grouped_group(C, ob);
597         else if(nr==8)  changed = select_grouped_object_hooks(C, ob);
598         else if(nr==9)  changed = select_grouped_index_object(C, ob);
599         else if(nr==10) changed = select_grouped_color(C, ob);
600         else if(nr==11) changed = select_grouped_gameprops(C, ob);
601         
602         if (changed) {
603                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
604                 return OPERATOR_FINISHED;
605         }
606         
607         return OPERATOR_CANCELLED;
608 }
609
610 void OBJECT_OT_select_grouped(wmOperatorType *ot)
611 {
612         /* identifiers */
613         ot->name= "Select Grouped";
614         ot->description = "Select all visible objects grouped by various properties.";
615         ot->idname= "OBJECT_OT_select_grouped";
616         
617         /* api callbacks */
618         ot->invoke= WM_menu_invoke;
619         ot->exec= object_select_grouped_exec;
620         ot->poll= ED_operator_scene_editable;
621         
622         /* flags */
623         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
624         
625         /* properties */
626         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first.");
627         RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
628 }
629
630 /************************* Select by Layer **********************/
631
632 static int object_select_by_layer_exec(bContext *C, wmOperator *op)
633 {
634         unsigned int layernum;
635         short extend;
636         
637         extend= RNA_boolean_get(op->ptr, "extend");
638         layernum = RNA_int_get(op->ptr, "layer");
639         
640         if (extend == 0) {
641                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
642                         ED_base_object_select(base, BA_DESELECT);
643                 }
644                 CTX_DATA_END;
645         }
646                 
647         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
648                 if(base->lay == (1<< (layernum -1)))
649                         ED_base_object_select(base, BA_SELECT);
650         }
651         CTX_DATA_END;
652         
653         /* undo? */
654         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
655         
656         return OPERATOR_FINISHED;
657 }
658
659 void OBJECT_OT_select_by_layer(wmOperatorType *ot)
660 {
661         /* identifiers */
662         ot->name= "select by layer";
663         ot->description = "Select all visible objects on a layer.";
664         ot->idname= "OBJECT_OT_select_by_layer";
665         
666         /* api callbacks */
667         /*ot->invoke = XXX - need a int grid popup*/
668         ot->exec= object_select_by_layer_exec;
669         ot->poll= ED_operator_scene_editable;
670         
671         /* flags */
672         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
673         
674         /* properties */
675         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first.");
676         RNA_def_int(ot->srna, "layer", 1, 1, 20, "Layer", "", 1, 20);
677 }
678
679 /************************** Select Inverse *************************/
680
681 static int object_select_inverse_exec(bContext *C, wmOperator *op)
682 {
683         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
684                 if (base->flag & SELECT)
685                         ED_base_object_select(base, BA_DESELECT);
686                 else
687                         ED_base_object_select(base, BA_SELECT);
688         }
689         CTX_DATA_END;
690         
691         /* undo? */
692         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
693         
694         return OPERATOR_FINISHED;
695 }
696
697 void OBJECT_OT_select_inverse(wmOperatorType *ot)
698 {
699         
700         /* identifiers */
701         ot->name= "Select Inverse";
702         ot->description = "Invert selection of all visible objects.";
703         ot->idname= "OBJECT_OT_select_inverse";
704         
705         /* api callbacks */
706         ot->exec= object_select_inverse_exec;
707         ot->poll= ED_operator_scene_editable;
708         
709         /* flags */
710         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
711         
712 }
713
714 /**************************** (De)select All ****************************/
715
716 static int object_select_de_select_all_exec(bContext *C, wmOperator *op)
717 {
718         
719         int a=0, ok=0; 
720         
721         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
722                 if (base->flag & SELECT) {
723                         ok= a= 1;
724                         break;
725                 }
726                 else ok=1;
727         }
728         CTX_DATA_END;
729         
730         if (!ok) return OPERATOR_PASS_THROUGH;
731         
732         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
733                 if (a) ED_base_object_select(base, BA_DESELECT);
734                 else ED_base_object_select(base, BA_SELECT);
735         }
736         CTX_DATA_END;
737         
738         /* undo? */
739         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
740         
741         return OPERATOR_FINISHED;
742 }
743
744 void OBJECT_OT_select_all_toggle(wmOperatorType *ot)
745 {
746         
747         /* identifiers */
748         ot->name= "deselect all";
749         ot->description = "(de)select all visible objects in scene.";
750         ot->idname= "OBJECT_OT_select_all_toggle";
751         
752         /* api callbacks */
753         ot->exec= object_select_de_select_all_exec;
754         ot->poll= ED_operator_scene_editable;
755         
756         /* flags */
757         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
758         
759 }
760
761 /**************************** Select Mirror ****************************/
762
763 /* finds the best possible flipped name. For renaming; check for unique names afterwards */
764 /* if strip_number: removes number extensions */
765 void object_flip_name (char *name)
766 {
767         int     len;
768         char    prefix[128]={""};   /* The part before the facing */
769         char    suffix[128]={""};   /* The part after the facing */
770         char    replace[128]={""};  /* The replacement string */
771         char    number[128]={""};   /* The number extension string */
772         char    *index=NULL;
773
774         len= strlen(name);
775         if(len<3) return; // we don't do names like .R or .L
776
777         /* We first check the case with a .### extension, let's find the last period */
778         if(isdigit(name[len-1])) {
779                 index= strrchr(name, '.'); // last occurrance
780                 if (index && isdigit(index[1]) ) { // doesnt handle case bone.1abc2 correct..., whatever!
781                         strcpy(number, index);
782                         *index= 0;
783                         len= strlen(name);
784                 }
785         }
786
787         strcpy (prefix, name);
788
789 #define IS_SEPARATOR(a) ((a)=='.' || (a)==' ' || (a)=='-' || (a)=='_')
790
791         /* first case; separator . - _ with extensions r R l L  */
792         if( IS_SEPARATOR(name[len-2]) ) {
793                 switch(name[len-1]) {
794                         case 'l':
795                                 prefix[len-1]= 0;
796                                 strcpy(replace, "r");
797                                 break;
798                         case 'r':
799                                 prefix[len-1]= 0;
800                                 strcpy(replace, "l");
801                                 break;
802                         case 'L':
803                                 prefix[len-1]= 0;
804                                 strcpy(replace, "R");
805                                 break;
806                         case 'R':
807                                 prefix[len-1]= 0;
808                                 strcpy(replace, "L");
809                                 break;
810                 }
811         }
812         /* case; beginning with r R l L , with separator after it */
813         else if( IS_SEPARATOR(name[1]) ) {
814                 switch(name[0]) {
815                         case 'l':
816                                 strcpy(replace, "r");
817                                 strcpy(suffix, name+1);
818                                 prefix[0]= 0;
819                                 break;
820                         case 'r':
821                                 strcpy(replace, "l");
822                                 strcpy(suffix, name+1);
823                                 prefix[0]= 0;
824                                 break;
825                         case 'L':
826                                 strcpy(replace, "R");
827                                 strcpy(suffix, name+1);
828                                 prefix[0]= 0;
829                                 break;
830                         case 'R':
831                                 strcpy(replace, "L");
832                                 strcpy(suffix, name+1);
833                                 prefix[0]= 0;
834                                 break;
835                 }
836         }
837         else if(len > 5) {
838                 /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
839                 index = BLI_strcasestr(prefix, "right");
840                 if (index==prefix || index==prefix+len-5) {
841                         if(index[0]=='r') 
842                                 strcpy (replace, "left");
843                         else {
844                                 if(index[1]=='I') 
845                                         strcpy (replace, "LEFT");
846                                 else
847                                         strcpy (replace, "Left");
848                         }
849                         *index= 0;
850                         strcpy (suffix, index+5);
851                 }
852                 else {
853                         index = BLI_strcasestr(prefix, "left");
854                         if (index==prefix || index==prefix+len-4) {
855                                 if(index[0]=='l') 
856                                         strcpy (replace, "right");
857                                 else {
858                                         if(index[1]=='E') 
859                                                 strcpy (replace, "RIGHT");
860                                         else
861                                                 strcpy (replace, "Right");
862                                 }
863                                 *index= 0;
864                                 strcpy (suffix, index+4);
865                         }
866                 }
867         }
868
869 #undef IS_SEPARATOR
870
871         sprintf (name, "%s%s%s%s", prefix, replace, suffix, number);
872 }
873
874 static int object_select_mirror_exec(bContext *C, wmOperator *op)
875 {
876         char tmpname[32];
877         short extend;
878         
879         extend= RNA_boolean_get(op->ptr, "extend");
880         
881         CTX_DATA_BEGIN(C, Base*, primbase, selected_bases) {
882
883                 strcpy(tmpname, primbase->object->id.name+2);
884                 object_flip_name(tmpname);
885                 
886                 CTX_DATA_BEGIN(C, Base*, secbase, visible_bases) {
887                         if(!strcmp(secbase->object->id.name+2, tmpname)) {
888                                 ED_base_object_select(secbase, BA_SELECT);
889                         }
890                 }
891                 CTX_DATA_END;
892                 
893                 if (extend == 0) ED_base_object_select(primbase, BA_DESELECT);
894                 
895         }
896         CTX_DATA_END;
897         
898         /* undo? */
899         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
900         
901         return OPERATOR_FINISHED;
902 }
903
904 void OBJECT_OT_select_mirror(wmOperatorType *ot)
905 {
906         
907         /* identifiers */
908         ot->name= "Select Mirror";
909         ot->description = "Select the Mirror objects of the selected object eg. L.sword -> R.sword";
910         ot->idname= "OBJECT_OT_select_mirror";
911         
912         /* api callbacks */
913         ot->exec= object_select_mirror_exec;
914         ot->poll= ED_operator_scene_editable;
915         
916         /* flags */
917         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
918         
919         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first.");
920 }
921
922
923 static int object_select_name_exec(bContext *C, wmOperator *op)
924 {
925         char *name= RNA_string_get_alloc(op->ptr, "name", NULL, 0);
926         short extend= RNA_boolean_get(op->ptr, "extend");
927         short changed = 0;
928
929         if(!extend) {
930                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
931                         ED_base_object_select(base, BA_DESELECT);
932                 }
933                 CTX_DATA_END;
934         }
935
936         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
937                 if(strcmp(name, base->object->id.name+2)==0) {
938                         ED_base_object_select(base, BA_SELECT);
939                         changed= 1;
940                 }
941         }
942         CTX_DATA_END;
943
944         MEM_freeN(name);
945
946         /* undo? */
947         if(changed) {
948                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
949                 return OPERATOR_FINISHED;
950         }
951         else {
952                 return OPERATOR_CANCELLED;
953         }
954 }
955
956 void OBJECT_OT_select_name(wmOperatorType *ot)
957 {
958
959         /* identifiers */
960         ot->name= "Select Name";
961         ot->description = "Select an object with this name";
962         ot->idname= "OBJECT_OT_select_name";
963
964         /* api callbacks */
965         ot->exec= object_select_name_exec;
966         ot->poll= ED_operator_scene_editable;
967
968         /* flags */
969         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
970
971         RNA_def_string(ot->srna, "name", "", 0, "Name", "Object name to select.");
972         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first.");
973 }
974
975 /**************************** Select Random ****************************/
976
977 static int object_select_random_exec(bContext *C, wmOperator *op)
978 {       
979         float percent;
980         short extend;
981         
982         extend= RNA_boolean_get(op->ptr, "extend");
983         
984         if (extend == 0) {
985                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
986                         ED_base_object_select(base, BA_DESELECT);
987                 }
988                 CTX_DATA_END;
989         }
990         percent = RNA_float_get(op->ptr, "percent");
991                 
992         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
993                 if (BLI_frand() < percent) {
994                                 ED_base_object_select(base, BA_SELECT);
995                 }
996         }
997         CTX_DATA_END;
998         
999         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1000         
1001         return OPERATOR_FINISHED;
1002 }
1003
1004 void OBJECT_OT_select_random(wmOperatorType *ot)
1005 {
1006         /* identifiers */
1007         ot->name= "Random select";
1008         ot->description = "Set select on random visible objects.";
1009         ot->idname= "OBJECT_OT_select_random";
1010         
1011         /* api callbacks */
1012         /*ot->invoke= object_select_random_invoke XXX - need a number popup ;*/
1013         ot->exec = object_select_random_exec;
1014         ot->poll= ED_operator_scene_editable;
1015         
1016         /* flags */
1017         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1018         
1019         /* properties */
1020         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first.");
1021         RNA_def_float_percentage(ot->srna, "percent", 0.5f, 0.0f, 1.0f, "Percent", "percentage of objects to randomly select", 0.0001f, 1.0f);
1022 }
1023
1024