part 1 of merge from trunk at r30358; it compiles, but doesn't link quite yet :)
[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_group.h"
49 #include "BKE_main.h"
50 #include "BKE_material.h"
51 #include "BKE_particle.h"
52 #include "BKE_property.h"
53 #include "BKE_report.h"
54 #include "BKE_scene.h"
55 #include "BKE_utildefines.h"
56
57 #include "WM_api.h"
58 #include "WM_types.h"
59
60 #include "ED_screen.h"
61
62 #include "UI_interface.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                                 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         
97         /* sets scene->basact */
98         BASACT= base;
99         
100         if(base) {
101                 
102                 /* XXX old signals, remember to handle notifiers now! */
103                 //              select_actionchannel_by_name(base->object->action, "Object", 1);
104                 
105                 WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);
106         }
107         else
108                 WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, NULL);
109 }
110
111 /********************** Selection Operators **********************/
112
113 /************************ Select by Type *************************/
114
115 static int object_select_by_type_exec(bContext *C, wmOperator *op)
116 {
117         short obtype, extend;
118         
119         obtype = RNA_enum_get(op->ptr, "type");
120         extend= RNA_boolean_get(op->ptr, "extend");
121                 
122         if (extend == 0) {
123                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
124                         ED_base_object_select(base, BA_DESELECT);
125                 }
126                 CTX_DATA_END;
127         }
128         
129         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
130                 if(base->object->type==obtype) {
131                         ED_base_object_select(base, BA_SELECT);
132                 }
133         }
134         CTX_DATA_END;
135         
136         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
137         
138         return OPERATOR_FINISHED;
139 }
140
141 void OBJECT_OT_select_by_type(wmOperatorType *ot)
142 {
143         /* identifiers */
144         ot->name= "Select By Type";
145         ot->description = "Select all visible objects that are of a type";
146         ot->idname= "OBJECT_OT_select_by_type";
147         
148         /* api callbacks */
149         ot->invoke= WM_menu_invoke;
150         ot->exec= object_select_by_type_exec;
151         ot->poll= ED_operator_scene_editable;
152         
153         /* flags */
154         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
155         
156         /* properties */
157         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first.");
158         ot->prop= RNA_def_enum(ot->srna, "type", object_type_items, 1, "Type", "");
159 }
160
161 /*********************** Selection by Links *********************/
162
163 static EnumPropertyItem prop_select_linked_types[] = {
164         //{1, "IPO", 0, "Object IPO", ""}, // XXX depreceated animation system stuff...
165         {2, "OBDATA", 0, "Object Data", ""},
166         {3, "MATERIAL", 0, "Material", ""},
167         {4, "TEXTURE", 0, "Texture", ""},
168         {5, "DUPGROUP", 0, "Dupligroup", ""},
169         {6, "PARTICLE", 0, "Particle System", ""},
170         {7, "LIBRARY", 0, "Library", ""},
171         {8, "LIBRARY_OBDATA", 0, "Library (Object Data)", ""},
172         {0, NULL, 0, NULL, NULL}
173 };
174
175 static int object_select_linked_exec(bContext *C, wmOperator *op)
176 {
177         Scene *scene= CTX_data_scene(C);
178         Object *ob;
179         void *obdata = NULL;
180         Material *mat = NULL, *mat1;
181         Tex *tex=0;
182         int a, b;
183         int nr = RNA_enum_get(op->ptr, "type");
184         short changed = 0, extend;
185         /* events (nr):
186          * Object Ipo: 1
187          * ObData: 2
188          * Current Material: 3
189          * Current Texture: 4
190          * DupliGroup: 5
191          * PSys: 6
192          */
193
194         extend= RNA_boolean_get(op->ptr, "extend");
195         
196         if (extend == 0) {
197                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
198                         ED_base_object_select(base, BA_DESELECT);
199                 }
200                 CTX_DATA_END;
201         }
202         
203         ob= OBACT;
204         if(ob==NULL){ 
205                 BKE_report(op->reports, RPT_ERROR, "No Active Object");
206                 return OPERATOR_CANCELLED;
207         }
208         
209         if(nr==1) {     
210                         // XXX old animation system
211                 //ipo= ob->ipo;
212                 //if(ipo==0) return OPERATOR_CANCELLED;
213                 return OPERATOR_CANCELLED;
214         }
215         else if(nr==2) {
216                 if(ob->data==0) return OPERATOR_CANCELLED;
217                 obdata= ob->data;
218         }
219         else if(nr==3 || nr==4) {
220                 mat= give_current_material(ob, ob->actcol);
221                 if(mat==0) return OPERATOR_CANCELLED;
222                 if(nr==4) {
223                         if(mat->mtex[ (int)mat->texact ]) tex= mat->mtex[ (int)mat->texact ]->tex;
224                         if(tex==0) return OPERATOR_CANCELLED;
225                 }
226         }
227         else if(nr==5) {
228                 if(ob->dup_group==NULL) return OPERATOR_CANCELLED;
229         }
230         else if(nr==6) {
231                 if(ob->particlesystem.first==NULL) return OPERATOR_CANCELLED;
232         }
233         else if(nr==7) {
234                 /* do nothing */
235         }
236         else if(nr==8) {
237                 if(ob->data==NULL) return OPERATOR_CANCELLED;
238         }
239         else
240                 return OPERATOR_CANCELLED;
241         
242         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
243                 if(nr==1) {
244                                 // XXX old animation system
245                         //if(base->object->ipo==ipo) base->flag |= SELECT;
246                         //changed = 1;
247                 }
248                 else if(nr==2) {
249                         if(base->object->data==obdata) base->flag |= SELECT;
250                         changed = 1;
251                 }
252                 else if(nr==3 || nr==4) {
253                         ob= base->object;
254                         
255                         for(a=1; a<=ob->totcol; a++) {
256                                 mat1= give_current_material(ob, a);
257                                 if(nr==3) {
258                                         if(mat1==mat) base->flag |= SELECT;
259                                         changed = 1;
260                                 }
261                                 else if(mat1 && nr==4) {
262                                         for(b=0; b<MAX_MTEX; b++) {
263                                                 if(mat1->mtex[b]) {
264                                                         if(tex==mat1->mtex[b]->tex) {
265                                                                 base->flag |= SELECT;
266                                                                 changed = 1;
267                                                                 break;
268                                                         }
269                                                 }
270                                         }
271                                 }
272                         }
273                 }
274                 else if(nr==5) {
275                         if(base->object->dup_group==ob->dup_group) {
276                                  base->flag |= SELECT;
277                                  changed = 1;
278                         }
279                 }
280                 else if(nr==6) {
281                         /* loop through other, then actives particles*/
282                         ParticleSystem *psys;
283                         ParticleSystem *psys_act;
284                         
285                         for(psys=base->object->particlesystem.first; psys; psys=psys->next) {
286                                 for(psys_act=ob->particlesystem.first; psys_act; psys_act=psys_act->next) {
287                                         if (psys->part == psys_act->part) {
288                                                 base->flag |= SELECT;
289                                                 changed = 1;
290                                                 break;
291                                         }
292                                 }
293                                 
294                                 if (base->flag & SELECT) {
295                                         break;
296                                 }
297                         }
298                 }
299                 else if(nr==7) {
300                         if(ob->id.lib == base->object->id.lib) {
301                                 base->flag |= SELECT;
302                                 changed= 1;
303                         }
304                 }
305                 else if(nr==8) {
306                         if(base->object->data && ((ID *)ob->data)->lib == ((ID *)base->object->data)->lib) {
307                                 base->flag |= SELECT;
308                                 changed= 1;
309                         }
310                 }
311                 base->object->flag= base->flag;
312         }
313         CTX_DATA_END;
314         
315         if (changed) {
316                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
317                 return OPERATOR_FINISHED;
318         }
319         
320         return OPERATOR_CANCELLED;
321 }
322
323 void OBJECT_OT_select_linked(wmOperatorType *ot)
324 {
325         /* identifiers */
326         ot->name= "Select Linked";
327         ot->description = "Select all visible objects that are linked";
328         ot->idname= "OBJECT_OT_select_linked";
329         
330         /* api callbacks */
331         ot->invoke= WM_menu_invoke;
332         ot->exec= object_select_linked_exec;
333         ot->poll= ED_operator_scene_editable;
334         
335         /* flags */
336         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
337         
338         /* properties */
339         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first.");
340         ot->prop= RNA_def_enum(ot->srna, "type", prop_select_linked_types, 0, "Type", "");
341 }
342
343 /*********************** Selected Grouped ********************/
344
345 static EnumPropertyItem prop_select_grouped_types[] = {
346         {1, "CHILDREN_RECURSIVE", 0, "Children", ""},
347         {2, "CHILDREN", 0, "Immediate Children", ""},
348         {3, "PARENT", 0, "Parent", ""},
349         {4, "SIBLINGS", 0, "Siblings", "Shared Parent"},
350         {5, "TYPE", 0, "Type", "Shared object type"},
351         {6, "LAYER", 0, "Layer", "Shared layers"},
352         {7, "GROUP", 0, "Group", "Shared group"},
353         {8, "HOOK", 0, "Hook", ""},
354         {9, "PASS", 0, "Pass", "Render pass Index"},
355         {10, "COLOR", 0, "Color", "Object Color"},
356         {11, "PROPERTIES", 0, "Properties", "Game Properties"},
357         {0, NULL, 0, NULL, NULL}
358 };
359
360 static short select_grouped_children(bContext *C, Object *ob, int recursive)
361 {
362         short changed = 0;
363
364         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
365                 if (ob == base->object->parent) {
366                         if (!(base->flag & SELECT)) {
367                                 ED_base_object_select(base, BA_SELECT);
368                                 changed = 1;
369                         }
370
371                         if (recursive)
372                                 changed |= select_grouped_children(C, base->object, 1);
373                 }
374         }
375         CTX_DATA_END;
376         return changed;
377 }
378
379 static short select_grouped_parent(bContext *C) /* Makes parent active and de-selected OBACT */
380 {
381         Scene *scene= CTX_data_scene(C);
382         View3D *v3d= CTX_wm_view3d(C);
383
384         short changed = 0;
385         Base *baspar, *basact= CTX_data_active_base(C);
386
387         if (!basact || !(basact->object->parent)) return 0; /* we know OBACT is valid */
388
389         baspar= object_in_scene(basact->object->parent, scene);
390
391         /* can be NULL if parent in other scene */
392         if(baspar && BASE_SELECTABLE(v3d, baspar)) {
393                 ED_base_object_select(basact, BA_DESELECT);
394                 ED_base_object_select(baspar, BA_SELECT);
395                 ED_base_object_activate(C, baspar);
396                 changed = 1;
397         }
398         return changed;
399 }
400
401
402 #define GROUP_MENU_MAX  24
403 static short select_grouped_group(bContext *C, Object *ob)      /* Select objects in the same group as the active */
404 {
405         short changed = 0;
406         Group *group, *ob_groups[GROUP_MENU_MAX];
407         int group_count=0, i;
408         uiPopupMenu *pup;
409         uiLayout *layout;
410
411         for (group=CTX_data_main(C)->group.first; group && group_count < GROUP_MENU_MAX; group=group->id.next) {
412                 if (object_in_group (ob, group)) {
413                         ob_groups[group_count] = group;
414                         group_count++;
415                 }
416         }
417
418         if (!group_count)
419                 return 0;
420         else if (group_count == 1) {
421                 group = ob_groups[0];
422                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
423                         if (!(base->flag & SELECT) && object_in_group(base->object, group)) {
424                                 ED_base_object_select(base, BA_SELECT);
425                                 changed = 1;
426                         }
427                 }
428                 CTX_DATA_END;
429                 return changed;
430         }
431
432         /* build the menu. */
433         pup= uiPupMenuBegin(C, "Select Group", 0);
434         layout= uiPupMenuLayout(pup);
435
436         for (i=0; i<group_count; i++) {
437                 group = ob_groups[i];
438                 uiItemStringO(layout, group->id.name+2, 0, "OBJECT_OT_select_same_group", "group", group->id.name);
439         }
440
441         uiPupMenuEnd(C, pup);
442         return changed; // The operator already handle this!
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) && (compare_v3v3(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                         changed = 1;
581                 }
582                 CTX_DATA_END;
583         }
584         
585         ob= OBACT;
586         if(ob==0){ 
587                 BKE_report(op->reports, RPT_ERROR, "No Active Object");
588                 return OPERATOR_CANCELLED;
589         }
590         
591         if(nr==1)               changed |= select_grouped_children(C, ob, 1);
592         else if(nr==2)  changed |= select_grouped_children(C, ob, 0);
593         else if(nr==3)  changed |= select_grouped_parent(C);
594         else if(nr==4)  changed |= select_grouped_siblings(C, ob);
595         else if(nr==5)  changed |= select_grouped_type(C, ob);
596         else if(nr==6)  changed |= select_grouped_layer(C, ob);
597         else if(nr==7)  changed |= select_grouped_group(C, ob);
598         else if(nr==8)  changed |= select_grouped_object_hooks(C, ob);
599         else if(nr==9)  changed |= select_grouped_index_object(C, ob);
600         else if(nr==10) changed |= select_grouped_color(C, ob);
601         else if(nr==11) changed |= select_grouped_gameprops(C, ob);
602         
603         if (changed) {
604                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
605                 return OPERATOR_FINISHED;
606         }
607         
608         return OPERATOR_CANCELLED;
609 }
610
611 void OBJECT_OT_select_grouped(wmOperatorType *ot)
612 {
613         /* identifiers */
614         ot->name= "Select Grouped";
615         ot->description = "Select all visible objects grouped by various properties";
616         ot->idname= "OBJECT_OT_select_grouped";
617         
618         /* api callbacks */
619         ot->invoke= WM_menu_invoke;
620         ot->exec= object_select_grouped_exec;
621         ot->poll= ED_operator_scene_editable;
622         
623         /* flags */
624         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
625         
626         /* properties */
627         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first.");
628         ot->prop= RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
629 }
630
631 /************************* Select by Layer **********************/
632
633 static int object_select_by_layer_exec(bContext *C, wmOperator *op)
634 {
635         unsigned int layernum;
636         short extend;
637         
638         extend= RNA_boolean_get(op->ptr, "extend");
639         layernum = RNA_int_get(op->ptr, "layer");
640         
641         if (extend == 0) {
642                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
643                         ED_base_object_select(base, BA_DESELECT);
644                 }
645                 CTX_DATA_END;
646         }
647                 
648         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
649                 if(base->lay == (1<< (layernum -1)))
650                         ED_base_object_select(base, BA_SELECT);
651         }
652         CTX_DATA_END;
653         
654         /* undo? */
655         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
656         
657         return OPERATOR_FINISHED;
658 }
659
660 void OBJECT_OT_select_by_layer(wmOperatorType *ot)
661 {
662         /* identifiers */
663         ot->name= "select by layer";
664         ot->description = "Select all visible objects on a layer";
665         ot->idname= "OBJECT_OT_select_by_layer";
666         
667         /* api callbacks */
668         /*ot->invoke = XXX - need a int grid popup*/
669         ot->exec= object_select_by_layer_exec;
670         ot->poll= ED_operator_scene_editable;
671         
672         /* flags */
673         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
674         
675         /* properties */
676         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first.");
677         RNA_def_int(ot->srna, "layer", 1, 1, 20, "Layer", "", 1, 20);
678 }
679
680 /************************** Select Inverse *************************/
681
682 static int object_select_inverse_exec(bContext *C, wmOperator *op)
683 {
684         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
685                 if (base->flag & SELECT)
686                         ED_base_object_select(base, BA_DESELECT);
687                 else
688                         ED_base_object_select(base, BA_SELECT);
689         }
690         CTX_DATA_END;
691         
692         /* undo? */
693         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
694         
695         return OPERATOR_FINISHED;
696 }
697
698 void OBJECT_OT_select_inverse(wmOperatorType *ot)
699 {
700         
701         /* identifiers */
702         ot->name= "Select Inverse";
703         ot->description = "Invert selection of all visible objects";
704         ot->idname= "OBJECT_OT_select_inverse";
705         
706         /* api callbacks */
707         ot->exec= object_select_inverse_exec;
708         ot->poll= ED_operator_scene_editable;
709         
710         /* flags */
711         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
712         
713 }
714
715 /**************************** (De)select All ****************************/
716
717 static int object_select_all_exec(bContext *C, wmOperator *op)
718 {
719         int action = RNA_enum_get(op->ptr, "action");
720         
721         /* passthrough if no objects are visible */
722         if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH;
723
724         if (action == SEL_TOGGLE) {
725                 action = SEL_SELECT;
726                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
727                         if (base->flag & SELECT) {
728                                 action = SEL_DESELECT;
729                                 break;
730                         }
731                 }
732                 CTX_DATA_END;
733         }
734
735         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
736                 switch (action) {
737                 case SEL_SELECT:
738                         ED_base_object_select(base, BA_SELECT);
739                         break;
740                 case SEL_DESELECT:
741                         ED_base_object_select(base, BA_DESELECT);
742                         break;
743                 case SEL_INVERT:
744                         if (base->flag & SELECT) {
745                                 ED_base_object_select(base, BA_DESELECT);
746                         } else {
747                                 ED_base_object_select(base, BA_SELECT);
748                         }
749                         break;
750                 }
751         }
752         CTX_DATA_END;
753         
754         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
755         
756         return OPERATOR_FINISHED;
757 }
758
759 void OBJECT_OT_select_all(wmOperatorType *ot)
760 {
761         
762         /* identifiers */
763         ot->name= "deselect all";
764         ot->description = "Change selection of all visible objects in scene";
765         ot->idname= "OBJECT_OT_select_all";
766         
767         /* api callbacks */
768         ot->exec= object_select_all_exec;
769         ot->poll= ED_operator_scene_editable;
770         
771         /* flags */
772         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
773
774         WM_operator_properties_select_all(ot);
775 }
776
777 /**************************** Select In The Same Group ****************************/
778
779 static int object_select_same_group_exec(bContext *C, wmOperator *op)
780 {
781         Group *group;
782         char group_name[32];
783
784         /* passthrough if no objects are visible */
785         if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH;
786
787         RNA_string_get(op->ptr, "group", group_name);
788
789         for (group=CTX_data_main(C)->group.first;       group; group=group->id.next) {
790                 if (!strcmp(group->id.name, group_name))
791                         break;
792         }
793
794         if (!group)
795                 return OPERATOR_PASS_THROUGH;
796
797         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
798                 if (!(base->flag & SELECT) && object_in_group(base->object, group))
799                         ED_base_object_select(base, BA_SELECT);
800         }
801         CTX_DATA_END;
802
803         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
804         
805         return OPERATOR_FINISHED;
806 }
807
808 void OBJECT_OT_select_same_group(wmOperatorType *ot)
809 {
810         
811         /* identifiers */
812         ot->name= "select same group";
813         ot->description = "Select object in the same group";
814         ot->idname= "OBJECT_OT_select_same_group";
815         
816         /* api callbacks */
817         ot->exec= object_select_same_group_exec;
818         ot->poll= ED_operator_scene_editable;
819         
820         /* flags */
821         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
822
823         RNA_def_string(ot->srna, "group", "", 32, "Group", "Name of the group to select.");
824 }
825
826 /**************************** Select Mirror ****************************/
827
828 /* finds the best possible flipped name. For renaming; check for unique names afterwards */
829 /* if strip_number: removes number extensions */
830 void object_flip_name (char *name)
831 {
832         int     len;
833         char    prefix[128]={""};   /* The part before the facing */
834         char    suffix[128]={""};   /* The part after the facing */
835         char    replace[128]={""};  /* The replacement string */
836         char    number[128]={""};   /* The number extension string */
837         char    *index=NULL;
838
839         len= strlen(name);
840         if(len<3) return; // we don't do names like .R or .L
841
842         /* We first check the case with a .### extension, let's find the last period */
843         if(isdigit(name[len-1])) {
844                 index= strrchr(name, '.'); // last occurrence
845                 if (index && isdigit(index[1]) ) { // doesnt handle case bone.1abc2 correct..., whatever!
846                         strcpy(number, index);
847                         *index= 0;
848                         len= strlen(name);
849                 }
850         }
851
852         strcpy (prefix, name);
853
854 #define IS_SEPARATOR(a) ((a)=='.' || (a)==' ' || (a)=='-' || (a)=='_')
855
856         /* first case; separator . - _ with extensions r R l L  */
857         if( IS_SEPARATOR(name[len-2]) ) {
858                 switch(name[len-1]) {
859                         case 'l':
860                                 prefix[len-1]= 0;
861                                 strcpy(replace, "r");
862                                 break;
863                         case 'r':
864                                 prefix[len-1]= 0;
865                                 strcpy(replace, "l");
866                                 break;
867                         case 'L':
868                                 prefix[len-1]= 0;
869                                 strcpy(replace, "R");
870                                 break;
871                         case 'R':
872                                 prefix[len-1]= 0;
873                                 strcpy(replace, "L");
874                                 break;
875                 }
876         }
877         /* case; beginning with r R l L , with separator after it */
878         else if( IS_SEPARATOR(name[1]) ) {
879                 switch(name[0]) {
880                         case 'l':
881                                 strcpy(replace, "r");
882                                 strcpy(suffix, name+1);
883                                 prefix[0]= 0;
884                                 break;
885                         case 'r':
886                                 strcpy(replace, "l");
887                                 strcpy(suffix, name+1);
888                                 prefix[0]= 0;
889                                 break;
890                         case 'L':
891                                 strcpy(replace, "R");
892                                 strcpy(suffix, name+1);
893                                 prefix[0]= 0;
894                                 break;
895                         case 'R':
896                                 strcpy(replace, "L");
897                                 strcpy(suffix, name+1);
898                                 prefix[0]= 0;
899                                 break;
900                 }
901         }
902         else if(len > 5) {
903                 /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
904                 index = BLI_strcasestr(prefix, "right");
905                 if (index==prefix || index==prefix+len-5) {
906                         if(index[0]=='r') 
907                                 strcpy (replace, "left");
908                         else {
909                                 if(index[1]=='I') 
910                                         strcpy (replace, "LEFT");
911                                 else
912                                         strcpy (replace, "Left");
913                         }
914                         *index= 0;
915                         strcpy (suffix, index+5);
916                 }
917                 else {
918                         index = BLI_strcasestr(prefix, "left");
919                         if (index==prefix || index==prefix+len-4) {
920                                 if(index[0]=='l') 
921                                         strcpy (replace, "right");
922                                 else {
923                                         if(index[1]=='E') 
924                                                 strcpy (replace, "RIGHT");
925                                         else
926                                                 strcpy (replace, "Right");
927                                 }
928                                 *index= 0;
929                                 strcpy (suffix, index+4);
930                         }
931                 }
932         }
933
934 #undef IS_SEPARATOR
935
936         sprintf (name, "%s%s%s%s", prefix, replace, suffix, number);
937 }
938
939 static int object_select_mirror_exec(bContext *C, wmOperator *op)
940 {
941         char tmpname[32];
942         short extend;
943         
944         extend= RNA_boolean_get(op->ptr, "extend");
945         
946         CTX_DATA_BEGIN(C, Base*, primbase, selected_bases) {
947
948                 strcpy(tmpname, primbase->object->id.name+2);
949                 object_flip_name(tmpname);
950                 
951                 CTX_DATA_BEGIN(C, Base*, secbase, visible_bases) {
952                         if(!strcmp(secbase->object->id.name+2, tmpname)) {
953                                 ED_base_object_select(secbase, BA_SELECT);
954                         }
955                 }
956                 CTX_DATA_END;
957                 
958                 if (extend == 0) ED_base_object_select(primbase, BA_DESELECT);
959                 
960         }
961         CTX_DATA_END;
962         
963         /* undo? */
964         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
965         
966         return OPERATOR_FINISHED;
967 }
968
969 void OBJECT_OT_select_mirror(wmOperatorType *ot)
970 {
971         
972         /* identifiers */
973         ot->name= "Select Mirror";
974         ot->description = "Select the Mirror objects of the selected object eg. L.sword -> R.sword";
975         ot->idname= "OBJECT_OT_select_mirror";
976         
977         /* api callbacks */
978         ot->exec= object_select_mirror_exec;
979         ot->poll= ED_operator_scene_editable;
980         
981         /* flags */
982         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
983         
984         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first.");
985 }
986
987
988 static int object_select_name_exec(bContext *C, wmOperator *op)
989 {
990         char *name= RNA_string_get_alloc(op->ptr, "name", NULL, 0);
991         short extend= RNA_boolean_get(op->ptr, "extend");
992         short changed = 0;
993
994         if(!extend) {
995                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
996                         ED_base_object_select(base, BA_DESELECT);
997                 }
998                 CTX_DATA_END;
999         }
1000
1001         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
1002                 /* this is a bit dodjy, there should only be ONE object with this name, but library objects can mess this up */
1003                 if(strcmp(name, base->object->id.name+2)==0) {
1004                         ED_base_object_activate(C, base);
1005                         ED_base_object_select(base, BA_SELECT);
1006                         changed= 1;
1007                 }
1008         }
1009         CTX_DATA_END;
1010
1011         MEM_freeN(name);
1012
1013         /* undo? */
1014         if(changed) {
1015                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1016                 return OPERATOR_FINISHED;
1017         }
1018         else {
1019                 return OPERATOR_CANCELLED;
1020         }
1021 }
1022
1023 void OBJECT_OT_select_name(wmOperatorType *ot)
1024 {
1025
1026         /* identifiers */
1027         ot->name= "Select Name";
1028         ot->description = "Select an object with this name";
1029         ot->idname= "OBJECT_OT_select_name";
1030
1031         /* api callbacks */
1032         ot->exec= object_select_name_exec;
1033         ot->poll= ED_operator_scene_editable;
1034
1035         /* flags */
1036         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1037
1038         RNA_def_string(ot->srna, "name", "", 0, "Name", "Object name to select.");
1039         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first.");
1040 }
1041
1042 /**************************** Select Random ****************************/
1043
1044 static int object_select_random_exec(bContext *C, wmOperator *op)
1045 {       
1046         float percent;
1047         short extend;
1048         
1049         extend= RNA_boolean_get(op->ptr, "extend");
1050         
1051         if (extend == 0) {
1052                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1053                         ED_base_object_select(base, BA_DESELECT);
1054                 }
1055                 CTX_DATA_END;
1056         }
1057         percent = RNA_float_get(op->ptr, "percent")/100.0f;
1058                 
1059         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1060                 if (BLI_frand() < percent) {
1061                         ED_base_object_select(base, BA_SELECT);
1062                 }
1063         }
1064         CTX_DATA_END;
1065         
1066         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1067         
1068         return OPERATOR_FINISHED;
1069 }
1070
1071 void OBJECT_OT_select_random(wmOperatorType *ot)
1072 {
1073         /* identifiers */
1074         ot->name= "Select Random";
1075         ot->description = "Set select on random visible objects";
1076         ot->idname= "OBJECT_OT_select_random";
1077         
1078         /* api callbacks */
1079         /*ot->invoke= object_select_random_invoke XXX - need a number popup ;*/
1080         ot->exec = object_select_random_exec;
1081         ot->poll= ED_operator_scene_editable;
1082         
1083         /* flags */
1084         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1085         
1086         /* properties */
1087         RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, "Percent", "Percentage of objects to select randomly", 0.f, 100.0f);
1088         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend Selection", "Extend selection instead of deselecting everything first.");
1089 }
1090
1091