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