PROP_ENUM_NO_CONTEXT flag for rna properties, forcing enum item functions to be passe...
[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;
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                                 add_to_group(group, base->object, scene, base);
77                                 ok = 1;
78                         }
79                         CTX_DATA_END;
80                 }
81         }
82         
83         if(!ok) BKE_report(op->reports, RPT_ERROR, "Active Object contains no groups");
84         
85         DAG_scene_sort(scene);
86         WM_event_add_notifier(C, NC_GROUP|NA_EDITED, NULL);
87         
88         return OPERATOR_FINISHED;
89 }
90
91 void GROUP_OT_objects_add_active(wmOperatorType *ot)
92 {
93         /* identifiers */
94         ot->name= "Add Selected To Active Group";
95         ot->description = "Add the object to an object group that contains the active object.";
96         ot->idname= "GROUP_OT_objects_add_active";
97         
98         /* api callbacks */
99         ot->exec= objects_add_active_exec;      
100         ot->poll= ED_operator_scene_editable;
101
102         /* flags */
103         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
104 }
105
106 static int objects_remove_active_exec(bContext *C, wmOperator *op)
107 {
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= G.main->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(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_scene_editable;
147         
148         /* flags */
149         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
150 }
151
152 static int group_objects_remove_exec(bContext *C, wmOperator *op)
153 {
154         Scene *scene= CTX_data_scene(C);
155         Group *group= NULL;
156
157         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
158                 group = NULL;
159                 while((group = find_group(base->object, group)))
160                         rem_from_group(group, base->object, scene, base);
161         }
162         CTX_DATA_END;
163
164         DAG_scene_sort(scene);
165         WM_event_add_notifier(C, NC_GROUP|NA_EDITED, NULL);
166         
167         return OPERATOR_FINISHED;
168 }
169
170 void GROUP_OT_objects_remove(wmOperatorType *ot)
171 {
172         /* identifiers */
173         ot->name= "Remove From Groups";
174         ot->description = "Remove selected objects from all groups.";
175         ot->idname= "GROUP_OT_objects_remove";
176         
177         /* api callbacks */
178         ot->exec= group_objects_remove_exec;    
179         ot->poll= ED_operator_scene_editable;
180         
181         /* flags */
182         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
183 }
184
185 static int group_create_exec(bContext *C, wmOperator *op)
186 {
187         Scene *scene= CTX_data_scene(C);
188         Group *group= NULL;
189         char name[32]; /* id name */
190         
191         RNA_string_get(op->ptr, "name", name);
192         
193         group= add_group(name);
194                 
195         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
196                 add_to_group(group, base->object, scene, base);
197         }
198         CTX_DATA_END;
199
200         DAG_scene_sort(scene);
201         WM_event_add_notifier(C, NC_GROUP|NA_EDITED, NULL);
202         
203         return OPERATOR_FINISHED;
204 }
205
206 void GROUP_OT_create(wmOperatorType *ot)
207 {
208         /* identifiers */
209         ot->name= "Create New Group";
210         ot->description = "Create an object group from selected objects.";
211         ot->idname= "GROUP_OT_create";
212         
213         /* api callbacks */
214         ot->exec= group_create_exec;    
215         ot->poll= ED_operator_scene_editable;
216         
217         /* flags */
218         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
219         
220         RNA_def_string(ot->srna, "name", "Group", 32, "Name", "Name of the new group");
221 }
222
223 /****************** properties window operators *********************/
224
225 static int group_add_exec(bContext *C, wmOperator *op)
226 {
227         Main *bmain= CTX_data_main(C);
228         Scene *scene= CTX_data_scene(C);
229         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
230         Base *base;
231         Group *group;
232         int value= RNA_enum_get(op->ptr, "group");
233
234         if(!ob)
235                 return OPERATOR_CANCELLED;
236         
237         base= object_in_scene(ob, scene);
238         if(!base)
239                 return OPERATOR_CANCELLED;
240         
241         if(value == -1)
242                 group= add_group( "Group" );
243         else
244                 group= BLI_findlink(&bmain->group, value);
245
246         if(group) {
247                 add_to_group(group, ob, scene, NULL); /* base will be used if found */
248         }
249
250         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
251         
252         return OPERATOR_FINISHED;
253 }
254
255 static EnumPropertyItem group_items[]= {
256         {-1, "ADD_NEW", 0, "Add New Group", ""},
257         {0, NULL, 0, NULL, NULL}};
258
259 static EnumPropertyItem *group_itemf(bContext *C, PointerRNA *ptr, int *free)
260 {       
261         Main *bmain= CTX_data_main(C);
262         Group *group;
263         EnumPropertyItem tmp = {0, "", 0, "", ""};
264         EnumPropertyItem *item= NULL;
265         int a, totitem= 0;
266         
267         RNA_enum_items_add_value(&item, &totitem, group_items, -1);
268
269         if (bmain) {
270                 if(bmain->group.first)
271                         RNA_enum_item_add_separator(&item, &totitem);
272
273                 for(a=0, group=bmain->group.first; group; group=group->id.next, a++) {
274                         tmp.value= a;
275                         tmp.identifier= group->id.name+2;
276                         tmp.name= group->id.name+2;
277                         RNA_enum_item_add(&item, &totitem, &tmp);
278                 }
279         }
280
281         RNA_enum_item_end(&item, &totitem);
282         *free= 1;
283
284         return item;
285 }
286
287 void OBJECT_OT_group_add(wmOperatorType *ot)
288 {
289         PropertyRNA *prop;
290
291         /* identifiers */
292         ot->name= "Add to Group";
293         ot->idname= "OBJECT_OT_group_add";
294         ot->description = "Add an object to an existing group, or create new.";
295         
296         /* api callbacks */
297         ot->exec= group_add_exec;
298
299         /* flags */
300         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
301
302         /* properties */
303         prop= RNA_def_enum(ot->srna, "group", group_items, -1, "Group", "Group to add object to.");
304         RNA_def_enum_funcs(prop, group_itemf);
305 }
306
307 static int group_remove_exec(bContext *C, wmOperator *op)
308 {
309         Scene *scene= CTX_data_scene(C);
310         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
311         Group *group= CTX_data_pointer_get_type(C, "group", &RNA_Group).data;
312
313         if(!ob || !group)
314                 return OPERATOR_CANCELLED;
315
316         rem_from_group(group, ob, scene, NULL); /* base will be used if found */
317
318         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
319         
320         return OPERATOR_FINISHED;
321 }
322
323 void OBJECT_OT_group_remove(wmOperatorType *ot)
324 {
325         /* identifiers */
326         ot->name= "Remove Group";
327         ot->idname= "OBJECT_OT_group_remove";
328         
329         /* api callbacks */
330         ot->exec= group_remove_exec;
331
332         /* flags */
333         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
334 }
335