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