NLA SoC: Merge from 2.5
[blender.git] / source / blender / blenkernel / intern / context.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) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation (2008).
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include "MEM_guardedalloc.h"
29
30 #include "DNA_ID.h"
31 #include "DNA_listBase.h"
32 #include "DNA_scene_types.h"
33 #include "DNA_screen_types.h"
34 #include "DNA_space_types.h"
35 #include "DNA_view3d_types.h"
36 #include "DNA_windowmanager_types.h"
37
38 #include "RNA_access.h"
39
40 #include "BLI_listbase.h"
41 #include "BLI_string.h"
42
43 #include "BKE_context.h"
44 #include "BKE_main.h"
45 #include "BKE_screen.h"
46
47 #include <string.h>
48
49 /* struct */
50
51 struct bContext {
52         int thread;
53
54         /* windowmanager context */
55         struct {
56                 struct wmWindowManager *manager;
57                 struct wmWindow *window;
58                 struct bScreen *screen;
59                 struct ScrArea *area;
60                 struct ARegion *region;
61                 struct ARegion *menu;
62                 struct bContextStore *store;
63         } wm;
64         
65         /* data context */
66         struct {
67                 struct Main *main;
68                 struct Scene *scene;
69
70                 int recursion;
71         } data;
72         
73         /* data evaluation */
74         struct {
75                 int render;
76         } eval;
77 };
78
79 /* context */
80
81 bContext *CTX_create()
82 {
83         bContext *C;
84         
85         C= MEM_callocN(sizeof(bContext), "bContext");
86
87         return C;
88 }
89
90 bContext *CTX_copy(const bContext *C)
91 {
92         bContext *newC= MEM_dupallocN((void*)C);
93
94         return newC;
95 }
96
97 void CTX_free(bContext *C)
98 {
99         MEM_freeN(C);
100 }
101
102 /* store */
103
104 bContextStore *CTX_store_add(ListBase *contexts, char *name, PointerRNA *ptr)
105 {
106         bContextStoreEntry *entry;
107         bContextStore *ctx, *lastctx;
108
109         /* ensure we have a context to put the entry in, if it was already used
110          * we have to copy the context to ensure */
111         ctx= contexts->last;
112
113         if(!ctx || ctx->used) {
114                 if(ctx) {
115                         lastctx= ctx;
116                         ctx= MEM_dupallocN(lastctx);
117                         BLI_duplicatelist(&ctx->entries, &lastctx->entries);
118                 }
119                 else
120                         ctx= MEM_callocN(sizeof(bContextStore), "bContextStore");
121
122                 BLI_addtail(contexts, ctx);
123         }
124
125         entry= MEM_callocN(sizeof(bContextStoreEntry), "bContextStoreEntry");
126         BLI_strncpy(entry->name, name, sizeof(entry->name));
127         entry->ptr= *ptr;
128
129         BLI_addtail(&ctx->entries, entry);
130
131         return ctx;
132 }
133
134 void CTX_store_set(bContext *C, bContextStore *store)
135 {
136         C->wm.store= store;
137 }
138
139 bContextStore *CTX_store_copy(bContextStore *store)
140 {
141         bContextStore *ctx;
142
143         ctx= MEM_dupallocN(store);
144         BLI_duplicatelist(&ctx->entries, &store->entries);
145
146         return ctx;
147 }
148
149 void CTX_store_free(bContextStore *store)
150 {
151         BLI_freelistN(&store->entries);
152         MEM_freeN(store);
153 }
154
155 void CTX_store_free_list(ListBase *contexts)
156 {
157         bContextStore *ctx;
158
159         while((ctx= contexts->first)) {
160                 BLI_remlink(contexts, ctx);
161                 CTX_store_free(ctx);
162         }
163 }
164
165 /* window manager context */
166
167 wmWindowManager *CTX_wm_manager(const bContext *C)
168 {
169         return C->wm.manager;
170 }
171
172 wmWindow *CTX_wm_window(const bContext *C)
173 {
174         return C->wm.window;
175 }
176
177 bScreen *CTX_wm_screen(const bContext *C)
178 {
179         return C->wm.screen;
180 }
181
182 ScrArea *CTX_wm_area(const bContext *C)
183 {
184         return C->wm.area;
185 }
186
187 SpaceLink *CTX_wm_space_data(const bContext *C)
188 {
189         return (C->wm.area)? C->wm.area->spacedata.first: NULL;
190 }
191
192 ARegion *CTX_wm_region(const bContext *C)
193 {
194         return C->wm.region;
195 }
196
197 void *CTX_wm_region_data(const bContext *C)
198 {
199         return (C->wm.region)? C->wm.region->regiondata: NULL;
200 }
201
202 struct ARegion *CTX_wm_menu(const bContext *C)
203 {
204         return C->wm.menu;
205 }
206
207 View3D *CTX_wm_view3d(const bContext *C)
208 {
209         if(C->wm.area && C->wm.area->spacetype==SPACE_VIEW3D)
210                 return C->wm.area->spacedata.first;
211         return NULL;
212 }
213
214 RegionView3D *CTX_wm_region_view3d(const bContext *C)
215 {
216         if(C->wm.area && C->wm.area->spacetype==SPACE_VIEW3D)
217                 if(C->wm.region)
218                         return C->wm.region->regiondata;
219         return NULL;
220 }
221
222 struct SpaceText *CTX_wm_space_text(const bContext *C)
223 {
224         if(C->wm.area && C->wm.area->spacetype==SPACE_TEXT)
225                 return C->wm.area->spacedata.first;
226         return NULL;
227 }
228
229 struct SpaceImage *CTX_wm_space_image(const bContext *C)
230 {
231         if(C->wm.area && C->wm.area->spacetype==SPACE_IMAGE)
232                 return C->wm.area->spacedata.first;
233         return NULL;
234 }
235
236 void CTX_wm_manager_set(bContext *C, wmWindowManager *wm)
237 {
238         C->wm.manager= wm;
239         C->wm.window= NULL;
240         C->wm.screen= NULL;
241         C->wm.area= NULL;
242         C->wm.region= NULL;
243 }
244
245 void CTX_wm_window_set(bContext *C, wmWindow *win)
246 {
247         C->wm.window= win;
248         C->wm.screen= (win)? win->screen: NULL;
249         C->data.scene= (C->wm.screen)? C->wm.screen->scene: NULL;
250         C->wm.area= NULL;
251         C->wm.region= NULL;
252 }
253
254 void CTX_wm_screen_set(bContext *C, bScreen *screen)
255 {
256         C->wm.screen= screen;
257         C->data.scene= (C->wm.screen)? C->wm.screen->scene: NULL;
258         C->wm.area= NULL;
259         C->wm.region= NULL;
260 }
261
262 void CTX_wm_area_set(bContext *C, ScrArea *area)
263 {
264         C->wm.area= area;
265         C->wm.region= NULL;
266 }
267
268 void CTX_wm_region_set(bContext *C, ARegion *region)
269 {
270         C->wm.region= region;
271 }
272
273 void CTX_wm_menu_set(bContext *C, ARegion *menu)
274 {
275         C->wm.menu= menu;
276 }
277
278 /* data context utility functions */
279
280 struct bContextDataResult {
281         PointerRNA ptr;
282         ListBase list;
283         const char **dir;
284 };
285
286 static int ctx_data_get(bContext *C, const char *member, bContextDataResult *result)
287 {
288         int done= 0, recursion= C->data.recursion;
289
290         memset(result, 0, sizeof(bContextDataResult));
291
292         /* we check recursion to ensure that we do not get infinite
293          * loops requesting data from ourselfs in a context callback */
294         if(!done && recursion < 1 && C->wm.store) {
295                 bContextStoreEntry *entry;
296
297                 C->data.recursion= 1;
298
299                 for(entry=C->wm.store->entries.first; entry; entry=entry->next) {
300                         if(strcmp(entry->name, member) == 0) {
301                                 result->ptr= entry->ptr;
302                                 done= 1;
303                         }
304                 }
305         }
306         if(!done && recursion < 2 && C->wm.region) {
307                 C->data.recursion= 2;
308                 if(C->wm.region->type && C->wm.region->type->context)
309                         done= C->wm.region->type->context(C, member, result);
310         }
311         if(!done && recursion < 3 && C->wm.area) {
312                 C->data.recursion= 3;
313                 if(C->wm.area->type && C->wm.area->type->context)
314                         done= C->wm.area->type->context(C, member, result);
315         }
316         if(!done && recursion < 4 && C->wm.screen) {
317                 bContextDataCallback cb= C->wm.screen->context;
318                 C->data.recursion= 4;
319                 if(cb)
320                         done= cb(C, member, result);
321         }
322
323         C->data.recursion= recursion;
324
325         return done;
326 }
327
328 static void *ctx_data_pointer_get(const bContext *C, const char *member)
329 {
330         bContextDataResult result;
331
332         if(ctx_data_get((bContext*)C, member, &result))
333                 return result.ptr.data;
334
335         return NULL;
336 }
337
338 static int ctx_data_pointer_verify(const bContext *C, const char *member, void **pointer)
339 {
340         bContextDataResult result;
341
342         if(ctx_data_get((bContext*)C, member, &result)) {
343                 *pointer= result.ptr.data;
344                 return 1;
345         }
346         else {
347                 *pointer= NULL;
348                 return 0;
349         }
350 }
351
352 static int ctx_data_collection_get(const bContext *C, const char *member, ListBase *list)
353 {
354         bContextDataResult result;
355
356         if(ctx_data_get((bContext*)C, member, &result)) {
357                 *list= result.list;
358                 return 1;
359         }
360
361         list->first= NULL;
362         list->last= NULL;
363
364         return 0;
365 }
366
367 PointerRNA CTX_data_pointer_get(const bContext *C, const char *member)
368 {
369         bContextDataResult result;
370
371         if(ctx_data_get((bContext*)C, member, &result))
372                 return result.ptr;
373         else
374                 return PointerRNA_NULL;
375 }
376
377 PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type)
378 {
379         PointerRNA ptr = CTX_data_pointer_get(C, member);
380
381         if(ptr.data && ptr.type == type)
382                 return ptr;
383         
384         return PointerRNA_NULL;
385 }
386
387 ListBase CTX_data_collection_get(const bContext *C, const char *member)
388 {
389         bContextDataResult result;
390
391         if(ctx_data_get((bContext*)C, member, &result)) {
392                 return result.list;
393         }
394         else {
395                 ListBase list;
396                 memset(&list, 0, sizeof(list));
397                 return list;
398         }
399 }
400
401 void CTX_data_get(const bContext *C, const char *member, PointerRNA *r_ptr, ListBase *r_lb)
402 {
403         bContextDataResult result;
404
405         if(ctx_data_get((bContext*)C, member, &result)) {
406                 *r_ptr= result.ptr;
407                 *r_lb= result.list;
408         }
409         else {
410                 memset(r_ptr, 0, sizeof(*r_ptr));
411                 memset(r_lb, 0, sizeof(*r_lb));
412         }
413 }
414
415 static void data_dir_add(ListBase *lb, const char *member)
416 {
417         LinkData *link;
418
419         if(strcmp(member, "scene") == 0) /* exception */
420                 return;
421
422         for(link=lb->first; link; link=link->next)
423                 if(strcmp(link->data, member) == 0)
424                         return;
425         
426         link= MEM_callocN(sizeof(LinkData), "LinkData");
427         link->data= (void*)member;
428         BLI_addtail(lb, link);
429 }
430
431 ListBase CTX_data_dir_get(const bContext *C)
432 {
433         bContextDataResult result;
434         ListBase lb;
435         int a;
436
437         memset(&lb, 0, sizeof(lb));
438
439         if(C->wm.store) {
440                 bContextStoreEntry *entry;
441
442                 for(entry=C->wm.store->entries.first; entry; entry=entry->next)
443                         data_dir_add(&lb, entry->name);
444         }
445         if(C->wm.region && C->wm.region->type && C->wm.region->type->context) {
446                 memset(&result, 0, sizeof(result));
447                 C->wm.region->type->context(C, "", &result);
448
449                 if(result.dir)
450                         for(a=0; result.dir[a]; a++)
451                                 data_dir_add(&lb, result.dir[a]);
452         }
453         if(C->wm.area && C->wm.area->type && C->wm.area->type->context) {
454                 memset(&result, 0, sizeof(result));
455                 C->wm.area->type->context(C, "", &result);
456
457                 if(result.dir)
458                         for(a=0; result.dir[a]; a++)
459                                 data_dir_add(&lb, result.dir[a]);
460         }
461         if(C->wm.screen && C->wm.screen->context) {
462                 bContextDataCallback cb= C->wm.screen->context;
463                 memset(&result, 0, sizeof(result));
464                 cb(C, "", &result);
465
466                 if(result.dir)
467                         for(a=0; result.dir[a]; a++)
468                                 data_dir_add(&lb, result.dir[a]);
469         }
470
471         return lb;
472 }
473
474 int CTX_data_equals(const char *member, const char *str)
475 {
476         return (strcmp(member, str) == 0);
477 }
478
479 int CTX_data_dir(const char *member)
480 {
481         return (strcmp(member, "") == 0);
482 }
483
484 void CTX_data_id_pointer_set(bContextDataResult *result, ID *id)
485 {
486         RNA_id_pointer_create(id, &result->ptr);
487 }
488
489 void CTX_data_pointer_set(bContextDataResult *result, ID *id, StructRNA *type, void *data)
490 {
491         RNA_pointer_create(id, type, data, &result->ptr);
492 }
493
494 void CTX_data_id_list_add(bContextDataResult *result, ID *id)
495 {
496         CollectionPointerLink *link;
497
498         link= MEM_callocN(sizeof(CollectionPointerLink), "CTX_data_id_list_add");
499         RNA_id_pointer_create(id, &link->ptr);
500
501         BLI_addtail(&result->list, link);
502 }
503
504 void CTX_data_list_add(bContextDataResult *result, ID *id, StructRNA *type, void *data)
505 {
506         CollectionPointerLink *link;
507
508         link= MEM_callocN(sizeof(CollectionPointerLink), "CTX_data_list_add");
509         RNA_pointer_create(id, type, data, &link->ptr);
510
511         BLI_addtail(&result->list, link);
512 }
513
514 int ctx_data_list_count(const bContext *C, int (*func)(const bContext*, ListBase*))
515 {
516         ListBase list;
517
518         if(func(C, &list)) {
519                 int tot= BLI_countlist(&list);
520                 BLI_freelistN(&list);
521                 return tot;
522         }
523         else
524                 return 0;
525 }
526
527 void CTX_data_dir_set(bContextDataResult *result, const char **dir)
528 {
529         result->dir= dir;
530 }
531
532 /* data context */
533
534 Main *CTX_data_main(const bContext *C)
535 {
536         Main *bmain;
537
538         if(ctx_data_pointer_verify(C, "main", (void*)&bmain))
539                 return bmain;
540         else
541                 return C->data.main;
542 }
543
544 void CTX_data_main_set(bContext *C, Main *bmain)
545 {
546         C->data.main= bmain;
547 }
548
549 Scene *CTX_data_scene(const bContext *C)
550 {
551         Scene *scene;
552
553         if(ctx_data_pointer_verify(C, "scene", (void*)&scene))
554                 return scene;
555         else
556                 return C->data.scene;
557 }
558
559 void CTX_data_scene_set(bContext *C, Scene *scene)
560 {
561         C->data.scene= scene;
562 }
563
564 ToolSettings *CTX_data_tool_settings(const bContext *C)
565 {
566         Scene *scene = CTX_data_scene(C);
567
568         if(scene)
569                 return scene->toolsettings;
570         else
571                 return NULL;
572 }
573
574 int CTX_data_selected_nodes(const bContext *C, ListBase *list)
575 {
576         return ctx_data_collection_get(C, "selected_nodes", list);
577 }
578
579 int CTX_data_selected_editable_objects(const bContext *C, ListBase *list)
580 {
581         return ctx_data_collection_get(C, "selected_editable_objects", list);
582 }
583
584 int CTX_data_selected_editable_bases(const bContext *C, ListBase *list)
585 {
586         return ctx_data_collection_get(C, "selected_editable_bases", list);
587 }
588
589 int CTX_data_selected_objects(const bContext *C, ListBase *list)
590 {
591         return ctx_data_collection_get(C, "selected_objects", list);
592 }
593
594 int CTX_data_selected_bases(const bContext *C, ListBase *list)
595 {
596         return ctx_data_collection_get(C, "selected_bases", list);
597 }
598
599 int CTX_data_visible_objects(const bContext *C, ListBase *list)
600 {
601         return ctx_data_collection_get(C, "visible_objects", list);
602 }
603
604 int CTX_data_visible_bases(const bContext *C, ListBase *list)
605 {
606         return ctx_data_collection_get(C, "visible_bases", list);
607 }
608
609 struct Object *CTX_data_active_object(const bContext *C)
610 {
611         return ctx_data_pointer_get(C, "active_object");
612 }
613
614 struct Base *CTX_data_active_base(const bContext *C)
615 {
616         return ctx_data_pointer_get(C, "active_base");
617 }
618
619 struct Object *CTX_data_edit_object(const bContext *C)
620 {
621         return ctx_data_pointer_get(C, "edit_object");
622 }
623
624 struct Image *CTX_data_edit_image(const bContext *C)
625 {
626         return ctx_data_pointer_get(C, "edit_image");
627 }
628
629 struct Text *CTX_data_edit_text(const bContext *C)
630 {
631         return ctx_data_pointer_get(C, "edit_text");
632 }
633
634 struct EditBone *CTX_data_active_bone(const bContext *C)
635 {
636         return ctx_data_pointer_get(C, "active_bone");
637 }
638
639 int CTX_data_selected_bones(const bContext *C, ListBase *list)
640 {
641         return ctx_data_collection_get(C, "selected_bones", list);
642 }
643
644 int CTX_data_selected_editable_bones(const bContext *C, ListBase *list)
645 {
646         return ctx_data_collection_get(C, "selected_editable_bones", list);
647 }
648
649 int CTX_data_visible_bones(const bContext *C, ListBase *list)
650 {
651         return ctx_data_collection_get(C, "visible_bones", list);
652 }
653
654 int CTX_data_editable_bones(const bContext *C, ListBase *list)
655 {
656         return ctx_data_collection_get(C, "editable_bones", list);
657 }
658
659 struct bPoseChannel *CTX_data_active_pchan(const bContext *C)
660 {
661         return ctx_data_pointer_get(C, "active_pchan");
662 }
663
664 int CTX_data_selected_pchans(const bContext *C, ListBase *list)
665 {
666         return ctx_data_collection_get(C, "selected_pchans", list);
667 }
668
669 int CTX_data_visible_pchans(const bContext *C, ListBase *list)
670 {
671         return ctx_data_collection_get(C, "visible_pchans", list);
672 }
673