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