Big i18n commit: add "reports" from bmesh/readfile/tracking/dynapaint (and a few...
[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_main.h"
46 #include "BKE_report.h"
47 #include "BKE_object.h"
48
49 #include "ED_screen.h"
50 #include "ED_object.h"
51
52 #include "WM_api.h"
53 #include "WM_types.h"
54
55 #include "RNA_access.h"
56 #include "RNA_define.h"
57 #include "RNA_enum_types.h"
58
59 #include "object_intern.h"
60
61 /********************* 3d view operators ***********************/
62
63 /* can be called with C == NULL */
64 static EnumPropertyItem *group_object_active_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
65 {
66         Object *ob;
67         EnumPropertyItem *item = NULL, item_tmp = {0};
68         int totitem = 0;
69
70         if (C == NULL) {
71                 return DummyRNA_NULL_items;
72         }
73
74         ob = ED_object_context(C);
75
76         /* check that the action exists */
77         if (ob) {
78                 Group *group = NULL;
79                 int i = 0;
80
81                 while ((group = find_group(ob, group))) {
82                         item_tmp.identifier = item_tmp.name = group->id.name + 2;
83                         /* item_tmp.icon = ICON_ARMATURE_DATA; */
84                         item_tmp.value = i;
85                         RNA_enum_item_add(&item, &totitem, &item_tmp);
86                         i++;
87                 }
88         }
89
90         RNA_enum_item_end(&item, &totitem);
91         *free = 1;
92
93         return item;
94 }
95
96 /* get the group back from the enum index, quite awkward and UI specific */
97 static Group *group_object_active_find_index(Object *ob, const int group_object_index)
98 {
99         Group *group = NULL;
100         int i = 0;
101         while ((group = find_group(ob, group))) {
102                 if (i == group_object_index) {
103                         break;
104                 }
105                 i++;
106         }
107
108         return group;
109 }
110
111 static int objects_add_active_exec(bContext *C, wmOperator *op)
112 {
113         Object *ob = ED_object_context(C);
114         Main *bmain = CTX_data_main(C);
115         Scene *scene = CTX_data_scene(C);
116         int group_object_index = RNA_enum_get(op->ptr, "group");
117         int is_cycle = FALSE;
118
119         if (ob) {
120                 Group *group = group_object_active_find_index(ob, group_object_index);
121
122                 /* now add all selected objects from the group */
123                 if (group) {
124
125                         CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
126                         {
127                                 if (base->object->dup_group != group) {
128                                         add_to_group(group, base->object, scene, base);
129                                 }
130                                 else {
131                                         is_cycle = TRUE;
132                                 }
133                         }
134                         CTX_DATA_END;
135
136                         if (is_cycle) {
137                                 BKE_report(op->reports, RPT_WARNING, "Skipped some groups because of cycle detected");
138                         }
139
140                         DAG_scene_sort(bmain, scene);
141                         WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
142
143                         return OPERATOR_FINISHED;
144                 }
145         }
146
147         return OPERATOR_CANCELLED;
148 }
149
150 void GROUP_OT_objects_add_active(wmOperatorType *ot)
151 {
152         PropertyRNA *prop;
153
154         /* identifiers */
155         ot->name = "Add Selected To Active Group";
156         ot->description = "Add the object to an object group that contains the active object";
157         ot->idname = "GROUP_OT_objects_add_active";
158         
159         /* api callbacks */
160         ot->exec = objects_add_active_exec;
161         ot->invoke = WM_menu_invoke;
162         ot->poll = ED_operator_objectmode;
163
164         /* flags */
165         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
166
167         /* properties */
168         prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "The group to add other selected objects to");
169         RNA_def_enum_funcs(prop, group_object_active_itemf);
170         ot->prop = prop;
171 }
172
173 static int objects_remove_active_exec(bContext *C, wmOperator *op)
174 {
175         Main *bmain = CTX_data_main(C);
176         Scene *scene = CTX_data_scene(C);
177         Object *ob = OBACT;
178         Group *group;
179         int ok = 0;
180         
181         if (!ob) return OPERATOR_CANCELLED;
182         
183         /* linking to same group requires its own loop so we can avoid
184          * looking up the active objects groups each time */
185
186         for (group = bmain->group.first; group; group = group->id.next) {
187                 if (object_in_group(ob, group)) {
188                         /* Assign groups to selected objects */
189                         CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
190                         {
191                                 rem_from_group(group, base->object, scene, base);
192                                 ok = 1;
193                         }
194                         CTX_DATA_END;
195                 }
196         }
197         
198         if (!ok) BKE_report(op->reports, RPT_ERROR, "Active object contains no groups");
199         
200         DAG_scene_sort(bmain, scene);
201         WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
202         
203         return OPERATOR_FINISHED;
204 }
205
206 void GROUP_OT_objects_remove_active(wmOperatorType *ot)
207 {
208         /* identifiers */
209         ot->name = "Remove Selected From Active Group";
210         ot->description = "Remove the object from an object group that contains the active object";
211         ot->idname = "GROUP_OT_objects_remove_active";
212         
213         /* api callbacks */
214         ot->exec = objects_remove_active_exec;
215         ot->poll = ED_operator_objectmode;
216         
217         /* flags */
218         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
219 }
220
221 static int group_objects_remove_all_exec(bContext *C, wmOperator *UNUSED(op))
222 {
223         Main *bmain = CTX_data_main(C);
224         Scene *scene = CTX_data_scene(C);
225
226         CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
227         {
228                 BKE_object_groups_clear(scene, base, base->object);
229         }
230         CTX_DATA_END;
231
232         DAG_scene_sort(bmain, scene);
233         WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
234         
235         return OPERATOR_FINISHED;
236 }
237
238 void GROUP_OT_objects_remove_all(wmOperatorType *ot)
239 {
240         /* identifiers */
241         ot->name = "Remove From All Groups";
242         ot->description = "Remove selected objects from all groups or a selected group";
243         ot->idname = "GROUP_OT_objects_remove_all";
244         
245         /* api callbacks */
246         ot->exec = group_objects_remove_all_exec;
247         ot->poll = ED_operator_objectmode;
248         
249         /* flags */
250         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
251 }
252
253 static int group_objects_remove_exec(bContext *C, wmOperator *op)
254 {
255         Object *ob = ED_object_context(C);
256         Main *bmain = CTX_data_main(C);
257         Scene *scene = CTX_data_scene(C);
258         int group_object_index = RNA_enum_get(op->ptr, "group");
259
260         if (ob) {
261                 Group *group = group_object_active_find_index(ob, group_object_index);
262
263                 /* now remove all selected objects from the group */
264                 if (group) {
265
266                         CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
267                         {
268                                 rem_from_group(group, base->object, scene, base);
269                         }
270                         CTX_DATA_END;
271
272                         DAG_scene_sort(bmain, scene);
273                         WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
274
275                         return OPERATOR_FINISHED;
276                 }
277         }
278
279         return OPERATOR_CANCELLED;
280 }
281
282 void GROUP_OT_objects_remove(wmOperatorType *ot)
283 {
284         PropertyRNA *prop;
285
286         /* identifiers */
287         ot->name = "Remove From Group";
288         ot->description = "Remove selected objects from all groups or a selected group";
289         ot->idname = "GROUP_OT_objects_remove";
290
291         /* api callbacks */
292         ot->exec = group_objects_remove_exec;
293         ot->invoke = WM_menu_invoke;
294         ot->poll = ED_operator_objectmode;
295
296         /* flags */
297         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
298
299         /* properties */
300         prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "The group to remove this object from");
301         RNA_def_enum_funcs(prop, group_object_active_itemf);
302         ot->prop = prop;
303 }
304
305 static int group_create_exec(bContext *C, wmOperator *op)
306 {
307         Main *bmain = CTX_data_main(C);
308         Scene *scene = CTX_data_scene(C);
309         Group *group = NULL;
310         char name[MAX_ID_NAME - 2]; /* id name */
311         
312         RNA_string_get(op->ptr, "name", name);
313         
314         group = add_group(name);
315                 
316         CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
317         {
318                 add_to_group(group, base->object, scene, base);
319         }
320         CTX_DATA_END;
321
322         DAG_scene_sort(bmain, scene);
323         WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
324         
325         return OPERATOR_FINISHED;
326 }
327
328 void GROUP_OT_create(wmOperatorType *ot)
329 {
330         /* identifiers */
331         ot->name = "Create New Group";
332         ot->description = "Create an object group from selected objects";
333         ot->idname = "GROUP_OT_create";
334         
335         /* api callbacks */
336         ot->exec = group_create_exec;
337         ot->poll = ED_operator_objectmode;
338         
339         /* flags */
340         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
341         
342         RNA_def_string(ot->srna, "name", "Group", MAX_ID_NAME - 2, "Name", "Name of the new group");
343 }
344
345 /****************** properties window operators *********************/
346
347 static int group_add_exec(bContext *C, wmOperator *UNUSED(op))
348 {
349         Scene *scene = CTX_data_scene(C);
350         Object *ob = ED_object_context(C);
351         Group *group;
352
353         if (ob == NULL)
354                 return OPERATOR_CANCELLED;
355
356         group = add_group("Group");
357         add_to_group(group, ob, scene, NULL);
358
359         WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
360
361         return OPERATOR_FINISHED;
362 }
363
364 void OBJECT_OT_group_add(wmOperatorType *ot)
365 {
366         /* identifiers */
367         ot->name = "Add to Group";
368         ot->idname = "OBJECT_OT_group_add";
369         ot->description = "Add an object to a new group";
370         
371         /* api callbacks */
372         ot->exec = group_add_exec;
373         ot->poll = ED_operator_objectmode;
374
375         /* flags */
376         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
377 }
378
379 static int group_link_exec(bContext *C, wmOperator *op)
380 {
381         Scene *scene = CTX_data_scene(C);
382         Object *ob = ED_object_context(C);
383         Group *group = BLI_findlink(&CTX_data_main(C)->group, RNA_enum_get(op->ptr, "group"));
384
385         if (ELEM(NULL, ob, group))
386                 return OPERATOR_CANCELLED;
387
388         add_to_group(group, ob, scene, NULL);
389
390         WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
391
392         return OPERATOR_FINISHED;
393 }
394
395 void OBJECT_OT_group_link(wmOperatorType *ot)
396 {
397         PropertyRNA *prop;
398
399         /* identifiers */
400         ot->name = "Link to Group";
401         ot->idname = "OBJECT_OT_group_link";
402         ot->description = "Add an object to an existing group";
403         
404         /* api callbacks */
405         ot->exec = group_link_exec;
406         ot->invoke = WM_enum_search_invoke;
407         ot->poll = ED_operator_objectmode;
408
409         /* flags */
410         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
411
412         /* properties */
413         prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "");
414         RNA_def_enum_funcs(prop, RNA_group_local_itemf);
415         ot->prop = prop;
416 }
417
418 static int group_remove_exec(bContext *C, wmOperator *UNUSED(op))
419 {
420         Scene *scene = CTX_data_scene(C);
421         Object *ob = ED_object_context(C);
422         Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data;
423
424         if (!ob || !group)
425                 return OPERATOR_CANCELLED;
426
427         rem_from_group(group, ob, scene, NULL); /* base will be used if found */
428
429         WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
430         
431         return OPERATOR_FINISHED;
432 }
433
434 void OBJECT_OT_group_remove(wmOperatorType *ot)
435 {
436         /* identifiers */
437         ot->name = "Remove Group";
438         ot->idname = "OBJECT_OT_group_remove";
439         ot->description = "Remove the active object from this group";
440         
441         /* api callbacks */
442         ot->exec = group_remove_exec;
443         ot->poll = ED_operator_objectmode;
444
445         /* flags */
446         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
447 }
448