RNA:
[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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 #include "MEM_guardedalloc.h"
33
34 #include "BLI_blenlib.h"
35
36 #include "DNA_group_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_scene_types.h"
39
40 #include "BKE_context.h"
41 #include "BKE_depsgraph.h"
42 #include "BKE_global.h"
43 #include "BKE_group.h"
44 #include "BKE_main.h"
45 #include "BKE_report.h"
46 #include "BKE_scene.h"
47
48 #include "ED_screen.h"
49
50 #include "WM_api.h"
51 #include "WM_types.h"
52
53 #include "RNA_access.h"
54 #include "RNA_define.h"
55
56 #include "object_intern.h"
57
58 /********************* 3d view operators ***********************/
59
60 static int objects_add_active_exec(bContext *C, wmOperator *op)
61 {
62         Scene *scene= CTX_data_scene(C);
63         Object *ob= OBACT, *obt;
64         Group *group;
65         int ok = 0;
66         
67         if(!ob) return OPERATOR_CANCELLED;
68         
69         /* linking to same group requires its own loop so we can avoid
70            looking up the active objects groups each time */
71
72         for(group= G.main->group.first; group; group=group->id.next) {
73                 if(object_in_group(ob, group)) {
74                         /* Assign groups to selected objects */
75                         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
76                                 obt= base->object;
77                                 add_to_group(group, obt);
78                                 obt->flag |= OB_FROMGROUP;
79                                 base->flag |= OB_FROMGROUP;
80                                 base->object->recalc= OB_RECALC_OB;
81                                 ok = 1;
82                         }
83                         CTX_DATA_END;
84                 }
85         }
86         
87         if(!ok) BKE_report(op->reports, RPT_ERROR, "Active Object contains no groups");
88         
89         DAG_scene_sort(scene);
90         WM_event_add_notifier(C, NC_GROUP|NA_EDITED, NULL);
91         
92         return OPERATOR_FINISHED;
93 }
94
95 void GROUP_OT_objects_add_active(wmOperatorType *ot)
96 {
97         /* identifiers */
98         ot->name= "Add Selected To Active Group";
99         ot->description = "Add the object to an object group that contains the active object.";
100         ot->idname= "GROUP_OT_objects_add_active";
101         
102         /* api callbacks */
103         ot->exec= objects_add_active_exec;      
104         ot->poll= ED_operator_scene_editable;
105
106         /* flags */
107         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
108 }
109
110 static int objects_remove_active_exec(bContext *C, wmOperator *op)
111 {
112         Scene *scene= CTX_data_scene(C);
113         Object *ob= OBACT, *obt;
114         Group *group;
115         int ok = 0;
116         
117         if(!ob) return OPERATOR_CANCELLED;
118         
119         /* linking to same group requires its own loop so we can avoid
120            looking up the active objects groups each time */
121
122         for(group= G.main->group.first; group; group=group->id.next) {
123                 if(object_in_group(ob, group)) {
124                         /* Assign groups to selected objects */
125                         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
126                                 obt= base->object;
127                                 rem_from_group(group, obt);
128                                 obt->flag &= ~OB_FROMGROUP;
129                                 base->flag &= ~OB_FROMGROUP;
130                                 base->object->recalc= OB_RECALC_OB;
131                                 ok = 1;
132                         }
133                         CTX_DATA_END;
134                 }
135         }
136         
137         if(!ok) BKE_report(op->reports, RPT_ERROR, "Active Object contains no groups");
138         
139         DAG_scene_sort(scene);
140         WM_event_add_notifier(C, NC_GROUP|NA_EDITED, NULL);
141         
142         return OPERATOR_FINISHED;
143 }
144
145 void GROUP_OT_objects_remove_active(wmOperatorType *ot)
146 {
147         /* identifiers */
148         ot->name= "Remove Selected From Active Group";
149         ot->description = "Remove the object from an object group that contains the active object.";
150         ot->idname= "GROUP_OT_objects_remove_active";
151         
152         /* api callbacks */
153         ot->exec= objects_remove_active_exec;   
154         ot->poll= ED_operator_scene_editable;
155         
156         /* flags */
157         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
158 }
159
160 static int group_objects_remove_exec(bContext *C, wmOperator *op)
161 {
162         Scene *scene= CTX_data_scene(C);
163         Group *group= NULL;
164
165         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
166                 group = NULL;
167                 while((group = find_group(base->object, group)))
168                         rem_from_group(group, base->object);
169
170                 base->object->flag &= ~OB_FROMGROUP;
171                 base->flag &= ~OB_FROMGROUP;
172                 base->object->recalc= OB_RECALC_OB;
173         }
174         CTX_DATA_END;
175
176         DAG_scene_sort(scene);
177         WM_event_add_notifier(C, NC_GROUP|NA_EDITED, NULL);
178         
179         return OPERATOR_FINISHED;
180 }
181
182 void GROUP_OT_objects_remove(wmOperatorType *ot)
183 {
184         /* identifiers */
185         ot->name= "Remove From Groups";
186         ot->description = "Remove selected objects from all groups.";
187         ot->idname= "GROUP_OT_objects_remove";
188         
189         /* api callbacks */
190         ot->exec= group_objects_remove_exec;    
191         ot->poll= ED_operator_scene_editable;
192         
193         /* flags */
194         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
195 }
196
197 static int group_create_exec(bContext *C, wmOperator *op)
198 {
199         Scene *scene= CTX_data_scene(C);
200         Group *group= NULL;
201         char gid[32]; //group id
202         
203         RNA_string_get(op->ptr, "GID", gid);
204         
205         group= add_group(gid);
206                 
207         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
208                 add_to_group(group, base->object);
209                 base->object->flag |= OB_FROMGROUP;
210                 base->flag |= OB_FROMGROUP;
211                 base->object->recalc= OB_RECALC_OB;
212         }
213         CTX_DATA_END;
214
215         DAG_scene_sort(scene);
216         WM_event_add_notifier(C, NC_GROUP|NA_EDITED, NULL);
217         
218         return OPERATOR_FINISHED;
219 }
220
221 void GROUP_OT_group_create(wmOperatorType *ot)
222 {
223         /* identifiers */
224         ot->name= "Create New Group";
225         ot->description = "Create an object group.";
226         ot->idname= "GROUP_OT_group_create";
227         
228         /* api callbacks */
229         ot->exec= group_create_exec;    
230         ot->poll= ED_operator_scene_editable;
231         
232         /* flags */
233         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
234         
235         RNA_def_string(ot->srna, "GID", "Group", 32, "Name", "Name of the new group");
236 }
237
238 /****************** properties window operators *********************/
239
240 static int group_add_exec(bContext *C, wmOperator *op)
241 {
242         Main *bmain= CTX_data_main(C);
243         Scene *scene= CTX_data_scene(C);
244         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
245         Base *base;
246         Group *group;
247         int value= RNA_enum_get(op->ptr, "group");
248
249         if(!ob)
250                 return OPERATOR_CANCELLED;
251         
252         base= object_in_scene(ob, scene);
253         if(!base)
254                 return OPERATOR_CANCELLED;
255         
256         if(value == -1)
257                 group= add_group( "Group" );
258         else
259                 group= BLI_findlink(&bmain->group, value);
260
261         if(group) {
262                 add_to_group(group, ob);
263                 ob->flag |= OB_FROMGROUP;
264                 base->flag |= OB_FROMGROUP;
265         }
266
267         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
268         
269         return OPERATOR_FINISHED;
270 }
271
272 static EnumPropertyItem group_items[]= {
273         {-1, "ADD_NEW", 0, "Add New Group", ""},
274         {0, NULL, 0, NULL, NULL}};
275
276 static EnumPropertyItem *group_itemf(bContext *C, PointerRNA *ptr, int *free)
277 {       
278         Main *bmain= CTX_data_main(C);
279         Group *group;
280         EnumPropertyItem tmp = {0, "", 0, "", ""};
281         EnumPropertyItem *item= NULL;
282         int a, totitem= 0;
283         
284         RNA_enum_items_add_value(&item, &totitem, group_items, -1);
285
286         if(bmain->group.first)
287                 RNA_enum_item_add_separator(&item, &totitem);
288
289         for(a=0, group=bmain->group.first; group; group=group->id.next, a++) {
290                 tmp.value= a;
291                 tmp.identifier= group->id.name+2;
292                 tmp.name= group->id.name+2;
293                 RNA_enum_item_add(&item, &totitem, &tmp);
294         }
295
296         RNA_enum_item_end(&item, &totitem);
297         *free= 1;
298
299         return item;
300 }
301
302 void OBJECT_OT_group_add(wmOperatorType *ot)
303 {
304         PropertyRNA *prop;
305
306         /* identifiers */
307         ot->name= "Add Group";
308         ot->idname= "OBJECT_OT_group_add";
309         
310         /* api callbacks */
311         ot->exec= group_add_exec;
312
313         /* flags */
314         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
315
316         /* properties */
317         prop= RNA_def_enum(ot->srna, "group", group_items, -1, "Group", "Group to add object to.");
318         RNA_def_enum_funcs(prop, group_itemf);
319 }
320
321 static int group_remove_exec(bContext *C, wmOperator *op)
322 {
323         Scene *scene= CTX_data_scene(C);
324         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
325         Group *group= CTX_data_pointer_get_type(C, "group", &RNA_Group).data;
326         Base *base;
327
328         if(!ob || !group)
329                 return OPERATOR_CANCELLED;
330
331         base= object_in_scene(ob, scene);
332         if(!base)
333                 return OPERATOR_CANCELLED;
334
335         rem_from_group(group, ob);
336
337         if(find_group(ob, NULL) == NULL) {
338                 ob->flag &= ~OB_FROMGROUP;
339                 base->flag &= ~OB_FROMGROUP;
340         }
341
342         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
343         
344         return OPERATOR_FINISHED;
345 }
346
347 void OBJECT_OT_group_remove(wmOperatorType *ot)
348 {
349         /* identifiers */
350         ot->name= "Remove Group";
351         ot->idname= "OBJECT_OT_group_remove";
352         
353         /* api callbacks */
354         ot->exec= group_remove_exec;
355
356         /* flags */
357         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
358 }
359