Bugfix #20382
[blender.git] / source / blender / editors / object / object_group.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) Blender Foundation
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <string.h>
31
32
33 #include "BLI_blenlib.h"
34
35 #include "DNA_group_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_scene_types.h"
38
39 #include "BKE_context.h"
40 #include "BKE_depsgraph.h"
41 #include "BKE_group.h"
42 #include "BKE_main.h"
43 #include "BKE_report.h"
44
45 #include "ED_screen.h"
46
47 #include "WM_api.h"
48 #include "WM_types.h"
49
50 #include "RNA_access.h"
51 #include "RNA_define.h"
52 #include "RNA_enum_types.h"
53
54 #include "object_intern.h"
55
56 /********************* 3d view operators ***********************/
57
58 static int objects_add_active_exec(bContext *C, wmOperator *op)
59 {
60         Main *bmain= CTX_data_main(C);
61         Scene *scene= CTX_data_scene(C);
62         Object *ob= OBACT;
63         Group *group;
64         int ok = 0;
65         
66         if(!ob) return OPERATOR_CANCELLED;
67         
68         /* linking to same group requires its own loop so we can avoid
69            looking up the active objects groups each time */
70
71         for(group= bmain->group.first; group; group=group->id.next) {
72                 if(object_in_group(ob, group)) {
73                         /* Assign groups to selected objects */
74                         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
75                                 add_to_group(group, base->object, scene, base);
76                                 ok = 1;
77                         }
78                         CTX_DATA_END;
79                 }
80         }
81         
82         if(!ok) BKE_report(op->reports, RPT_ERROR, "Active Object contains no groups");
83         
84         DAG_scene_sort(bmain, scene);
85         WM_event_add_notifier(C, NC_GROUP|NA_EDITED, NULL);
86         
87         return OPERATOR_FINISHED;
88 }
89
90 void GROUP_OT_objects_add_active(wmOperatorType *ot)
91 {
92         /* identifiers */
93         ot->name= "Add Selected To Active Group";
94         ot->description = "Add the object to an object group that contains the active object";
95         ot->idname= "GROUP_OT_objects_add_active";
96         
97         /* api callbacks */
98         ot->exec= objects_add_active_exec;      
99         ot->poll= ED_operator_objectmode;
100
101         /* flags */
102         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
103 }
104
105 static int objects_remove_active_exec(bContext *C, wmOperator *op)
106 {
107         Main *bmain= CTX_data_main(C);
108         Scene *scene= CTX_data_scene(C);
109         Object *ob= OBACT;
110         Group *group;
111         int ok = 0;
112         
113         if(!ob) return OPERATOR_CANCELLED;
114         
115         /* linking to same group requires its own loop so we can avoid
116            looking up the active objects groups each time */
117
118         for(group= bmain->group.first; group; group=group->id.next) {
119                 if(object_in_group(ob, group)) {
120                         /* Assign groups to selected objects */
121                         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
122                                 rem_from_group(group, base->object, scene, base);
123                                 ok = 1;
124                         }
125                         CTX_DATA_END;
126                 }
127         }
128         
129         if(!ok) BKE_report(op->reports, RPT_ERROR, "Active Object contains no groups");
130         
131         DAG_scene_sort(bmain, scene);
132         WM_event_add_notifier(C, NC_GROUP|NA_EDITED, NULL);
133         
134         return OPERATOR_FINISHED;
135 }
136
137 void GROUP_OT_objects_remove_active(wmOperatorType *ot)
138 {
139         /* identifiers */
140         ot->name= "Remove Selected From Active Group";
141         ot->description = "Remove the object from an object group that contains the active object";
142         ot->idname= "GROUP_OT_objects_remove_active";
143         
144         /* api callbacks */
145         ot->exec= objects_remove_active_exec;   
146         ot->poll= ED_operator_objectmode;
147         
148         /* flags */
149         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
150 }
151
152 static int group_objects_remove_exec(bContext *C, wmOperator *UNUSED(op))
153 {
154         Main *bmain= CTX_data_main(C);
155         Scene *scene= CTX_data_scene(C);
156         Group *group= NULL;
157
158         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
159                 group = NULL;
160                 while((group = find_group(base->object, group)))
161                         rem_from_group(group, base->object, scene, base);
162         }
163         CTX_DATA_END;
164
165         DAG_scene_sort(bmain, scene);
166         WM_event_add_notifier(C, NC_GROUP|NA_EDITED, NULL);
167         
168         return OPERATOR_FINISHED;
169 }
170
171 void GROUP_OT_objects_remove(wmOperatorType *ot)
172 {
173         /* identifiers */
174         ot->name= "Remove From Groups";
175         ot->description = "Remove selected objects from all groups";
176         ot->idname= "GROUP_OT_objects_remove";
177         
178         /* api callbacks */
179         ot->exec= group_objects_remove_exec;    
180         ot->poll= ED_operator_objectmode;
181         
182         /* flags */
183         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
184 }
185
186 static int group_create_exec(bContext *C, wmOperator *op)
187 {
188         Main *bmain= CTX_data_main(C);
189         Scene *scene= CTX_data_scene(C);
190         Group *group= NULL;
191         char name[32]; /* id name */
192         
193         RNA_string_get(op->ptr, "name", name);
194         
195         group= add_group(name);
196                 
197         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
198                 add_to_group(group, base->object, scene, base);
199         }
200         CTX_DATA_END;
201
202         DAG_scene_sort(bmain, scene);
203         WM_event_add_notifier(C, NC_GROUP|NA_EDITED, NULL);
204         
205         return OPERATOR_FINISHED;
206 }
207
208 void GROUP_OT_create(wmOperatorType *ot)
209 {
210         /* identifiers */
211         ot->name= "Create New Group";
212         ot->description = "Create an object group from selected objects";
213         ot->idname= "GROUP_OT_create";
214         
215         /* api callbacks */
216         ot->exec= group_create_exec;    
217         ot->poll= ED_operator_objectmode;
218         
219         /* flags */
220         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
221         
222         RNA_def_string(ot->srna, "name", "Group", 32, "Name", "Name of the new group");
223 }
224
225 /****************** properties window operators *********************/
226
227 static int group_add_exec(bContext *C, wmOperator *UNUSED(op))
228 {
229         Scene *scene= CTX_data_scene(C);
230         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
231         Group *group;
232
233         if(ob == NULL)
234                 return OPERATOR_CANCELLED;
235
236     group= add_group("Group");
237     add_to_group(group, ob, scene, NULL);
238
239         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
240
241         return OPERATOR_FINISHED;
242 }
243
244 void OBJECT_OT_group_add(wmOperatorType *ot)
245 {
246         /* identifiers */
247         ot->name= "Add to Group";
248         ot->idname= "OBJECT_OT_group_add";
249         ot->description = "Add an object to a new group";
250         
251         /* api callbacks */
252         ot->exec= group_add_exec;
253
254         /* flags */
255         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
256 }
257
258 static int group_link_exec(bContext *C, wmOperator *op)
259 {
260         Scene *scene= CTX_data_scene(C);
261         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
262     Group *group= BLI_findlink(&CTX_data_main(C)->group, RNA_enum_get(op->ptr, "group"));
263
264         if(ELEM(NULL, ob, group))
265                 return OPERATOR_CANCELLED;
266
267     add_to_group(group, ob, scene, NULL);
268
269         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
270
271         return OPERATOR_FINISHED;
272 }
273
274 void OBJECT_OT_group_link(wmOperatorType *ot)
275 {
276         PropertyRNA *prop;
277
278         /* identifiers */
279         ot->name= "Link to Group";
280         ot->idname= "OBJECT_OT_group_link";
281         ot->description = "Add an object to an existing group";
282         
283         /* api callbacks */
284         ot->exec= group_link_exec;
285         ot->invoke= WM_enum_search_invoke;
286
287         /* flags */
288         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
289
290         /* properties */
291         prop= RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "");
292         RNA_def_enum_funcs(prop, RNA_group_local_itemf);
293         ot->prop= prop;
294 }
295
296 static int group_remove_exec(bContext *C, wmOperator *UNUSED(op))
297 {
298         Scene *scene= CTX_data_scene(C);
299         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
300         Group *group= CTX_data_pointer_get_type(C, "group", &RNA_Group).data;
301
302         if(!ob || !group)
303                 return OPERATOR_CANCELLED;
304
305         rem_from_group(group, ob, scene, NULL); /* base will be used if found */
306
307         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
308         
309         return OPERATOR_FINISHED;
310 }
311
312 void OBJECT_OT_group_remove(wmOperatorType *ot)
313 {
314         /* identifiers */
315         ot->name= "Remove Group";
316         ot->idname= "OBJECT_OT_group_remove";
317         
318         /* api callbacks */
319         ot->exec= group_remove_exec;
320
321         /* flags */
322         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
323 }
324