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