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