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