ID-Remap - Step one: core work (cleanup and rework of generic ID datablock handling).
[blender.git] / source / blender / editors / object / object_group.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) Blender Foundation
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/object/object_group.c
29  *  \ingroup edobj
30  */
31
32
33 #include <string.h>
34
35 #include "BLI_blenlib.h"
36 #include "BLI_utildefines.h"
37
38 #include "DNA_group_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_scene_types.h"
41
42 #include "BKE_context.h"
43 #include "BKE_depsgraph.h"
44 #include "BKE_group.h"
45 #include "BKE_library.h"
46 #include "BKE_library_remap.h"
47 #include "BKE_main.h"
48 #include "BKE_report.h"
49 #include "BKE_object.h"
50
51 #include "ED_screen.h"
52 #include "ED_object.h"
53
54 #include "WM_api.h"
55 #include "WM_types.h"
56
57 #include "RNA_access.h"
58 #include "RNA_define.h"
59 #include "RNA_enum_types.h"
60
61 #include "object_intern.h"
62
63 /********************* 3d view operators ***********************/
64
65 /* can be called with C == NULL */
66 static EnumPropertyItem *group_object_active_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
67 {
68         Object *ob;
69         EnumPropertyItem *item = NULL, item_tmp = {0};
70         int totitem = 0;
71
72         if (C == NULL) {
73                 return DummyRNA_NULL_items;
74         }
75
76         ob = ED_object_context(C);
77
78         /* check that the object exists */
79         if (ob) {
80                 Group *group;
81                 int i = 0, count = 0;
82
83                 /* if 2 or more groups, add option to add to all groups */
84                 group = NULL;
85                 while ((group = BKE_group_object_find(group, ob)))
86                         count++;
87
88                 if (count >= 2) {
89                         item_tmp.identifier = item_tmp.name = "All Groups";
90                         item_tmp.value = INT_MAX; /* this will give NULL on lookup */
91                         RNA_enum_item_add(&item, &totitem, &item_tmp);
92                         RNA_enum_item_add_separator(&item, &totitem);
93                 }
94
95                 /* add groups */
96                 group = NULL;
97                 while ((group = BKE_group_object_find(group, ob))) {
98                         item_tmp.identifier = item_tmp.name = group->id.name + 2;
99                         /* item_tmp.icon = ICON_ARMATURE_DATA; */
100                         item_tmp.value = i;
101                         RNA_enum_item_add(&item, &totitem, &item_tmp);
102                         i++;
103                 }
104         }
105
106         RNA_enum_item_end(&item, &totitem);
107         *r_free = true;
108
109         return item;
110 }
111
112 /* get the group back from the enum index, quite awkward and UI specific */
113 static Group *group_object_active_find_index(Object *ob, const int group_object_index)
114 {
115         Group *group = NULL;
116         int i = 0;
117         while ((group = BKE_group_object_find(group, ob))) {
118                 if (i == group_object_index) {
119                         break;
120                 }
121                 i++;
122         }
123
124         return group;
125 }
126
127 static int objects_add_active_exec(bContext *C, wmOperator *op)
128 {
129         Object *ob = ED_object_context(C);
130         Main *bmain = CTX_data_main(C);
131         Scene *scene = CTX_data_scene(C);
132         int single_group_index = RNA_enum_get(op->ptr, "group");
133         Group *single_group = group_object_active_find_index(ob, single_group_index);
134         Group *group;
135         bool is_cycle = false;
136         bool updated = false;
137
138         if (ob == NULL)
139                 return OPERATOR_CANCELLED;
140
141         /* now add all selected objects to the group(s) */
142         for (group = bmain->group.first; group; group = group->id.next) {
143                 if (single_group && group != single_group)
144                         continue;
145                 if (!BKE_group_object_exists(group, ob))
146                         continue;
147
148                 CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
149                 {
150                         if (BKE_group_object_exists(group, base->object))
151                                 continue;
152
153                         if (!BKE_group_object_cyclic_check(bmain, base->object, group)) {
154                                 BKE_group_object_add(group, base->object, scene, base);
155                                 updated = true;
156                         }
157                         else {
158                                 is_cycle = true;
159                         }
160                 }
161                 CTX_DATA_END;
162         }
163
164         if (is_cycle)
165                 BKE_report(op->reports, RPT_WARNING, "Skipped some groups because of cycle detected");
166
167         if (!updated)
168                 return OPERATOR_CANCELLED;
169
170         DAG_relations_tag_update(bmain);
171         WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
172
173         return OPERATOR_FINISHED;
174 }
175
176 void GROUP_OT_objects_add_active(wmOperatorType *ot)
177 {
178         PropertyRNA *prop;
179
180         /* identifiers */
181         ot->name = "Add Selected To Active Group";
182         ot->description = "Add the object to an object group that contains the active object";
183         ot->idname = "GROUP_OT_objects_add_active";
184         
185         /* api callbacks */
186         ot->exec = objects_add_active_exec;
187         ot->invoke = WM_menu_invoke;
188         ot->poll = ED_operator_objectmode;
189
190         /* flags */
191         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
192
193         /* properties */
194         prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "The group to add other selected objects to");
195         RNA_def_enum_funcs(prop, group_object_active_itemf);
196         RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
197         ot->prop = prop;
198 }
199
200 static int objects_remove_active_exec(bContext *C, wmOperator *op)
201 {
202         Main *bmain = CTX_data_main(C);
203         Scene *scene = CTX_data_scene(C);
204         Object *ob = OBACT;
205         int single_group_index = RNA_enum_get(op->ptr, "group");
206         Group *single_group = group_object_active_find_index(ob, single_group_index);
207         Group *group;
208         bool ok = false;
209         
210         if (ob == NULL)
211                 return OPERATOR_CANCELLED;
212         
213         /* linking to same group requires its own loop so we can avoid
214          * looking up the active objects groups each time */
215
216         for (group = bmain->group.first; group; group = group->id.next) {
217                 if (single_group && group != single_group)
218                         continue;
219
220                 if (BKE_group_object_exists(group, ob)) {
221                         /* Remove groups from selected objects */
222                         CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
223                         {
224                                 BKE_group_object_unlink(group, base->object, scene, base);
225                                 ok = 1;
226                         }
227                         CTX_DATA_END;
228                 }
229         }
230         
231         if (!ok)
232                 BKE_report(op->reports, RPT_ERROR, "Active object contains no groups");
233         
234         DAG_relations_tag_update(bmain);
235         WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
236         
237         return OPERATOR_FINISHED;
238 }
239
240 void GROUP_OT_objects_remove_active(wmOperatorType *ot)
241 {
242         PropertyRNA *prop;
243
244         /* identifiers */
245         ot->name = "Remove Selected From Active Group";
246         ot->description = "Remove the object from an object group that contains the active object";
247         ot->idname = "GROUP_OT_objects_remove_active";
248         
249         /* api callbacks */
250         ot->exec = objects_remove_active_exec;
251         ot->invoke = WM_menu_invoke;
252         ot->poll = ED_operator_objectmode;
253         
254         /* flags */
255         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
256
257         /* properties */
258         prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "The group to remove other selected objects from");
259         RNA_def_enum_funcs(prop, group_object_active_itemf);
260         RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
261         ot->prop = prop;
262 }
263
264 static int group_objects_remove_all_exec(bContext *C, wmOperator *UNUSED(op))
265 {
266         Main *bmain = CTX_data_main(C);
267         Scene *scene = CTX_data_scene(C);
268
269         CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
270         {
271                 BKE_object_groups_clear(scene, base, base->object);
272         }
273         CTX_DATA_END;
274
275         DAG_relations_tag_update(bmain);
276         WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
277         
278         return OPERATOR_FINISHED;
279 }
280
281 void GROUP_OT_objects_remove_all(wmOperatorType *ot)
282 {
283         /* identifiers */
284         ot->name = "Remove From All Groups";
285         ot->description = "Remove selected objects from all groups";
286         ot->idname = "GROUP_OT_objects_remove_all";
287         
288         /* api callbacks */
289         ot->exec = group_objects_remove_all_exec;
290         ot->poll = ED_operator_objectmode;
291         
292         /* flags */
293         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
294 }
295
296 static int group_objects_remove_exec(bContext *C, wmOperator *op)
297 {
298         Object *ob = ED_object_context(C);
299         Main *bmain = CTX_data_main(C);
300         Scene *scene = CTX_data_scene(C);
301         int single_group_index = RNA_enum_get(op->ptr, "group");
302         Group *single_group = group_object_active_find_index(ob, single_group_index);
303         Group *group;
304         bool updated = false;
305
306         if (ob == NULL)
307                 return OPERATOR_CANCELLED;
308
309         for (group = bmain->group.first; group; group = group->id.next) {
310                 if (single_group && group != single_group)
311                         continue;
312                 if (!BKE_group_object_exists(group, ob))
313                         continue;
314
315                 /* now remove all selected objects from the group */
316                 CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
317                 {
318                         BKE_group_object_unlink(group, base->object, scene, base);
319                         updated = true;
320                 }
321                 CTX_DATA_END;
322         }
323
324         if (!updated)
325                 return OPERATOR_CANCELLED;
326
327         DAG_relations_tag_update(bmain);
328         WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
329
330         return OPERATOR_FINISHED;
331 }
332
333 void GROUP_OT_objects_remove(wmOperatorType *ot)
334 {
335         PropertyRNA *prop;
336
337         /* identifiers */
338         ot->name = "Remove From Group";
339         ot->description = "Remove selected objects from a group";
340         ot->idname = "GROUP_OT_objects_remove";
341
342         /* api callbacks */
343         ot->exec = group_objects_remove_exec;
344         ot->invoke = WM_menu_invoke;
345         ot->poll = ED_operator_objectmode;
346
347         /* flags */
348         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
349
350         /* properties */
351         prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "The group to remove this object from");
352         RNA_def_enum_funcs(prop, group_object_active_itemf);
353         RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
354         ot->prop = prop;
355 }
356
357 static int group_create_exec(bContext *C, wmOperator *op)
358 {
359         Main *bmain = CTX_data_main(C);
360         Scene *scene = CTX_data_scene(C);
361         Group *group = NULL;
362         char name[MAX_ID_NAME - 2]; /* id name */
363         
364         RNA_string_get(op->ptr, "name", name);
365         
366         group = BKE_group_add(bmain, name);
367                 
368         CTX_DATA_BEGIN (C, Base *, base, selected_bases)
369         {
370                 BKE_group_object_add(group, base->object, scene, base);
371         }
372         CTX_DATA_END;
373
374         DAG_relations_tag_update(bmain);
375         WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
376         
377         return OPERATOR_FINISHED;
378 }
379
380 void GROUP_OT_create(wmOperatorType *ot)
381 {
382         /* identifiers */
383         ot->name = "Create New Group";
384         ot->description = "Create an object group from selected objects";
385         ot->idname = "GROUP_OT_create";
386         
387         /* api callbacks */
388         ot->exec = group_create_exec;
389         ot->poll = ED_operator_objectmode;
390         
391         /* flags */
392         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
393         
394         RNA_def_string(ot->srna, "name", "Group", MAX_ID_NAME - 2, "Name", "Name of the new group");
395 }
396
397 /****************** properties window operators *********************/
398
399 static int group_add_exec(bContext *C, wmOperator *UNUSED(op))
400 {
401         Scene *scene = CTX_data_scene(C);
402         Object *ob = ED_object_context(C);
403         Main *bmain = CTX_data_main(C);
404         Group *group;
405
406         if (ob == NULL)
407                 return OPERATOR_CANCELLED;
408
409         group = BKE_group_add(bmain, "Group");
410         BKE_group_object_add(group, ob, scene, NULL);
411
412         WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
413
414         return OPERATOR_FINISHED;
415 }
416
417 void OBJECT_OT_group_add(wmOperatorType *ot)
418 {
419         /* identifiers */
420         ot->name = "Add to Group";
421         ot->idname = "OBJECT_OT_group_add";
422         ot->description = "Add an object to a new group";
423         
424         /* api callbacks */
425         ot->exec = group_add_exec;
426         ot->poll = ED_operator_objectmode;
427
428         /* flags */
429         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
430 }
431
432 static int group_link_exec(bContext *C, wmOperator *op)
433 {
434         Main *bmain = CTX_data_main(C);
435         Scene *scene = CTX_data_scene(C);
436         Object *ob = ED_object_context(C);
437         Group *group = BLI_findlink(&bmain->group, RNA_enum_get(op->ptr, "group"));
438
439         if (ELEM(NULL, ob, group))
440                 return OPERATOR_CANCELLED;
441
442         /* Early return check, if the object is already in group
443          * we could sckip all the dependency check and just consider
444          * operator is finished.
445          */
446         if (BKE_group_object_exists(group, ob)) {
447                 return OPERATOR_FINISHED;
448         }
449
450         /* Adding object to group which is used as dupligroup for self is bad idea.
451          *
452          * It is also  bad idea to add object to group which is in group which
453          * contains our current object.
454          */
455         if (BKE_group_object_cyclic_check(bmain, ob, group)) {
456                 BKE_report(op->reports, RPT_ERROR, "Could not add the group because of dependency cycle detected");
457                 return OPERATOR_CANCELLED;
458         }
459
460         BKE_group_object_add(group, ob, scene, NULL);
461
462         WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
463
464         return OPERATOR_FINISHED;
465 }
466
467 void OBJECT_OT_group_link(wmOperatorType *ot)
468 {
469         PropertyRNA *prop;
470
471         /* identifiers */
472         ot->name = "Link to Group";
473         ot->idname = "OBJECT_OT_group_link";
474         ot->description = "Add an object to an existing group";
475         
476         /* api callbacks */
477         ot->exec = group_link_exec;
478         ot->invoke = WM_enum_search_invoke;
479         ot->poll = ED_operator_objectmode;
480
481         /* flags */
482         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
483
484         /* properties */
485         prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "");
486         RNA_def_enum_funcs(prop, RNA_group_local_itemf);
487         RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
488         ot->prop = prop;
489 }
490
491 static int group_remove_exec(bContext *C, wmOperator *UNUSED(op))
492 {
493         Scene *scene = CTX_data_scene(C);
494         Object *ob = ED_object_context(C);
495         Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data;
496
497         if (!ob || !group)
498                 return OPERATOR_CANCELLED;
499
500         BKE_group_object_unlink(group, ob, scene, NULL); /* base will be used if found */
501
502         WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
503         
504         return OPERATOR_FINISHED;
505 }
506
507 void OBJECT_OT_group_remove(wmOperatorType *ot)
508 {
509         /* identifiers */
510         ot->name = "Remove Group";
511         ot->idname = "OBJECT_OT_group_remove";
512         ot->description = "Remove the active object from this group";
513         
514         /* api callbacks */
515         ot->exec = group_remove_exec;
516         ot->poll = ED_operator_objectmode;
517
518         /* flags */
519         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
520 }
521
522
523 static int group_unlink_exec(bContext *C, wmOperator *UNUSED(op))
524 {
525         Main *bmain = CTX_data_main(C);
526         Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data;
527
528         if (!group)
529                 return OPERATOR_CANCELLED;
530
531         BKE_libblock_unlink(bmain, group, false);
532         BKE_libblock_free(bmain, group);
533
534         WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
535
536         return OPERATOR_FINISHED;
537 }
538
539 void OBJECT_OT_group_unlink(wmOperatorType *ot)
540 {
541         /* identifiers */
542         ot->name = "Unlink Group";
543         ot->idname = "OBJECT_OT_group_unlink";
544         ot->description = "Unlink the group from all objects";
545
546         /* api callbacks */
547         ot->exec = group_unlink_exec;
548         ot->poll = ED_operator_objectmode;
549
550         /* flags */
551         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
552 }
553
554 static int select_grouped_exec(bContext *C, wmOperator *UNUSED(op))  /* Select objects in the same group as the active */
555 {
556         Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data;
557
558         if (!group)
559                 return OPERATOR_CANCELLED;
560
561         CTX_DATA_BEGIN (C, Base *, base, visible_bases)
562         {
563                 if (!(base->flag & SELECT) && BKE_group_object_exists(group, base->object)) {
564                         ED_base_object_select(base, BA_SELECT);
565                 }
566         }
567         CTX_DATA_END;
568
569         WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
570
571         return OPERATOR_FINISHED;
572 }
573
574 void OBJECT_OT_grouped_select(wmOperatorType *ot)
575 {
576         /* identifiers */
577         ot->name = "Select Grouped";
578         ot->idname = "OBJECT_OT_grouped_select";
579         ot->description = "Select all objects in group";
580
581         /* api callbacks */
582         ot->exec = select_grouped_exec;
583         ot->poll = ED_operator_objectmode;
584
585         /* flags */
586         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
587 }