a040c63b2ab834f03a3115ae429ba00a43158c55
[blender-staging.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 /* region dropbox definition */
148 static void outliner_dropboxes(void)
149 {
150         ListBase *lb = WM_dropboxmap_find("Outliner", SPACE_OUTLINER, RGN_TYPE_WINDOW);
151
152         WM_dropbox_add(lb, "OUTLINER_OT_parent_drop", outliner_parent_drop_poll, outliner_parent_drop_copy);
153         WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", outliner_parent_clear_poll, outliner_parent_clear_copy);
154 }
155
156 static void outliner_main_area_draw(const bContext *C, ARegion *ar)
157 {
158         View2D *v2d= &ar->v2d;
159         View2DScrollers *scrollers;
160         
161         /* clear */
162         UI_ThemeClearColor(TH_BACK);
163         glClear(GL_COLOR_BUFFER_BIT);
164         
165         draw_outliner(C);
166         
167         /* reset view matrix */
168         UI_view2d_view_restore(C);
169         
170         /* scrollers */
171         scrollers= UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
172         UI_view2d_scrollers_draw(C, v2d, scrollers);
173         UI_view2d_scrollers_free(scrollers);
174 }
175
176
177 static void outliner_main_area_free(ARegion *UNUSED(ar))
178 {
179         
180 }
181
182 static void outliner_main_area_listener(ARegion *ar, wmNotifier *wmn)
183 {
184         /* context changes */
185         switch(wmn->category) {
186                 case NC_SCENE:
187                         switch(wmn->data) {
188                                 case ND_OB_ACTIVE:
189                                 case ND_OB_SELECT:
190                                 case ND_OB_VISIBLE:
191                                 case ND_OB_RENDER:
192                                 case ND_MODE:
193                                 case ND_KEYINGSET:
194                                 case ND_FRAME:
195                                 case ND_RENDER_OPTIONS:
196                                 case ND_LAYER:
197                                 case ND_WORLD:
198                                         ED_region_tag_redraw(ar);
199                                         break;
200                         }
201                         break;
202                 case NC_OBJECT:
203                         switch(wmn->data) {
204                                 case ND_TRANSFORM:
205                                         /* transform doesn't change outliner data */
206                                         break;
207                                 case ND_BONE_ACTIVE:
208                                 case ND_BONE_SELECT:
209                                 case ND_DRAW:
210                                 case ND_PARENT:
211                                 case ND_OB_SHADING:
212                                         ED_region_tag_redraw(ar);
213                                         break;
214                                 case ND_CONSTRAINT:
215                                         switch(wmn->action) {
216                                                 case NA_ADDED:
217                                                 case NA_REMOVED:
218                                                 case NA_RENAME:
219                                                         ED_region_tag_redraw(ar);
220                                                         break;
221                                         }
222                                         break;
223                                 case ND_MODIFIER:
224                                         /* all modifier actions now */
225                                         ED_region_tag_redraw(ar);
226                                         break;
227                         }
228                         break;
229                 case NC_GROUP:
230                         /* all actions now, todo: check outliner view mode? */
231                         ED_region_tag_redraw(ar);
232                         break;
233                 case NC_LAMP:
234                         /* For updating lamp icons, when changing lamp type */
235                         if(wmn->data == ND_LIGHTING_DRAW)
236                                 ED_region_tag_redraw(ar);
237                                 break;
238                 case NC_SPACE:
239                         if(wmn->data == ND_SPACE_OUTLINER)
240                                 ED_region_tag_redraw(ar);
241                                 break;
242                 case NC_ID:
243                         if(wmn->action == NA_RENAME)
244                                 ED_region_tag_redraw(ar);
245                         break;
246                 case NC_MATERIAL:
247                         switch(wmn->data) {
248                                 case ND_SHADING:
249                                 case ND_SHADING_DRAW:
250                                         ED_region_tag_redraw(ar);
251                                         break;
252                         }
253                         break;
254                 case NC_TEXTURE:
255                         ED_region_tag_redraw(ar);
256                         break;
257                 case NC_GEOM:
258                         switch(wmn->data) {
259                                 case ND_DATA:
260                                         /* needed for vertex groups only, no special notifier atm so use NC_GEOM|ND_DATA */
261                                         ED_region_tag_redraw(ar);
262                                         break;
263                         }
264                         break;
265                 case NC_ANIMATION:
266                         switch(wmn->data) {
267                                 case ND_NLA_ACTCHANGE:
268                                         ED_region_tag_redraw(ar);
269                                         break;
270                                 case ND_ANIMCHAN:
271                                         if(wmn->action==NA_SELECTED)
272                                                 ED_region_tag_redraw(ar);
273                                         break;
274                         }
275                         break;
276         }
277         
278 }
279
280
281 /* ************************ header outliner area region *********************** */
282
283 /* add handlers, stuff you only do once or on area/region changes */
284 static void outliner_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
285 {
286         ED_region_header_init(ar);
287 }
288
289 static void outliner_header_area_draw(const bContext *C, ARegion *ar)
290 {
291         ED_region_header(C, ar);
292 }
293
294 static void outliner_header_area_free(ARegion *UNUSED(ar))
295 {
296 }
297
298 static void outliner_header_area_listener(ARegion *ar, wmNotifier *wmn)
299 {
300         /* context changes */
301         switch(wmn->category) {
302                 case NC_SCENE:
303                         if(wmn->data == ND_KEYINGSET)
304                                 ED_region_tag_redraw(ar);
305                         break;
306                 case NC_SPACE:
307                         if(wmn->data == ND_SPACE_OUTLINER)
308                                 ED_region_tag_redraw(ar);
309                         break;
310         }
311 }
312
313 /* ******************** default callbacks for outliner space ***************** */
314
315 static SpaceLink *outliner_new(const bContext *UNUSED(C))
316 {
317         ARegion *ar;
318         SpaceOops *soutliner;
319
320         soutliner= MEM_callocN(sizeof(SpaceOops), "initoutliner");
321         soutliner->spacetype= SPACE_OUTLINER;
322         
323         /* header */
324         ar= MEM_callocN(sizeof(ARegion), "header for outliner");
325         
326         BLI_addtail(&soutliner->regionbase, ar);
327         ar->regiontype= RGN_TYPE_HEADER;
328         ar->alignment= RGN_ALIGN_BOTTOM;
329         
330         /* main area */
331         ar= MEM_callocN(sizeof(ARegion), "main area for outliner");
332         
333         BLI_addtail(&soutliner->regionbase, ar);
334         ar->regiontype= RGN_TYPE_WINDOW;
335         
336         ar->v2d.scroll = (V2D_SCROLL_RIGHT|V2D_SCROLL_BOTTOM_O);
337         ar->v2d.align = (V2D_ALIGN_NO_NEG_X|V2D_ALIGN_NO_POS_Y);
338         ar->v2d.keepzoom = (V2D_LOCKZOOM_X|V2D_LOCKZOOM_Y|V2D_LIMITZOOM|V2D_KEEPASPECT);
339         ar->v2d.keeptot= V2D_KEEPTOT_STRICT;
340         ar->v2d.minzoom= ar->v2d.maxzoom= 1.0f;
341         
342         return (SpaceLink*)soutliner;
343 }
344
345 /* not spacelink itself */
346 static void outliner_free(SpaceLink *sl)
347 {
348         SpaceOops *soutliner= (SpaceOops*)sl;
349         
350         outliner_free_tree(&soutliner->tree);
351         if(soutliner->treestore) {
352                 if(soutliner->treestore->data) MEM_freeN(soutliner->treestore->data);
353                 MEM_freeN(soutliner->treestore);
354         }
355         
356 }
357
358 /* spacetype; init callback */
359 static void outliner_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
360 {
361         
362 }
363
364 static SpaceLink *outliner_duplicate(SpaceLink *sl)
365 {
366         SpaceOops *soutliner= (SpaceOops *)sl;
367         SpaceOops *soutlinern= MEM_dupallocN(soutliner);
368
369         soutlinern->tree.first= soutlinern->tree.last= NULL;
370         soutlinern->treestore= NULL;
371         
372         return (SpaceLink *)soutlinern;
373 }
374
375 /* only called once, from space_api/spacetypes.c */
376 void ED_spacetype_outliner(void)
377 {
378         SpaceType *st= MEM_callocN(sizeof(SpaceType), "spacetype time");
379         ARegionType *art;
380         
381         st->spaceid= SPACE_OUTLINER;
382         strncpy(st->name, "Outliner", BKE_ST_MAXNAME);
383         
384         st->new= outliner_new;
385         st->free= outliner_free;
386         st->init= outliner_init;
387         st->duplicate= outliner_duplicate;
388         st->operatortypes= outliner_operatortypes;
389         st->keymap= outliner_keymap;
390         st->dropboxes= outliner_dropboxes;
391         
392         /* regions: main window */
393         art= MEM_callocN(sizeof(ARegionType), "spacetype time region");
394         art->regionid = RGN_TYPE_WINDOW;
395         art->keymapflag= ED_KEYMAP_UI|ED_KEYMAP_VIEW2D;
396         
397         art->init= outliner_main_area_init;
398         art->draw= outliner_main_area_draw;
399         art->free= outliner_main_area_free;
400         art->listener= outliner_main_area_listener;
401         BLI_addhead(&st->regiontypes, art);
402         
403         /* regions: header */
404         art= MEM_callocN(sizeof(ARegionType), "spacetype time region");
405         art->regionid = RGN_TYPE_HEADER;
406         art->prefsizey= HEADERY;
407         art->keymapflag= ED_KEYMAP_UI|ED_KEYMAP_VIEW2D|ED_KEYMAP_FRAMES|ED_KEYMAP_HEADER;
408         
409         art->init= outliner_header_area_init;
410         art->draw= outliner_header_area_draw;
411         art->free= outliner_header_area_free;
412         art->listener= outliner_header_area_listener;
413         BLI_addhead(&st->regiontypes, art);
414         
415         BKE_spacetype_register(st);
416 }
417