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