ac3210348de62924b364287fdf5c98323760ca14
[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 "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
46 #include "BLI_math.h"
47 #include "BLI_listbase.h"
48 #include "BLI_rand.h"
49 #include "BLI_string.h"
50 #include "BLI_utildefines.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 depreceated 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         int 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 int object_select_all_by_obdata(bContext *C, void *obdata)
234 {
235         int 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 int object_select_all_by_material_texture(bContext *C, int use_texture, Material *mat, Tex *tex)
254 {
255         int 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 int object_select_all_by_dup_group(bContext *C, Object *ob)
295 {
296         int 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 int object_select_all_by_particle(bContext *C, Object *ob)
317 {
318         int changed = FALSE;
319
320         CTX_DATA_BEGIN (C, Base *, base, visible_bases)
321         {
322                 if ((base->flag & SELECT) == 0) {
323                         /* loop through other, then actives particles*/
324                         ParticleSystem *psys;
325                         ParticleSystem *psys_act;
326
327                         for (psys = base->object->particlesystem.first; psys; psys = psys->next) {
328                                 for (psys_act = ob->particlesystem.first; psys_act; psys_act = psys_act->next) {
329                                         if (psys->part == psys_act->part) {
330                                                 base->flag |= SELECT;
331                                                 changed = TRUE;
332                                                 break;
333                                         }
334                                 }
335
336                                 if (base->flag & SELECT) {
337                                         break;
338                                 }
339                         }
340
341                         base->object->flag = base->flag;
342                 }
343         }
344         CTX_DATA_END;
345
346         return changed;
347 }
348
349 static int object_select_all_by_library(bContext *C, Library *lib)
350 {
351         int changed = FALSE;
352
353         CTX_DATA_BEGIN (C, Base *, base, visible_bases)
354         {
355                 if ((base->flag & SELECT) == 0) {
356                         if (lib == base->object->id.lib) {
357                                 base->flag |= SELECT;
358                                 base->object->flag = base->flag;
359
360                                 changed = TRUE;
361                         }
362                 }
363         }
364         CTX_DATA_END;
365
366         return changed;
367 }
368
369 static int object_select_all_by_library_obdata(bContext *C, Library *lib)
370 {
371         int changed = FALSE;
372
373         CTX_DATA_BEGIN (C, Base *, base, visible_bases)
374         {
375                 if ((base->flag & SELECT) == 0) {
376                         if (base->object->data && lib == ((ID *)base->object->data)->lib) {
377                                 base->flag |= SELECT;
378                                 base->object->flag = base->flag;
379
380                                 changed = TRUE;
381                         }
382                 }
383         }
384         CTX_DATA_END;
385
386         return changed;
387 }
388
389 void ED_object_select_linked_by_id(bContext *C, ID *id)
390 {
391         int gs = GS(id->name);
392         int changed = FALSE;
393
394         if (ELEM8(gs, ID_ME, ID_CU, ID_MB, ID_LT, ID_LA, ID_CA, ID_TXT, ID_SPK)) {
395                 changed = object_select_all_by_obdata(C, id);
396         }
397         else if (gs == ID_MA) {
398                 changed = object_select_all_by_material_texture(C, FALSE, (Material *)id, NULL);
399         }
400         else if (gs == ID_LI) {
401                 changed = object_select_all_by_library(C, (Library *) id);
402         }
403
404         if (changed)
405                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
406 }
407
408 static int object_select_linked_exec(bContext *C, wmOperator *op)
409 {
410         Scene *scene = CTX_data_scene(C);
411         Object *ob;
412         int nr = RNA_enum_get(op->ptr, "type");
413         short changed = FALSE, extend;
414
415         extend = RNA_boolean_get(op->ptr, "extend");
416         
417         if (extend == 0) {
418                 CTX_DATA_BEGIN (C, Base *, base, visible_bases)
419                 {
420                         ED_base_object_select(base, BA_DESELECT);
421                 }
422                 CTX_DATA_END;
423         }
424         
425         ob = OBACT;
426         if (ob == NULL) {
427                 BKE_report(op->reports, RPT_ERROR, "No Active Object");
428                 return OPERATOR_CANCELLED;
429         }
430         
431         if (nr == OBJECT_SELECT_LINKED_IPO) {
432                 // XXX old animation system
433                 //if (ob->ipo == 0) return OPERATOR_CANCELLED;
434                 //object_select_all_by_ipo(C, ob->ipo)
435                 return OPERATOR_CANCELLED;
436         }
437         else if (nr == OBJECT_SELECT_LINKED_OBDATA) {
438                 if (ob->data == 0)
439                         return OPERATOR_CANCELLED;
440
441                 changed = object_select_all_by_obdata(C, ob->data);
442         }
443         else if (nr == OBJECT_SELECT_LINKED_MATERIAL || nr == OBJECT_SELECT_LINKED_TEXTURE) {
444                 Material *mat = NULL;
445                 Tex *tex = NULL;
446                 int use_texture = FALSE;
447
448                 mat = give_current_material(ob, ob->actcol);
449                 if (mat == NULL) return OPERATOR_CANCELLED;
450                 if (nr == OBJECT_SELECT_LINKED_TEXTURE) {
451                         use_texture = TRUE;
452
453                         if (mat->mtex[(int)mat->texact]) tex = mat->mtex[(int)mat->texact]->tex;
454                         if (tex == NULL) return OPERATOR_CANCELLED;
455                 }
456
457                 changed = object_select_all_by_material_texture(C, use_texture, mat, tex);
458         }
459         else if (nr == OBJECT_SELECT_LINKED_DUPGROUP) {
460                 if (ob->dup_group == NULL)
461                         return OPERATOR_CANCELLED;
462
463                 changed = object_select_all_by_dup_group(C, ob);
464         }
465         else if (nr == OBJECT_SELECT_LINKED_PARTICLE) {
466                 if (ob->particlesystem.first == NULL)
467                         return OPERATOR_CANCELLED;
468
469                 changed = object_select_all_by_particle(C, ob);
470         }
471         else if (nr == OBJECT_SELECT_LINKED_LIBRARY) {
472                 /* do nothing */
473                 changed = object_select_all_by_library(C, ob->id.lib);
474         }
475         else if (nr == OBJECT_SELECT_LINKED_LIBRARY_OBDATA) {
476                 if (ob->data == NULL)
477                         return OPERATOR_CANCELLED;
478
479                 changed = object_select_all_by_library_obdata(C, ((ID *) ob->data)->lib);
480         }
481         else
482                 return OPERATOR_CANCELLED;
483
484         if (changed) {
485                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
486                 return OPERATOR_FINISHED;
487         }
488         
489         return OPERATOR_CANCELLED;
490 }
491
492 void OBJECT_OT_select_linked(wmOperatorType *ot)
493 {
494         /* identifiers */
495         ot->name = "Select Linked";
496         ot->description = "Select all visible objects that are linked";
497         ot->idname = "OBJECT_OT_select_linked";
498         
499         /* api callbacks */
500         ot->invoke = WM_menu_invoke;
501         ot->exec = object_select_linked_exec;
502         ot->poll = objects_selectable_poll;
503         
504         /* flags */
505         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
506         
507         /* properties */
508         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
509         ot->prop = RNA_def_enum(ot->srna, "type", prop_select_linked_types, 0, "Type", "");
510 }
511
512 /*********************** Selected Grouped ********************/
513
514 static EnumPropertyItem prop_select_grouped_types[] = {
515         {1, "CHILDREN_RECURSIVE", 0, "Children", ""},
516         {2, "CHILDREN", 0, "Immediate Children", ""},
517         {3, "PARENT", 0, "Parent", ""},
518         {4, "SIBLINGS", 0, "Siblings", "Shared Parent"},
519         {5, "TYPE", 0, "Type", "Shared object type"},
520         {6, "LAYER", 0, "Layer", "Shared layers"},
521         {7, "GROUP", 0, "Group", "Shared group"},
522         {8, "HOOK", 0, "Hook", ""},
523         {9, "PASS", 0, "Pass", "Render pass Index"},
524         {10, "COLOR", 0, "Color", "Object Color"},
525         {11, "PROPERTIES", 0, "Properties", "Game Properties"},
526         {12, "KEYINGSET", 0, "Keying Set", "Objects included in active Keying Set"},
527         {0, NULL, 0, NULL, NULL}
528 };
529
530 static short select_grouped_children(bContext *C, Object *ob, int recursive)
531 {
532         short changed = 0;
533
534         CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
535         {
536                 if (ob == base->object->parent) {
537                         if (!(base->flag & SELECT)) {
538                                 ED_base_object_select(base, BA_SELECT);
539                                 changed = 1;
540                         }
541
542                         if (recursive)
543                                 changed |= select_grouped_children(C, base->object, 1);
544                 }
545         }
546         CTX_DATA_END;
547         return changed;
548 }
549
550 static short select_grouped_parent(bContext *C) /* Makes parent active and de-selected OBACT */
551 {
552         Scene *scene = CTX_data_scene(C);
553         View3D *v3d = CTX_wm_view3d(C);
554
555         short changed = 0;
556         Base *baspar, *basact = CTX_data_active_base(C);
557
558         if (!basact || !(basact->object->parent)) return 0;  /* we know OBACT is valid */
559
560         baspar = BKE_scene_base_find(scene, basact->object->parent);
561
562         /* can be NULL if parent in other scene */
563         if (baspar && BASE_SELECTABLE(v3d, baspar)) {
564                 ED_base_object_select(basact, BA_DESELECT);
565                 ED_base_object_select(baspar, BA_SELECT);
566                 ED_base_object_activate(C, baspar);
567                 changed = 1;
568         }
569         return changed;
570 }
571
572
573 #define GROUP_MENU_MAX  24
574 static short select_grouped_group(bContext *C, Object *ob)  /* Select objects in the same group as the active */
575 {
576         short changed = 0;
577         Group *group, *ob_groups[GROUP_MENU_MAX];
578         int group_count = 0, i;
579         uiPopupMenu *pup;
580         uiLayout *layout;
581
582         for (group = CTX_data_main(C)->group.first; group && group_count < GROUP_MENU_MAX; group = group->id.next) {
583                 if (object_in_group(ob, group)) {
584                         ob_groups[group_count] = group;
585                         group_count++;
586                 }
587         }
588
589         if (!group_count)
590                 return 0;
591         else if (group_count == 1) {
592                 group = ob_groups[0];
593                 CTX_DATA_BEGIN (C, Base *, base, visible_bases)
594                 {
595                         if (!(base->flag & SELECT) && object_in_group(base->object, group)) {
596                                 ED_base_object_select(base, BA_SELECT);
597                                 changed = 1;
598                         }
599                 }
600                 CTX_DATA_END;
601                 return changed;
602         }
603
604         /* build the menu. */
605         pup = uiPupMenuBegin(C, "Select Group", ICON_NONE);
606         layout = uiPupMenuLayout(pup);
607
608         for (i = 0; i < group_count; i++) {
609                 group = ob_groups[i];
610                 uiItemStringO(layout, group->id.name + 2, 0, "OBJECT_OT_select_same_group", "group", group->id.name);
611         }
612
613         uiPupMenuEnd(C, pup);
614         return changed; // The operator already handle this!
615 }
616
617 static short select_grouped_object_hooks(bContext *C, Object *ob)
618 {
619         Scene *scene = CTX_data_scene(C);
620         View3D *v3d = CTX_wm_view3d(C);
621
622         short changed = 0;
623         Base *base;
624         ModifierData *md;
625         HookModifierData *hmd;
626
627         for (md = ob->modifiers.first; md; md = md->next) {
628                 if (md->type == eModifierType_Hook) {
629                         hmd = (HookModifierData *) md;
630                         if (hmd->object && !(hmd->object->flag & SELECT)) {
631                                 base = BKE_scene_base_find(scene, hmd->object);
632                                 if (base && (BASE_SELECTABLE(v3d, base))) {
633                                         ED_base_object_select(base, BA_SELECT);
634                                         changed = 1;
635                                 }
636                         }
637                 }
638         }
639         return changed;
640 }
641
642 /* Select objects with the same parent as the active (siblings),
643  * parent can be NULL also */
644 static short select_grouped_siblings(bContext *C, Object *ob)
645 {
646         short changed = 0;
647
648         CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
649         {
650                 if ((base->object->parent == ob->parent) && !(base->flag & SELECT)) {
651                         ED_base_object_select(base, BA_SELECT);
652                         changed = 1;
653                 }
654         }
655         CTX_DATA_END;
656         return changed;
657 }
658
659 static short select_grouped_type(bContext *C, Object *ob)
660 {
661         short changed = 0;
662
663         CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
664         {
665                 if ((base->object->type == ob->type) && !(base->flag & SELECT)) {
666                         ED_base_object_select(base, BA_SELECT);
667                         changed = 1;
668                 }
669         }
670         CTX_DATA_END;
671         return changed;
672 }
673
674 static short select_grouped_layer(bContext *C, Object *ob)
675 {
676         char changed = 0;
677
678         CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
679         {
680                 if ((base->lay & ob->lay) && !(base->flag & SELECT)) {
681                         ED_base_object_select(base, BA_SELECT);
682                         changed = 1;
683                 }
684         }
685         CTX_DATA_END;
686         return changed;
687 }
688
689 static short select_grouped_index_object(bContext *C, Object *ob)
690 {
691         char changed = 0;
692
693         CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
694         {
695                 if ((base->object->index == ob->index) && !(base->flag & SELECT)) {
696                         ED_base_object_select(base, BA_SELECT);
697                         changed = 1;
698                 }
699         }
700         CTX_DATA_END;
701         return changed;
702 }
703
704 static short select_grouped_color(bContext *C, Object *ob)
705 {
706         char changed = 0;
707
708         CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
709         {
710                 if (!(base->flag & SELECT) && (compare_v3v3(base->object->col, ob->col, 0.005f))) {
711                         ED_base_object_select(base, BA_SELECT);
712                         changed = 1;
713                 }
714         }
715         CTX_DATA_END;
716         return changed;
717 }
718
719 static short objects_share_gameprop(Object *a, Object *b)
720 {
721         bProperty *prop;
722         /*make a copy of all its properties*/
723
724         for (prop = a->prop.first; prop; prop = prop->next) {
725                 if (get_ob_property(b, prop->name) )
726                         return 1;
727         }
728         return 0;
729 }
730
731 static short select_grouped_gameprops(bContext *C, Object *ob)
732 {
733         char changed = 0;
734
735         CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
736         {
737                 if (!(base->flag & SELECT) && (objects_share_gameprop(base->object, ob))) {
738                         ED_base_object_select(base, BA_SELECT);
739                         changed = 1;
740                 }
741         }
742         CTX_DATA_END;
743         return changed;
744 }
745
746 static short select_grouped_keyingset(bContext *C, Object *UNUSED(ob))
747 {
748         KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C));
749         short changed = 0;
750         
751         /* firstly, validate KeyingSet */
752         if ((ks == NULL) || (ANIM_validate_keyingset(C, NULL, ks) != 0))
753                 return 0;
754         
755         /* select each object that Keying Set refers to */
756         // TODO: perhaps to be more in line with the rest of these, we should only take objects 
757         // if the passed in object is included in this too
758         CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
759         {
760                 /* only check for this object if it isn't selected already, to limit time wasted */
761                 if ((base->flag & SELECT) == 0) {
762                         KS_Path *ksp;
763                         
764                         /* this is the slow way... we could end up with > 500 items here, 
765                          * with none matching, but end up doing this on 1000 objects...
766                          */
767                         for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
768                                 /* if id matches, select then stop looping (match found) */
769                                 if (ksp->id == (ID *)base->object) {
770                                         ED_base_object_select(base, BA_SELECT);
771                                         changed = 1;
772                                         break;
773                                 }
774                         }
775                 }
776         }
777         CTX_DATA_END;
778                 
779         return changed;
780 }
781
782 static int object_select_grouped_exec(bContext *C, wmOperator *op)
783 {
784         Scene *scene = CTX_data_scene(C);
785         Object *ob;
786         int nr = RNA_enum_get(op->ptr, "type");
787         short changed = 0, extend;
788
789         extend = RNA_boolean_get(op->ptr, "extend");
790         
791         if (extend == 0) {
792                 CTX_DATA_BEGIN (C, Base *, base, visible_bases)
793                 {
794                         ED_base_object_select(base, BA_DESELECT);
795                         changed = 1;
796                 }
797                 CTX_DATA_END;
798         }
799         
800         ob = OBACT;
801         if (ob == NULL) {
802                 BKE_report(op->reports, RPT_ERROR, "No Active Object");
803                 return OPERATOR_CANCELLED;
804         }
805         
806         if      (nr == 1) changed |= select_grouped_children(C, ob, 1);
807         else if (nr == 2) changed |= select_grouped_children(C, ob, 0);
808         else if (nr == 3) changed |= select_grouped_parent(C);
809         else if (nr == 4) changed |= select_grouped_siblings(C, ob);
810         else if (nr == 5) changed |= select_grouped_type(C, ob);
811         else if (nr == 6) changed |= select_grouped_layer(C, ob);
812         else if (nr == 7) changed |= select_grouped_group(C, ob);
813         else if (nr == 8) changed |= select_grouped_object_hooks(C, ob);
814         else if (nr == 9) changed |= select_grouped_index_object(C, ob);
815         else if (nr == 10) changed |= select_grouped_color(C, ob);
816         else if (nr == 11) changed |= select_grouped_gameprops(C, ob);
817         else if (nr == 12) changed |= select_grouped_keyingset(C, ob);
818         
819         if (changed) {
820                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
821                 return OPERATOR_FINISHED;
822         }
823         
824         return OPERATOR_CANCELLED;
825 }
826
827 void OBJECT_OT_select_grouped(wmOperatorType *ot)
828 {
829         /* identifiers */
830         ot->name = "Select Grouped";
831         ot->description = "Select all visible objects grouped by various properties";
832         ot->idname = "OBJECT_OT_select_grouped";
833         
834         /* api callbacks */
835         ot->invoke = WM_menu_invoke;
836         ot->exec = object_select_grouped_exec;
837         ot->poll = objects_selectable_poll;
838         
839         /* flags */
840         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
841         
842         /* properties */
843         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
844         ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
845 }
846
847 /************************* Select by Layer **********************/
848
849 static int object_select_by_layer_exec(bContext *C, wmOperator *op)
850 {
851         unsigned int layernum;
852         short extend, match;
853         
854         extend = RNA_boolean_get(op->ptr, "extend");
855         layernum = RNA_int_get(op->ptr, "layers");
856         match = RNA_enum_get(op->ptr, "match");
857         
858         if (extend == 0) {
859                 CTX_DATA_BEGIN (C, Base *, base, visible_bases)
860                 {
861                         ED_base_object_select(base, BA_DESELECT);
862                 }
863                 CTX_DATA_END;
864         }
865                 
866         CTX_DATA_BEGIN (C, Base *, base, visible_bases)
867         {
868                 int ok = 0;
869
870                 if (match == 1) /* exact */
871                         ok = (base->lay == (1 << (layernum - 1)));
872                 else /* shared layers */
873                         ok = (base->lay & (1 << (layernum - 1)));
874
875                 if (ok)
876                         ED_base_object_select(base, BA_SELECT);
877         }
878         CTX_DATA_END;
879         
880         /* undo? */
881         WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
882         
883         return OPERATOR_FINISHED;
884 }
885
886 void OBJECT_OT_select_by_layer(wmOperatorType *ot)
887 {
888         static EnumPropertyItem match_items[] = {
889                 {1, "EXACT", 0, "Exact Match", ""},
890                 {2, "SHARED", 0, "Shared Layers", ""},
891                 {0, NULL, 0, NULL, NULL}
892         };
893
894         /* identifiers */
895         ot->name = "Select by Layer";
896         ot->description = "Select all visible objects on a layer";
897         ot->idname = "OBJECT_OT_select_by_layer";
898         
899         /* api callbacks */
900         /*ot->invoke = XXX - need a int grid popup*/
901         ot->exec = object_select_by_layer_exec;
902         ot->poll = objects_selectable_poll;
903         
904         /* flags */
905         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
906         
907         /* properties */
908         RNA_def_enum(ot->srna, "match", match_items, 0, "Match", "");
909         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
910         RNA_def_int(ot->srna, "layers", 1, 1, 20, "Layer", "", 1, 20);
911 }
912
913 /**************************** (De)select All ****************************/
914
915 static int object_select_all_exec(bContext *C, wmOperator *op)
916 {
917         int action = RNA_enum_get(op->ptr, "action");
918         
919         /* passthrough if no objects are visible */
920         if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH;
921
922         if (action == SEL_TOGGLE) {
923                 action = SEL_SELECT;
924                 CTX_DATA_BEGIN (C, Base *, base, visible_bases)
925                 {
926                         if (base->flag & SELECT) {
927                                 action = SEL_DESELECT;
928                                 break;
929                         }
930                 }
931                 CTX_DATA_END;
932         }
933
934         CTX_DATA_BEGIN (C, Base *, base, visible_bases)
935         {
936                 switch (action) {
937                         case SEL_SELECT:
938                                 ED_base_object_select(base, BA_SELECT);
939                                 break;
940                         case SEL_DESELECT:
941                                 ED_base_object_select(base, BA_DESELECT);
942                                 break;
943                         case SEL_INVERT:
944                                 if (base->flag & SELECT) {
945                                         ED_base_object_select(base, BA_DESELECT);
946                                 }
947                                 else {
948                                         ED_base_object_select(base, BA_SELECT);
949                                 }
950                                 break;
951                 }
952         }
953         CTX_DATA_END;
954         
955         WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
956         
957         return OPERATOR_FINISHED;
958 }
959
960 void OBJECT_OT_select_all(wmOperatorType *ot)
961 {
962         
963         /* identifiers */
964         ot->name = "(De)select All";
965         ot->description = "Change selection of all visible objects in scene";
966         ot->idname = "OBJECT_OT_select_all";
967         
968         /* api callbacks */
969         ot->exec = object_select_all_exec;
970         ot->poll = objects_selectable_poll;
971         
972         /* flags */
973         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
974
975         WM_operator_properties_select_all(ot);
976 }
977
978 /**************************** Select In The Same Group ****************************/
979
980 static int object_select_same_group_exec(bContext *C, wmOperator *op)
981 {
982         Group *group;
983         char group_name[MAX_ID_NAME];
984
985         /* passthrough if no objects are visible */
986         if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH;
987
988         RNA_string_get(op->ptr, "group", group_name);
989
990         for (group = CTX_data_main(C)->group.first; group; group = group->id.next) {
991                 if (!strcmp(group->id.name, group_name))
992                         break;
993         }
994
995         if (!group)
996                 return OPERATOR_PASS_THROUGH;
997
998         CTX_DATA_BEGIN (C, Base *, base, visible_bases)
999         {
1000                 if (!(base->flag & SELECT) && object_in_group(base->object, group))
1001                         ED_base_object_select(base, BA_SELECT);
1002         }
1003         CTX_DATA_END;
1004
1005         WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
1006         
1007         return OPERATOR_FINISHED;
1008 }
1009
1010 void OBJECT_OT_select_same_group(wmOperatorType *ot)
1011 {
1012         
1013         /* identifiers */
1014         ot->name = "Select Same Group";
1015         ot->description = "Select object in the same group";
1016         ot->idname = "OBJECT_OT_select_same_group";
1017         
1018         /* api callbacks */
1019         ot->exec = object_select_same_group_exec;
1020         ot->poll = objects_selectable_poll;
1021         
1022         /* flags */
1023         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1024
1025         RNA_def_string(ot->srna, "group", "", MAX_ID_NAME, "Group", "Name of the group to select");
1026 }
1027
1028 /**************************** Select Mirror ****************************/
1029 static int object_select_mirror_exec(bContext *C, wmOperator *op)
1030 {
1031         Scene *scene = CTX_data_scene(C);
1032         short extend;
1033         
1034         extend = RNA_boolean_get(op->ptr, "extend");
1035         
1036         CTX_DATA_BEGIN (C, Base *, primbase, selected_bases)
1037         {
1038                 char tmpname[MAXBONENAME];
1039
1040                 flip_side_name(tmpname, primbase->object->id.name + 2, TRUE);
1041                 
1042                 if (strcmp(tmpname, primbase->object->id.name + 2) != 0) { /* names differ */
1043                         Object *ob = (Object *)BKE_libblock_find_name(ID_OB, tmpname);
1044                         if (ob) {
1045                                 Base *secbase = BKE_scene_base_find(scene, ob);
1046
1047                                 if (secbase) {
1048                                         ED_base_object_select(secbase, BA_SELECT);
1049                                 }
1050                         }
1051                 }
1052                 
1053                 if (extend == 0) ED_base_object_select(primbase, BA_DESELECT);
1054                 
1055         }
1056         CTX_DATA_END;
1057         
1058         /* undo? */
1059         WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
1060         
1061         return OPERATOR_FINISHED;
1062 }
1063
1064 void OBJECT_OT_select_mirror(wmOperatorType *ot)
1065 {
1066         
1067         /* identifiers */
1068         ot->name = "Select Mirror";
1069         ot->description = "Select the Mirror objects of the selected object eg. L.sword -> R.sword";
1070         ot->idname = "OBJECT_OT_select_mirror";
1071         
1072         /* api callbacks */
1073         ot->exec = object_select_mirror_exec;
1074         ot->poll = objects_selectable_poll;
1075         
1076         /* flags */
1077         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1078         
1079         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first");
1080 }
1081
1082
1083 /**************************** Select Random ****************************/
1084
1085 static int object_select_random_exec(bContext *C, wmOperator *op)
1086 {       
1087         float percent;
1088         short extend;
1089         
1090         extend = RNA_boolean_get(op->ptr, "extend");
1091         
1092         if (extend == 0) {
1093                 CTX_DATA_BEGIN (C, Base *, base, visible_bases)
1094                 {
1095                         ED_base_object_select(base, BA_DESELECT);
1096                 }
1097                 CTX_DATA_END;
1098         }
1099         percent = RNA_float_get(op->ptr, "percent") / 100.0f;
1100                 
1101         CTX_DATA_BEGIN (C, Base *, base, visible_bases)
1102         {
1103                 if (BLI_frand() < percent) {
1104                         ED_base_object_select(base, BA_SELECT);
1105                 }
1106         }
1107         CTX_DATA_END;
1108         
1109         WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
1110         
1111         return OPERATOR_FINISHED;
1112 }
1113
1114 void OBJECT_OT_select_random(wmOperatorType *ot)
1115 {
1116         /* identifiers */
1117         ot->name = "Select Random";
1118         ot->description = "Set select on random visible objects";
1119         ot->idname = "OBJECT_OT_select_random";
1120         
1121         /* api callbacks */
1122         /*ot->invoke = object_select_random_invoke XXX - need a number popup ;*/
1123         ot->exec = object_select_random_exec;
1124         ot->poll = objects_selectable_poll;
1125         
1126         /* flags */
1127         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1128         
1129         /* properties */
1130         RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, "Percent", "Percentage of objects to select randomly", 0.f, 100.0f);
1131         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend Selection", "Extend selection instead of deselecting everything first");
1132 }