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