OUTLINER_OT_scene_drop -- "Drag object to scene in Outliner" operator
[blender.git] / source / blender / editors / space_outliner / space_outliner.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) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  * 
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_outliner/space_outliner.c
28  *  \ingroup spoutliner
29  */
30
31
32 #include <string.h>
33 #include <stdio.h>
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_blenlib.h"
38 #include "BLI_math.h"
39 #include "BLI_rand.h"
40 #include "BLI_utildefines.h"
41
42 #include "BKE_context.h"
43 #include "BKE_screen.h"
44
45 #include "ED_space_api.h"
46 #include "ED_screen.h"
47
48 #include "WM_api.h"
49 #include "WM_types.h"
50
51 #include "BIF_gl.h"
52
53 #include "RNA_access.h"
54
55 #include "UI_resources.h"
56 #include "UI_view2d.h"
57
58
59 #include "outliner_intern.h"
60
61 static void outliner_main_area_init(wmWindowManager *wm, ARegion *ar)
62 {
63         ListBase *lb;
64         wmKeyMap *keymap;
65         
66         UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy);
67         
68         /* own keymap */
69         keymap = WM_keymap_find(wm->defaultconf, "Outliner", SPACE_OUTLINER, 0);
70         /* don't pass on view2d mask, it's always set with scrollbar space, hide fails */
71         WM_event_add_keymap_handler_bb(&ar->handlers, keymap, NULL, &ar->winrct);
72
73         /* Add dropboxes */
74         lb = WM_dropboxmap_find("Outliner", SPACE_OUTLINER, RGN_TYPE_WINDOW);
75         WM_event_add_dropbox_handler(&ar->handlers, lb);
76 }
77
78 static int outliner_parent_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
79 {
80         ARegion *ar = CTX_wm_region(C);
81         SpaceOops *soops = CTX_wm_space_outliner(C);
82         TreeElement *te = NULL;
83         float fmval[2];
84         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
85
86         if (drag->type == WM_DRAG_ID) {
87                 ID *id = (ID *)drag->poin;
88                 if (GS(id->name) == ID_OB) {
89                         /* Ensure item under cursor is valid drop target */
90                         /* Find object hovered over */
91                         for (te = soops->tree.first; te; te = te->next) {
92                                 TreeElement *te_valid;
93                                 te_valid = outliner_dropzone_parent(C, event, te, fmval);
94                                 if (te_valid) return 1;
95                         }
96                 }
97         }
98         return 0;
99 }
100
101 static void outliner_parent_drop_copy(wmDrag *drag, wmDropBox *drop)
102 {
103         ID *id = (ID *)drag->poin;
104
105         RNA_string_set(drop->ptr, "child", id->name + 2);
106 }
107
108 static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, wmEvent *event)
109 {
110         ARegion *ar = CTX_wm_region(C);
111         SpaceOops *soops = CTX_wm_space_outliner(C);
112         TreeElement *te = NULL;
113         float fmval[2];
114
115         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
116
117         if (drag->type == WM_DRAG_ID) {
118                 ID *id = (ID *)drag->poin;
119                 if (GS(id->name) == ID_OB) {
120                         //TODO: Check if no parent?
121                         /* Ensure location under cursor is valid dropzone */
122                         for (te = soops->tree.first; te; te = te->next) {
123                                 if (outliner_dropzone_parent_clear(C, event, te, fmval)) return 1;
124                         }
125                         /* Check if mouse cursor is below the tree */
126                         te = soops->tree.last;
127                         while (((te->flag & TE_LAZY_CLOSED) == 0) && (te->subtree.last)) {
128                                 te = te->subtree.last;
129                         }
130                         if (fmval[1] < te->ys) return 1;
131                 }
132         }
133         return 0;
134 }
135
136 static void outliner_parent_clear_copy(wmDrag *drag, wmDropBox *drop)
137 {
138         ID *id = (ID *)drag->poin;
139         RNA_string_set(drop->ptr, "dragged_obj", id->name + 2);
140
141         /* Set to simple parent clear type. Avoid menus for drag and drop if possible.
142          * If desired, user can toggle the different "Clear Parent" types in the operator
143          * menu on tool shelf. */
144         RNA_enum_set(drop->ptr, "type", 0);
145 }
146
147 static int outliner_scene_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
148 {
149         ARegion *ar = CTX_wm_region(C);
150         SpaceOops *soops = CTX_wm_space_outliner(C);
151         TreeElement *te = NULL;
152         float fmval[2];
153         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
154
155         if (drag->type == WM_DRAG_ID) {
156                 ID *id = (ID *)drag->poin;
157                 if (GS(id->name) == ID_OB) {
158                         /* Ensure item under cursor is valid drop target */
159                         /* Find object hovered over */
160                         for (te = soops->tree.first; te; te = te->next) {
161                                 if (outliner_dropzone_scene(C, event, te, fmval))
162                                         return 1;
163                         }
164                 }
165         }
166         return 0;
167 }
168
169 static void outliner_scene_drop_copy(wmDrag *drag, wmDropBox *drop)
170 {
171         ID *id = (ID *)drag->poin;
172
173         RNA_string_set(drop->ptr, "object", id->name + 2);
174 }
175
176 /* region dropbox definition */
177 static void outliner_dropboxes(void)
178 {
179         ListBase *lb = WM_dropboxmap_find("Outliner", SPACE_OUTLINER, RGN_TYPE_WINDOW);
180
181         WM_dropbox_add(lb, "OUTLINER_OT_parent_drop", outliner_parent_drop_poll, outliner_parent_drop_copy);
182         WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", outliner_parent_clear_poll, outliner_parent_clear_copy);
183         WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", outliner_scene_drop_poll, outliner_scene_drop_copy);
184 }
185
186 static void outliner_main_area_draw(const bContext *C, ARegion *ar)
187 {
188         View2D *v2d = &ar->v2d;
189         View2DScrollers *scrollers;
190         
191         /* clear */
192         UI_ThemeClearColor(TH_BACK);
193         glClear(GL_COLOR_BUFFER_BIT);
194         
195         draw_outliner(C);
196         
197         /* reset view matrix */
198         UI_view2d_view_restore(C);
199         
200         /* scrollers */
201         scrollers = UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
202         UI_view2d_scrollers_draw(C, v2d, scrollers);
203         UI_view2d_scrollers_free(scrollers);
204 }
205
206
207 static void outliner_main_area_free(ARegion *UNUSED(ar))
208 {
209         
210 }
211
212 static void outliner_main_area_listener(ARegion *ar, wmNotifier *wmn)
213 {
214         /* context changes */
215         switch (wmn->category) {
216                 case NC_SCENE:
217                         switch (wmn->data) {
218                                 case ND_OB_ACTIVE:
219                                 case ND_OB_SELECT:
220                                 case ND_OB_VISIBLE:
221                                 case ND_OB_RENDER:
222                                 case ND_MODE:
223                                 case ND_KEYINGSET:
224                                 case ND_FRAME:
225                                 case ND_RENDER_OPTIONS:
226                                 case ND_LAYER:
227                                 case ND_WORLD:
228                                         ED_region_tag_redraw(ar);
229                                         break;
230                         }
231                         break;
232                 case NC_OBJECT:
233                         switch (wmn->data) {
234                                 case ND_TRANSFORM:
235                                         /* transform doesn't change outliner data */
236                                         break;
237                                 case ND_BONE_ACTIVE:
238                                 case ND_BONE_SELECT:
239                                 case ND_DRAW:
240                                 case ND_PARENT:
241                                 case ND_OB_SHADING:
242                                         ED_region_tag_redraw(ar);
243                                         break;
244                                 case ND_CONSTRAINT:
245                                         switch (wmn->action) {
246                                                 case NA_ADDED:
247                                                 case NA_REMOVED:
248                                                 case NA_RENAME:
249                                                         ED_region_tag_redraw(ar);
250                                                         break;
251                                         }
252                                         break;
253                                 case ND_MODIFIER:
254                                         /* all modifier actions now */
255                                         ED_region_tag_redraw(ar);
256                                         break;
257                         }
258                         break;
259                 case NC_GROUP:
260                         /* all actions now, todo: check outliner view mode? */
261                         ED_region_tag_redraw(ar);
262                         break;
263                 case NC_LAMP:
264                         /* For updating lamp icons, when changing lamp type */
265                         if (wmn->data == ND_LIGHTING_DRAW)
266                                 ED_region_tag_redraw(ar);
267                         break;
268                 case NC_SPACE:
269                         if (wmn->data == ND_SPACE_OUTLINER)
270                                 ED_region_tag_redraw(ar);
271                         break;
272                 case NC_ID:
273                         if (wmn->action == NA_RENAME)
274                                 ED_region_tag_redraw(ar);
275                         break;
276                 case NC_MATERIAL:
277                         switch (wmn->data) {
278                                 case ND_SHADING:
279                                 case ND_SHADING_DRAW:
280                                         ED_region_tag_redraw(ar);
281                                         break;
282                         }
283                         break;
284                 case NC_TEXTURE:
285                         ED_region_tag_redraw(ar);
286                         break;
287                 case NC_GEOM:
288                         switch (wmn->data) {
289                                 case ND_DATA:
290                                         /* needed for vertex groups only, no special notifier atm so use NC_GEOM|ND_DATA */
291                                         ED_region_tag_redraw(ar);
292                                         break;
293                         }
294                         break;
295                 case NC_ANIMATION:
296                         switch (wmn->data) {
297                                 case ND_NLA_ACTCHANGE:
298                                 case ND_KEYFRAME:
299                                         ED_region_tag_redraw(ar);
300                                         break;
301                                 case ND_ANIMCHAN:
302                                         if (wmn->action == NA_SELECTED)
303                                                 ED_region_tag_redraw(ar);
304                                         break;
305                         }
306                         break;
307         }
308         
309 }
310
311
312 /* ************************ header outliner area region *********************** */
313
314 /* add handlers, stuff you only do once or on area/region changes */
315 static void outliner_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
316 {
317         ED_region_header_init(ar);
318 }
319
320 static void outliner_header_area_draw(const bContext *C, ARegion *ar)
321 {
322         ED_region_header(C, ar);
323 }
324
325 static void outliner_header_area_free(ARegion *UNUSED(ar))
326 {
327 }
328
329 static void outliner_header_area_listener(ARegion *ar, wmNotifier *wmn)
330 {
331         /* context changes */
332         switch (wmn->category) {
333                 case NC_SCENE:
334                         if (wmn->data == ND_KEYINGSET)
335                                 ED_region_tag_redraw(ar);
336                         break;
337                 case NC_SPACE:
338                         if (wmn->data == ND_SPACE_OUTLINER)
339                                 ED_region_tag_redraw(ar);
340                         break;
341         }
342 }
343
344 /* ******************** default callbacks for outliner space ***************** */
345
346 static SpaceLink *outliner_new(const bContext *UNUSED(C))
347 {
348         ARegion *ar;
349         SpaceOops *soutliner;
350
351         soutliner = MEM_callocN(sizeof(SpaceOops), "initoutliner");
352         soutliner->spacetype = SPACE_OUTLINER;
353         
354         /* header */
355         ar = MEM_callocN(sizeof(ARegion), "header for outliner");
356         
357         BLI_addtail(&soutliner->regionbase, ar);
358         ar->regiontype = RGN_TYPE_HEADER;
359         ar->alignment = RGN_ALIGN_BOTTOM;
360         
361         /* main area */
362         ar = MEM_callocN(sizeof(ARegion), "main area for outliner");
363         
364         BLI_addtail(&soutliner->regionbase, ar);
365         ar->regiontype = RGN_TYPE_WINDOW;
366         
367         ar->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM_O);
368         ar->v2d.align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y);
369         ar->v2d.keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT);
370         ar->v2d.keeptot = V2D_KEEPTOT_STRICT;
371         ar->v2d.minzoom = ar->v2d.maxzoom = 1.0f;
372         
373         return (SpaceLink *)soutliner;
374 }
375
376 /* not spacelink itself */
377 static void outliner_free(SpaceLink *sl)
378 {
379         SpaceOops *soutliner = (SpaceOops *)sl;
380         
381         outliner_free_tree(&soutliner->tree);
382         if (soutliner->treestore) {
383                 if (soutliner->treestore->data) MEM_freeN(soutliner->treestore->data);
384                 MEM_freeN(soutliner->treestore);
385         }
386         
387 }
388
389 /* spacetype; init callback */
390 static void outliner_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
391 {
392         
393 }
394
395 static SpaceLink *outliner_duplicate(SpaceLink *sl)
396 {
397         SpaceOops *soutliner = (SpaceOops *)sl;
398         SpaceOops *soutlinern = MEM_dupallocN(soutliner);
399
400         soutlinern->tree.first = soutlinern->tree.last = NULL;
401         soutlinern->treestore = NULL;
402         
403         return (SpaceLink *)soutlinern;
404 }
405
406 /* only called once, from space_api/spacetypes.c */
407 void ED_spacetype_outliner(void)
408 {
409         SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype time");
410         ARegionType *art;
411         
412         st->spaceid = SPACE_OUTLINER;
413         strncpy(st->name, "Outliner", BKE_ST_MAXNAME);
414         
415         st->new = outliner_new;
416         st->free = outliner_free;
417         st->init = outliner_init;
418         st->duplicate = outliner_duplicate;
419         st->operatortypes = outliner_operatortypes;
420         st->keymap = outliner_keymap;
421         st->dropboxes = outliner_dropboxes;
422         
423         /* regions: main window */
424         art = MEM_callocN(sizeof(ARegionType), "spacetype time region");
425         art->regionid = RGN_TYPE_WINDOW;
426         art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
427         
428         art->init = outliner_main_area_init;
429         art->draw = outliner_main_area_draw;
430         art->free = outliner_main_area_free;
431         art->listener = outliner_main_area_listener;
432         BLI_addhead(&st->regiontypes, art);
433         
434         /* regions: header */
435         art = MEM_callocN(sizeof(ARegionType), "spacetype time region");
436         art->regionid = RGN_TYPE_HEADER;
437         art->prefsizey = HEADERY;
438         art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
439         
440         art->init = outliner_header_area_init;
441         art->draw = outliner_header_area_draw;
442         art->free = outliner_header_area_free;
443         art->listener = outliner_header_area_listener;
444         BLI_addhead(&st->regiontypes, art);
445         
446         BKE_spacetype_register(st);
447 }
448