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