code cleanup: BKE_libblock_find_name() now takes an ID constant rather then a string.
[blender.git] / source / blender / editors / object / object_select.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation, 2002-2008 full recode
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/object/object_select.c
27  *  \ingroup edobj
28  */
29
30
31 #include <ctype.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "DNA_anim_types.h"
39 #include "DNA_group_types.h"
40 #include "DNA_material_types.h"
41 #include "DNA_modifier_types.h"
42 #include "DNA_property_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_armature_types.h"
45
46 #include "BLI_math.h"
47 #include "BLI_listbase.h"
48 #include "BLI_rand.h"
49 #include "BLI_string.h"
50 #include "BLI_utildefines.h"
51
52 #include "BKE_context.h"
53 #include "BKE_group.h"
54 #include "BKE_main.h"
55 #include "BKE_material.h"
56 #include "BKE_particle.h"
57 #include "BKE_property.h"
58 #include "BKE_report.h"
59 #include "BKE_scene.h"
60 #include "BKE_library.h"
61 #include "BKE_deform.h"
62
63 #include "WM_api.h"
64 #include "WM_types.h"
65
66 #include "ED_object.h"
67 #include "ED_screen.h"
68 #include "ED_keyframing.h"
69
70 #include "UI_interface.h"
71 #include "UI_resources.h"
72
73 #include "RNA_access.h"
74 #include "RNA_define.h"
75 #include "RNA_enum_types.h"
76
77 #include "object_intern.h"
78
79 /************************ Exported **************************/
80
81 /* simple API for object selection, rather than just using the flag
82 * this takes into account the 'restrict selection in 3d view' flag.
83 * deselect works always, the restriction just prevents selection */
84
85 /* Note: send a NC_SCENE|ND_OB_SELECT notifier yourself! (or 
86  * or a NC_SCENE|ND_OB_VISIBLE in case of visibility toggling */
87
88 void ED_base_object_select(Base *base, short mode)
89 {
90         if (base) {
91                 if (mode == BA_SELECT) {
92                         if (!(base->object->restrictflag & OB_RESTRICT_SELECT))
93                                 base->flag |= SELECT;
94                 }
95                 else if (mode == BA_DESELECT) {
96                         base->flag &= ~SELECT;
97                 }
98                 base->object->flag = base->flag;
99         }
100 }
101
102 /* also to set active NULL */
103 void ED_base_object_activate(bContext *C, Base *base)
104 {
105         Scene *scene = CTX_data_scene(C);
106         
107         /* sets scene->basact */
108         BASACT = base;
109         
110         if (base) {
111                 
112                 /* XXX old signals, remember to handle notifiers now! */
113                 //              select_actionchannel_by_name(base->object->action, "Object", 1);
114                 
115                 WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
116         }
117         else
118                 WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, NULL);
119 }
120
121 /********************** Selection Operators **********************/
122
123 static int objects_selectable_poll(bContext *C)
124 {
125         /* we don't check for linked scenes here, selection is
126          * still allowed then for inspection of scene */
127         Object *obact = CTX_data_active_object(C);
128
129         if (CTX_data_edit_object(C))
130                 return 0;
131         if (obact && obact->mode)
132                 return 0;
133         
134         return 1;
135 }
136
137 /************************ Select by Type *************************/
138
139 static int object_select_by_type_exec(bContext *C, wmOperator *op)
140 {
141         short obtype, extend;
142         
143         obtype = RNA_enum_get(op->ptr, "type");
144         extend = RNA_boolean_get(op->ptr, "extend");
145                 
146         if (extend == 0) {
147                 CTX_DATA_BEGIN (C, Base *, base, visible_bases)
148                 {
149                         ED_base_object_select(base, BA_DESELECT);
150                 }
151                 CTX_DATA_END;
152         }
153         
154         CTX_DATA_BEGIN (C, Base *, base, visible_bases)
155         {
156                 if (base->object->type == obtype) {
157                         ED_base_object_select(base, BA_SELECT);
158                 }
159         }
160         CTX_DATA_END;
161         
162         WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
163         
164         return OPERATOR_FINISHED;
165 }
166
167 void OBJECT_OT_select_by_type(wmOperatorType *ot)
168 {
169         /* identifiers */
170         ot->name = "Select By Type";
171         ot->description = "Select all visible objects that are of a type";
172         ot->idname = "OBJECT_OT_select_by_type";
173         
174         /* api callbacks */
175         ot->invoke = WM_menu_invoke;
176         ot->exec = object_select_by_type_exec;
177         ot->poll = objects_selectable_poll;
178         
179         /* flags */
180         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
181         
182         /* properties */
183         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
184         ot->prop = RNA_def_enum(ot->srna, "type", object_type_items, 1, "Type", "");
185 }
186
187 /*********************** Selection by Links *********************/
188
189 static EnumPropertyItem prop_select_linked_types[] = {
190         //{1, "IPO", 0, "Object IPO", ""}, // XXX depreceated animation system stuff...
191         {2, "OBDATA", 0, "Object Data", ""},
192         {3, "MATERIAL", 0, "Material", ""},
193         {4, "TEXTURE", 0, "Texture", ""},
194         {5, "DUPGROUP", 0, "Dupligroup", ""},
195         {6, "PARTICLE", 0, "Particle System", ""},
196         {7, "LIBRARY", 0, "Library", ""},
197         {8, "LIBRARY_OBDATA", 0, "Library (Object Data)", ""},
198         {0, NULL, 0, NULL, NULL}
199 };
200
201 static int object_select_linked_exec(bContext *C, wmOperator *op)
202 {
203         Scene *scene = CTX_data_scene(C);
204         Object *ob;
205         void *obdata = NULL;
206         Material *mat = NULL, *mat1;
207         Tex *tex = NULL;
208         int a, b;
209         int nr = RNA_enum_get(op->ptr, "type");
210         short changed = 0, extend;
211         /* events (nr):
212          * Object Ipo: 1
213          * ObData: 2
214          * Current Material: 3
215          * Current Texture: 4
216          * DupliGroup: 5
217          * PSys: 6
218          */
219
220         extend = RNA_boolean_get(op->ptr, "extend");
221         
222         if (extend == 0) {
223                 CTX_DATA_BEGIN (C, Base *, base, visible_bases)
224                 {
225                         ED_base_object_select(base, BA_DESELECT);
226                 }
227                 CTX_DATA_END;
228         }
229         
230         ob = OBACT;
231         if (ob == NULL) {
232                 BKE_report(op->reports, RPT_ERROR, "No Active Object");
233                 return OPERATOR_CANCELLED;
234         }
235         
236         if (nr == 1) {
237                 // XXX old animation system
238                 //ipo= ob->ipo;
239                 //if (ipo==0) return OPERATOR_CANCELLED;
240                 return OPERATOR_CANCELLED;
241         }
242         else if (nr == 2) {
243                 if (ob->data == NULL) return OPERATOR_CANCELLED;
244                 obdata = ob->data;
245         }
246         else if (nr == 3 || nr == 4) {
247                 mat = give_current_material(ob, ob->actcol);
248                 if (mat == NULL) return OPERATOR_CANCELLED;
249                 if (nr == 4) {
250                         if (mat->mtex[(int)mat->texact]) tex = mat->mtex[(int)mat->texact]->tex;
251                         if (tex == NULL) return OPERATOR_CANCELLED;
252                 }
253         }
254         else if (nr == 5) {
255                 if (ob->dup_group == NULL) return OPERATOR_CANCELLED;
256         }
257         else if (nr == 6) {
258                 if (ob->particlesystem.first == NULL) return OPERATOR_CANCELLED;
259         }
260         else if (nr == 7) {
261                 /* do nothing */
262         }
263         else if (nr == 8) {
264                 if (ob->data == NULL) return OPERATOR_CANCELLED;
265         }
266         else
267                 return OPERATOR_CANCELLED;
268         
269         CTX_DATA_BEGIN (C, Base *, base, visible_bases)
270         {
271                 if (nr == 1) {
272                         // XXX old animation system
273                         //if (base->object->ipo==ipo) base->flag |= SELECT;
274                         //changed = 1;
275                 }
276                 else if (nr == 2) {
277                         if (base->object->data == obdata) base->flag |= SELECT;
278                         changed = 1;
279                 }
280                 else if (nr == 3 || nr == 4) {
281                         ob = base->object;
282                         
283                         for (a = 1; a <= ob->totcol; a++) {
284                                 mat1 = give_current_material(ob, a);
285                                 if (nr == 3) {
286                                         if (mat1 == mat) base->flag |= SELECT;
287                                         changed = 1;
288                                 }
289                                 else if (mat1 && nr == 4) {
290                                         for (b = 0; b < MAX_MTEX; b++) {
291                                                 if (mat1->mtex[b]) {
292                                                         if (tex == mat1->mtex[b]->tex) {
293                                                                 base->flag |= SELECT;
294                                                                 changed = 1;
295                                                                 break;
296                                                         }
297                                                 }
298                                         }
299                                 }
300                         }
301                 }
302                 else if (nr == 5) {
303                         if (base->object->dup_group == ob->dup_group) {
304                                 base->flag |= SELECT;
305                                 changed = 1;
306                         }
307                 }
308                 else if (nr == 6) {
309                         /* loop through other, then actives particles*/
310                         ParticleSystem *psys;
311                         ParticleSystem *psys_act;
312                         
313                         for (psys = base->object->particlesystem.first; psys; psys = psys->next) {
314                                 for (psys_act = ob->particlesystem.first; psys_act; psys_act = psys_act->next) {
315                                         if (psys->part == psys_act->part) {
316                                                 base->flag |= SELECT;
317                                                 changed = 1;
318                                                 break;
319                                         }
320                                 }
321                                 
322                                 if (base->flag & SELECT) {
323                                         break;
324                                 }
325                         }
326                 }
327                 else if (nr == 7) {
328                         if (ob->id.lib == base->object->id.lib) {
329                                 base->flag |= SELECT;
330                                 changed = 1;
331                         }
332                 }
333                 else if (nr == 8) {
334                         if (base->object->data && ((ID *)ob->data)->lib == ((ID *)base->object->data)->lib) {
335                                 base->flag |= SELECT;
336                                 changed = 1;
337                         }
338                 }
339                 base->object->flag = base->flag;
340         }
341         CTX_DATA_END;
342         
343         if (changed) {
344                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
345                 return OPERATOR_FINISHED;
346         }
347         
348         return OPERATOR_CANCELLED;
349 }
350
351 void OBJECT_OT_select_linked(wmOperatorType *ot)
352 {
353         /* identifiers */
354         ot->name = "Select Linked";
355         ot->description = "Select all visible objects that are linked";
356         ot->idname = "OBJECT_OT_select_linked";
357         
358         /* api callbacks */
359         ot->invoke = WM_menu_invoke;
360         ot->exec = object_select_linked_exec;
361         ot->poll = objects_selectable_poll;
362         
363         /* flags */
364         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
365         
366         /* properties */
367         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
368         ot->prop = RNA_def_enum(ot->srna, "type", prop_select_linked_types, 0, "Type", "");
369 }
370
371 /*********************** Selected Grouped ********************/
372
373 static EnumPropertyItem prop_select_grouped_types[] = {
374         {1, "CHILDREN_RECURSIVE", 0, "Children", ""},
375         {2, "CHILDREN", 0, "Immediate Children", ""},
376         {3, "PARENT", 0, "Parent", ""},
377         {4, "SIBLINGS", 0, "Siblings", "Shared Parent"},
378         {5, "TYPE", 0, "Type", "Shared object type"},
379         {6, "LAYER", 0, "Layer", "Shared layers"},
380         {7, "GROUP", 0, "Group", "Shared group"},
381         {8, "HOOK", 0, "Hook", ""},
382         {9, "PASS", 0, "Pass", "Render pass Index"},
383         {10, "COLOR", 0, "Color", "Object Color"},
384         {11, "PROPERTIES", 0, "Properties", "Game Properties"},
385         {12, "KEYINGSET", 0, "Keying Set", "Objects included in active Keying Set"},
386         {0, NULL, 0, NULL, NULL}
387 };
388
389 static short select_grouped_children(bContext *C, Object *ob, int recursive)
390 {
391         short changed = 0;
392
393         CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
394         {
395                 if (ob == base->object->parent) {
396                         if (!(base->flag & SELECT)) {
397                                 ED_base_object_select(base, BA_SELECT);
398                                 changed = 1;
399                         }
400
401                         if (recursive)
402                                 changed |= select_grouped_children(C, base->object, 1);
403                 }
404         }
405         CTX_DATA_END;
406         return changed;
407 }
408
409 static short select_grouped_parent(bContext *C) /* Makes parent active and de-selected OBACT */
410 {
411         Scene *scene = CTX_data_scene(C);
412         View3D *v3d = CTX_wm_view3d(C);
413
414         short changed = 0;
415         Base *baspar, *basact = CTX_data_active_base(C);
416
417         if (!basact || !(basact->object->parent)) return 0;  /* we know OBACT is valid */
418
419         baspar = BKE_scene_base_find(scene, basact->object->parent);
420
421         /* can be NULL if parent in other scene */
422         if (baspar && BASE_SELECTABLE(v3d, baspar)) {
423                 ED_base_object_select(basact, BA_DESELECT);
424                 ED_base_object_select(baspar, BA_SELECT);
425                 ED_base_object_activate(C, baspar);
426                 changed = 1;
427         }
428         return changed;
429 }
430
431
432 #define GROUP_MENU_MAX  24
433 static short select_grouped_group(bContext *C, Object *ob)  /* Select objects in the same group as the active */
434 {
435         short changed = 0;
436         Group *group, *ob_groups[GROUP_MENU_MAX];
437         int group_count = 0, i;
438         uiPopupMenu *pup;
439         uiLayout *layout;
440
441         for (group = CTX_data_main(C)->group.first; group && group_count < GROUP_MENU_MAX; group = group->id.next) {
442                 if (object_in_group(ob, group)) {
443                         ob_groups[group_count] = group;
444                         group_count++;
445                 }
446         }
447
448         if (!group_count)
449                 return 0;
450         else if (group_count == 1) {
451                 group = ob_groups[0];
452                 CTX_DATA_BEGIN (C, Base *, base, visible_bases)
453                 {
454                         if (!(base->flag & SELECT) && object_in_group(base->object, group)) {
455                                 ED_base_object_select(base, BA_SELECT);
456                                 changed = 1;
457                         }
458                 }
459                 CTX_DATA_END;
460                 return changed;
461         }
462
463         /* build the menu. */
464         pup = uiPupMenuBegin(C, "Select Group", ICON_NONE);
465         layout = uiPupMenuLayout(pup);
466
467         for (i = 0; i < group_count; i++) {
468                 group = ob_groups[i];
469                 uiItemStringO(layout, group->id.name + 2, 0, "OBJECT_OT_select_same_group", "group", group->id.name);
470         }
471
472         uiPupMenuEnd(C, pup);
473         return changed; // The operator already handle this!
474 }
475
476 static short select_grouped_object_hooks(bContext *C, Object *ob)
477 {
478         Scene *scene = CTX_data_scene(C);
479         View3D *v3d = CTX_wm_view3d(C);
480
481         short changed = 0;
482         Base *base;
483         ModifierData *md;
484         HookModifierData *hmd;
485
486         for (md = ob->modifiers.first; md; md = md->next) {
487                 if (md->type == eModifierType_Hook) {
488                         hmd = (HookModifierData *) md;
489                         if (hmd->object && !(hmd->object->flag & SELECT)) {
490                                 base = BKE_scene_base_find(scene, hmd->object);
491                                 if (base && (BASE_SELECTABLE(v3d, base))) {
492                                         ED_base_object_select(base, BA_SELECT);
493                                         changed = 1;
494                                 }
495                         }
496                 }
497         }
498         return changed;
499 }
500
501 /* Select objects with the same parent as the active (siblings),
502  * parent can be NULL also */
503 static short select_grouped_siblings(bContext *C, Object *ob)
504 {
505         short changed = 0;
506
507         CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
508         {
509                 if ((base->object->parent == ob->parent)  && !(base->flag & SELECT)) {
510                         ED_base_object_select(base, BA_SELECT);
511                         changed = 1;
512                 }
513         }
514         CTX_DATA_END;
515         return changed;
516 }
517
518 static short select_grouped_type(bContext *C, Object *ob)
519 {
520         short changed = 0;
521
522         CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
523         {
524                 if ((base->object->type == ob->type) && !(base->flag & SELECT)) {
525                         ED_base_object_select(base, BA_SELECT);
526                         changed = 1;
527                 }
528         }
529         CTX_DATA_END;
530         return changed;
531 }
532
533 static short select_grouped_layer(bContext *C, Object *ob)
534 {
535         char changed = 0;
536
537         CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
538         {
539                 if ((base->lay & ob->lay) && !(base->flag & SELECT)) {
540                         ED_base_object_select(base, BA_SELECT);
541                         changed = 1;
542                 }
543         }
544         CTX_DATA_END;
545         return changed;
546 }
547
548 static short select_grouped_index_object(bContext *C, Object *ob)
549 {
550         char changed = 0;
551
552         CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
553         {
554                 if ((base->object->index == ob->index) && !(base->flag & SELECT)) {
555                         ED_base_object_select(base, BA_SELECT);
556                         changed = 1;
557                 }
558         }
559         CTX_DATA_END;
560         return changed;
561 }
562
563 static short select_grouped_color(bContext *C, Object *ob)
564 {
565         char changed = 0;
566
567         CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
568         {
569                 if (!(base->flag & SELECT) && (compare_v3v3(base->object->col, ob->col, 0.005f))) {
570                         ED_base_object_select(base, BA_SELECT);
571                         changed = 1;
572                 }
573         }
574         CTX_DATA_END;
575         return changed;
576 }
577
578 static short objects_share_gameprop(Object *a, Object *b)
579 {
580         bProperty *prop;
581         /*make a copy of all its properties*/
582
583         for (prop = a->prop.first; prop; prop = prop->next) {
584                 if (get_ob_property(b, prop->name) )
585                         return 1;
586         }
587         return 0;
588 }
589
590 static short select_grouped_gameprops(bContext *C, Object *ob)
591 {
592         char changed = 0;
593
594         CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
595         {
596                 if (!(base->flag & SELECT) && (objects_share_gameprop(base->object, ob))) {
597                         ED_base_object_select(base, BA_SELECT);
598                         changed = 1;
599                 }
600         }
601         CTX_DATA_END;
602         return changed;
603 }
604
605 static short select_grouped_keyingset(bContext *C, Object *UNUSED(ob))
606 {
607         KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C));
608         short changed = 0;
609         
610         /* firstly, validate KeyingSet */
611         if ((ks == NULL) || (ANIM_validate_keyingset(C, NULL, ks) != 0))
612                 return 0;
613         
614         /* select each object that Keying Set refers to */
615         // TODO: perhaps to be more in line with the rest of these, we should only take objects 
616         // if the passed in object is included in this too
617         CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
618         {
619                 /* only check for this object if it isn't selected already, to limit time wasted */
620                 if ((base->flag & SELECT) == 0) {
621                         KS_Path *ksp;
622                         
623                         /* this is the slow way... we could end up with > 500 items here, 
624                          * with none matching, but end up doing this on 1000 objects...
625                          */
626                         for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
627                                 /* if id matches, select then stop looping (match found) */
628                                 if (ksp->id == (ID *)base->object) {
629                                         ED_base_object_select(base, BA_SELECT);
630                                         changed = 1;
631                                         break;
632                                 }
633                         }
634                 }
635         }
636         CTX_DATA_END;
637                 
638         return changed;
639 }
640
641 static int object_select_grouped_exec(bContext *C, wmOperator *op)
642 {
643         Scene *scene = CTX_data_scene(C);
644         Object *ob;
645         int nr = RNA_enum_get(op->ptr, "type");
646         short changed = 0, extend;
647
648         extend = RNA_boolean_get(op->ptr, "extend");
649         
650         if (extend == 0) {
651                 CTX_DATA_BEGIN (C, Base *, base, visible_bases)
652                 {
653                         ED_base_object_select(base, BA_DESELECT);
654                         changed = 1;
655                 }
656                 CTX_DATA_END;
657         }
658         
659         ob = OBACT;
660         if (ob == NULL) {
661                 BKE_report(op->reports, RPT_ERROR, "No Active Object");
662                 return OPERATOR_CANCELLED;
663         }
664         
665         if      (nr == 1) changed |= select_grouped_children(C, ob, 1);
666         else if (nr == 2) changed |= select_grouped_children(C, ob, 0);
667         else if (nr == 3) changed |= select_grouped_parent(C);
668         else if (nr == 4) changed |= select_grouped_siblings(C, ob);
669         else if (nr == 5) changed |= select_grouped_type(C, ob);
670         else if (nr == 6) changed |= select_grouped_layer(C, ob);
671         else if (nr == 7) changed |= select_grouped_group(C, ob);
672         else if (nr == 8) changed |= select_grouped_object_hooks(C, ob);
673         else if (nr == 9) changed |= select_grouped_index_object(C, ob);
674         else if (nr == 10) changed |= select_grouped_color(C, ob);
675         else if (nr == 11) changed |= select_grouped_gameprops(C, ob);
676         else if (nr == 12) changed |= select_grouped_keyingset(C, ob);
677         
678         if (changed) {
679                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
680                 return OPERATOR_FINISHED;
681         }
682         
683         return OPERATOR_CANCELLED;
684 }
685
686 void OBJECT_OT_select_grouped(wmOperatorType *ot)
687 {
688         /* identifiers */
689         ot->name = "Select Grouped";
690         ot->description = "Select all visible objects grouped by various properties";
691         ot->idname = "OBJECT_OT_select_grouped";
692         
693         /* api callbacks */
694         ot->invoke = WM_menu_invoke;
695         ot->exec = object_select_grouped_exec;
696         ot->poll = objects_selectable_poll;
697         
698         /* flags */
699         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
700         
701         /* properties */
702         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
703         ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
704 }
705
706 /************************* Select by Layer **********************/
707
708 static int object_select_by_layer_exec(bContext *C, wmOperator *op)
709 {
710         unsigned int layernum;
711         short extend;
712         
713         extend = RNA_boolean_get(op->ptr, "extend");
714         layernum = RNA_int_get(op->ptr, "layers");
715         
716         if (extend == 0) {
717                 CTX_DATA_BEGIN (C, Base *, base, visible_bases)
718                 {
719                         ED_base_object_select(base, BA_DESELECT);
720                 }
721                 CTX_DATA_END;
722         }
723                 
724         CTX_DATA_BEGIN (C, Base *, base, visible_bases)
725         {
726                 if (base->lay == (1 << (layernum - 1)))
727                         ED_base_object_select(base, BA_SELECT);
728         }
729         CTX_DATA_END;
730         
731         /* undo? */
732         WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
733         
734         return OPERATOR_FINISHED;
735 }
736
737 void OBJECT_OT_select_by_layer(wmOperatorType *ot)
738 {
739         /* identifiers */
740         ot->name = "Select by Layer";
741         ot->description = "Select all visible objects on a layer";
742         ot->idname = "OBJECT_OT_select_by_layer";
743         
744         /* api callbacks */
745         /*ot->invoke = XXX - need a int grid popup*/
746         ot->exec = object_select_by_layer_exec;
747         ot->poll = objects_selectable_poll;
748         
749         /* flags */
750         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
751         
752         /* properties */
753         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
754         RNA_def_int(ot->srna, "layers", 1, 1, 20, "Layer", "", 1, 20);
755 }
756
757 /**************************** (De)select All ****************************/
758
759 static int object_select_all_exec(bContext *C, wmOperator *op)
760 {
761         int action = RNA_enum_get(op->ptr, "action");
762         
763         /* passthrough if no objects are visible */
764         if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH;
765
766         if (action == SEL_TOGGLE) {
767                 action = SEL_SELECT;
768                 CTX_DATA_BEGIN (C, Base *, base, visible_bases)
769                 {
770                         if (base->flag & SELECT) {
771                                 action = SEL_DESELECT;
772                                 break;
773                         }
774                 }
775                 CTX_DATA_END;
776         }
777
778         CTX_DATA_BEGIN (C, Base *, base, visible_bases)
779         {
780                 switch (action) {
781                         case SEL_SELECT:
782                                 ED_base_object_select(base, BA_SELECT);
783                                 break;
784                         case SEL_DESELECT:
785                                 ED_base_object_select(base, BA_DESELECT);
786                                 break;
787                         case SEL_INVERT:
788                                 if (base->flag & SELECT) {
789                                         ED_base_object_select(base, BA_DESELECT);
790                                 }
791                                 else {
792                                         ED_base_object_select(base, BA_SELECT);
793                                 }
794                                 break;
795                 }
796         }
797         CTX_DATA_END;
798         
799         WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
800         
801         return OPERATOR_FINISHED;
802 }
803
804 void OBJECT_OT_select_all(wmOperatorType *ot)
805 {
806         
807         /* identifiers */
808         ot->name = "(De)select All";
809         ot->description = "Change selection of all visible objects in scene";
810         ot->idname = "OBJECT_OT_select_all";
811         
812         /* api callbacks */
813         ot->exec = object_select_all_exec;
814         ot->poll = objects_selectable_poll;
815         
816         /* flags */
817         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
818
819         WM_operator_properties_select_all(ot);
820 }
821
822 /**************************** Select In The Same Group ****************************/
823
824 static int object_select_same_group_exec(bContext *C, wmOperator *op)
825 {
826         Group *group;
827         char group_name[MAX_ID_NAME];
828
829         /* passthrough if no objects are visible */
830         if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH;
831
832         RNA_string_get(op->ptr, "group", group_name);
833
834         for (group = CTX_data_main(C)->group.first; group; group = group->id.next) {
835                 if (!strcmp(group->id.name, group_name))
836                         break;
837         }
838
839         if (!group)
840                 return OPERATOR_PASS_THROUGH;
841
842         CTX_DATA_BEGIN (C, Base *, base, visible_bases)
843         {
844                 if (!(base->flag & SELECT) && object_in_group(base->object, group))
845                         ED_base_object_select(base, BA_SELECT);
846         }
847         CTX_DATA_END;
848
849         WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
850         
851         return OPERATOR_FINISHED;
852 }
853
854 void OBJECT_OT_select_same_group(wmOperatorType *ot)
855 {
856         
857         /* identifiers */
858         ot->name = "Select Same Group";
859         ot->description = "Select object in the same group";
860         ot->idname = "OBJECT_OT_select_same_group";
861         
862         /* api callbacks */
863         ot->exec = object_select_same_group_exec;
864         ot->poll = objects_selectable_poll;
865         
866         /* flags */
867         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
868
869         RNA_def_string(ot->srna, "group", "", MAX_ID_NAME, "Group", "Name of the group to select");
870 }
871
872 /**************************** Select Mirror ****************************/
873 static int object_select_mirror_exec(bContext *C, wmOperator *op)
874 {
875         Scene *scene = CTX_data_scene(C);
876         short extend;
877         
878         extend = RNA_boolean_get(op->ptr, "extend");
879         
880         CTX_DATA_BEGIN (C, Base *, primbase, selected_bases)
881         {
882                 char tmpname[MAXBONENAME];
883
884                 flip_side_name(tmpname, primbase->object->id.name + 2, TRUE);
885                 
886                 if (strcmp(tmpname, primbase->object->id.name + 2) != 0) { /* names differ */
887                         Object *ob = (Object *)BKE_libblock_find_name(ID_OB, tmpname);
888                         if (ob) {
889                                 Base *secbase = BKE_scene_base_find(scene, ob);
890
891                                 if (secbase) {
892                                         ED_base_object_select(secbase, BA_SELECT);
893                                 }
894                         }
895                 }
896                 
897                 if (extend == 0) ED_base_object_select(primbase, BA_DESELECT);
898                 
899         }
900         CTX_DATA_END;
901         
902         /* undo? */
903         WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
904         
905         return OPERATOR_FINISHED;
906 }
907
908 void OBJECT_OT_select_mirror(wmOperatorType *ot)
909 {
910         
911         /* identifiers */
912         ot->name = "Select Mirror";
913         ot->description = "Select the Mirror objects of the selected object eg. L.sword -> R.sword";
914         ot->idname = "OBJECT_OT_select_mirror";
915         
916         /* api callbacks */
917         ot->exec = object_select_mirror_exec;
918         ot->poll = objects_selectable_poll;
919         
920         /* flags */
921         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
922         
923         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first");
924 }
925
926
927 /**************************** Select Random ****************************/
928
929 static int object_select_random_exec(bContext *C, wmOperator *op)
930 {       
931         float percent;
932         short extend;
933         
934         extend = RNA_boolean_get(op->ptr, "extend");
935         
936         if (extend == 0) {
937                 CTX_DATA_BEGIN (C, Base *, base, visible_bases)
938                 {
939                         ED_base_object_select(base, BA_DESELECT);
940                 }
941                 CTX_DATA_END;
942         }
943         percent = RNA_float_get(op->ptr, "percent") / 100.0f;
944                 
945         CTX_DATA_BEGIN (C, Base *, base, visible_bases)
946         {
947                 if (BLI_frand() < percent) {
948                         ED_base_object_select(base, BA_SELECT);
949                 }
950         }
951         CTX_DATA_END;
952         
953         WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
954         
955         return OPERATOR_FINISHED;
956 }
957
958 void OBJECT_OT_select_random(wmOperatorType *ot)
959 {
960         /* identifiers */
961         ot->name = "Select Random";
962         ot->description = "Set select on random visible objects";
963         ot->idname = "OBJECT_OT_select_random";
964         
965         /* api callbacks */
966         /*ot->invoke = object_select_random_invoke XXX - need a number popup ;*/
967         ot->exec = object_select_random_exec;
968         ot->poll = objects_selectable_poll;
969         
970         /* flags */
971         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
972         
973         /* properties */
974         RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, "Percent", "Percentage of objects to select randomly", 0.f, 100.0f);
975         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend Selection", "Extend selection instead of deselecting everything first");
976 }
977
978