2.5
[blender.git] / source / blender / editors / object / editgroup.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 #include "BLI_arithb.h"
36
37 #include "DNA_group_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_scene_types.h"
40 #include "DNA_view3d_types.h"
41
42 #include "BKE_depsgraph.h"
43 #include "BKE_group.h"
44 #include "BKE_global.h"
45 #include "BKE_context.h"
46 #include "BKE_main.h"
47
48 #include "ED_view3d.h"
49 #include "ED_space_api.h"
50 #include "ED_screen.h"
51 #include "ED_types.h"
52 #include "ED_util.h"
53
54 #include "UI_interface.h"
55 #include "UI_resources.h"
56
57 #include "WM_api.h"
58 #include "WM_types.h"
59
60 #include "RNA_access.h"
61 #include "RNA_define.h"
62
63 #include "object_intern.h"
64
65 /* XXX */
66 static void BIF_undo_push() {}
67 static void error() {}
68 static int pupmenu() {return 0;}
69 static int pupmenu_col() {return 0;}
70
71 void add_selected_to_act_ob_groups(Scene *scene, View3D *v3d)
72 {
73         Object *ob= OBACT, *obt;
74         Base *base;
75         Group *group;
76         
77         if (!ob) return;
78         
79         /* linking to same group requires its own loop so we can avoid
80            looking up the active objects groups each time */
81
82         group= G.main->group.first;
83         while(group) {
84                 if(object_in_group(ob, group)) {
85                         /* Assign groups to selected objects */
86                         base= FIRSTBASE;
87                         while(base) {
88                                 if(TESTBASE(v3d, base)) {
89                                         obt= base->object;
90                                         add_to_group(group, obt);
91                                         obt->flag |= OB_FROMGROUP;
92                                         base->flag |= OB_FROMGROUP;
93                                 }
94                                 base= base->next;
95                         }
96                 }
97                 group= group->id.next;
98         }
99         DAG_scene_sort(scene);
100         BIF_undo_push("Add to Active Objects Group");
101 }
102
103 static int group_remove_exec(bContext *C, wmOperator *op)
104 {
105         Group *group= NULL;
106         Group *group_array[24] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
107         int gid,i=0; //group id
108
109         gid = RNA_int_get(op->ptr, "GID");
110         
111         /*remove from all groups*/
112         if (gid == 26) {
113                 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
114                         group = NULL;
115                         while( (group = find_group(base->object, group)) ) {
116                                 rem_from_group(group, base->object);
117                         }
118                         base->object->flag &= ~OB_FROMGROUP;
119                         base->flag &= ~OB_FROMGROUP;
120                 }
121                 CTX_DATA_END;
122         }
123         else {          
124                 /* build array of the groups that are in menu*/
125                 for(group= G.main->group.first; group && i<24; group= group->id.next) {
126                         if(group->id.lib==NULL) {
127                                 GroupObject *go;
128                                 for(go= group->gobject.first; go; go= go->next) {
129                                         if(go->ob->id.flag & LIB_DOIT) {
130                                                 group_array[i] = group;
131                                                 i++;
132                                                 break; /* Only want to know if this group should go in the list*/
133                                         }
134                                 }
135                         }
136                 }
137         
138                 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
139                         /* if we are removed and are not in any group, set our flag */
140                         if(rem_from_group(group, base->object) && find_group(base->object, NULL)==NULL) {
141                                 base->object->flag &= ~OB_FROMGROUP;
142                                 base->flag &= ~OB_FROMGROUP;
143                         }
144                 }
145                 CTX_DATA_END;
146         }
147
148         DAG_scene_sort(CTX_data_scene(C));
149         ED_undo_push(C,"Remove From Group");
150
151         WM_event_add_notifier(C, NC_SCENE, CTX_data_scene(C));
152         
153         return OPERATOR_FINISHED;
154
155 }
156 static int group_remove_invoke(bContext *C, wmOperator *op, wmEvent *event)
157 {
158         Group *group= NULL;
159         char *menutext= MEM_callocN(30+(22*22), "group rem menu"), *menupt;
160         int i = 0;
161         
162         /* UnSet Tags for Objects and Groups */
163         for(group= G.main->group.first; group; group= group->id.next) {
164                 if(group->id.lib==NULL) {
165                         group->id.flag &= ~LIB_DOIT;
166                 }
167         }
168         CTX_DATA_BEGIN(C, Object*, ob, visible_objects) {
169                 ob->id.flag &= ~LIB_DOIT;
170         }
171         CTX_DATA_END;
172         
173         /* Not tag selected objects */
174         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
175                         base->object->id.flag |= LIB_DOIT;
176         }
177         CTX_DATA_END;
178         
179         menupt = menutext;
180         
181         menupt += sprintf(menupt, "Remove From %%t|");
182         
183         /* Build a list of groups that contain selected objects */
184         for(group= G.main->group.first; group && i<24; group= group->id.next) {
185                 if(group->id.lib==NULL) {
186                         GroupObject *go;
187                         for(go= group->gobject.first; go; go= go->next) {
188                                 if(go->ob->id.flag & LIB_DOIT) {
189                                         menupt += sprintf(menupt, "|%s", group->id.name+2);
190                                         i++;
191                                         break; /* Only want to know if this group should go in the list*/
192                                 }
193                         }
194                 }
195         }
196         menupt += sprintf(menupt, "|%s %%x%d", "ALL", 26);
197         /* do we have any groups? */
198         if (i = 0) error("Object selection contains no groups");
199         else    uiPupmenuOperator(C, 0, op, "GID", menutext);
200                 
201         MEM_freeN(menutext);
202         return OPERATOR_RUNNING_MODAL;
203 }
204 void GROUP_OT_group_remove(wmOperatorType *ot)
205 {
206         
207         /* identifiers */
208         ot->name= "remove Selected from group";
209         ot->idname= "GROUP_OT_group_remove";
210         
211         /* api callbacks */
212         ot->invoke = group_remove_invoke;
213         ot->exec= group_remove_exec;    
214         ot->poll= ED_operator_scene_editable;
215         
216         RNA_def_int(ot->srna, "GID", 0, INT_MIN, INT_MAX, "Group", "", INT_MIN, INT_MAX);
217 }
218 static int group_create_exec(bContext *C, wmOperator *op)
219 {
220         Group *group= NULL;
221         int gid; //group id
222         
223         gid = RNA_int_get(op->ptr, "GID");
224         
225         if(gid>0) group= BLI_findlink(&G.main->group, gid-1);
226         else if (gid == 0 ) group= add_group( "Group" );
227         else return OPERATOR_CANCELLED;
228         
229         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
230                 add_to_group(group, base->object);
231                 base->object->flag |= OB_FROMGROUP;
232                 base->flag |= OB_FROMGROUP;
233                 base->object->recalc= OB_RECALC_OB;
234         }
235         CTX_DATA_END;
236
237         DAG_scene_sort(CTX_data_scene(C));
238         ED_undo_push(C,"Add to Group");
239
240         WM_event_add_notifier(C, NC_SCENE, CTX_data_scene(C));
241         
242         return OPERATOR_FINISHED;
243
244 }
245 static int group_create_invoke(bContext *C, wmOperator *op, wmEvent *event)
246 {
247         Group *group= NULL;
248         int tot= BLI_countlist(&G.main->group);
249         char *strp= MEM_callocN(tot*32 + 32, "group menu"), *strp1;
250
251         /* are there existing groups? */
252         for(group= G.main->group.first; group; group= group->id.next)
253                 if(group->id.lib==NULL)
254                         break;
255         strp1= strp;
256         strp1 += sprintf(strp1, "Add To %%t|");
257         
258         strp1 += sprintf(strp1, "%s %%x%d|", "ADD NEW", 0);
259         
260         for(tot=1, group= G.main->group.first; group; group= group->id.next, tot++) {
261                 if(group->id.lib==NULL) {
262                         strp1 += sprintf(strp1, "%s %%x%d|", group->id.name+2, tot);
263                 }
264         }
265         uiPupmenuOperator(C, 0, op, "GID", strp);
266         MEM_freeN(strp);
267
268         return OPERATOR_RUNNING_MODAL;
269 }
270 void GROUP_OT_group_create(wmOperatorType *ot)
271 {
272         
273         /* identifiers */
274         ot->name= "Add Selected to group";
275         ot->idname= "GROUP_OT_group_create";
276         
277         /* api callbacks */
278         ot->invoke = group_create_invoke;
279         ot->exec= group_create_exec;    
280         ot->poll= ED_operator_scene_editable;
281         
282         RNA_def_int(ot->srna, "GID", 0, INT_MIN, INT_MAX, "Group", "", INT_MIN, INT_MAX);
283 }
284