bbf3ceb01e8fa9c09b61b0b7b2f90f915d3b8ab8
[blender-staging.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 struct ReportList *CTX_wm_reports(const bContext *C)
208 {
209         return C->wm.manager->reports;
210 }
211
212 View3D *CTX_wm_view3d(const bContext *C)
213 {
214         if(C->wm.area && C->wm.area->spacetype==SPACE_VIEW3D)
215                 return C->wm.area->spacedata.first;
216         return NULL;
217 }
218
219 RegionView3D *CTX_wm_region_view3d(const bContext *C)
220 {
221         if(C->wm.area && C->wm.area->spacetype==SPACE_VIEW3D)
222                 if(C->wm.region)
223                         return C->wm.region->regiondata;
224         return NULL;
225 }
226
227 struct SpaceText *CTX_wm_space_text(const bContext *C)
228 {
229         if(C->wm.area && C->wm.area->spacetype==SPACE_TEXT)
230                 return C->wm.area->spacedata.first;
231         return NULL;
232 }
233
234 struct SpaceConsole *CTX_wm_space_console(const bContext *C)
235 {
236         if(C->wm.area && C->wm.area->spacetype==SPACE_CONSOLE)
237                 return C->wm.area->spacedata.first;
238         return NULL;
239 }
240
241 struct SpaceImage *CTX_wm_space_image(const bContext *C)
242 {
243         if(C->wm.area && C->wm.area->spacetype==SPACE_IMAGE)
244                 return C->wm.area->spacedata.first;
245         return NULL;
246 }
247
248 void CTX_wm_manager_set(bContext *C, wmWindowManager *wm)
249 {
250         C->wm.manager= wm;
251         C->wm.window= NULL;
252         C->wm.screen= NULL;
253         C->wm.area= NULL;
254         C->wm.region= NULL;
255 }
256
257 void CTX_wm_window_set(bContext *C, wmWindow *win)
258 {
259         C->wm.window= win;
260         C->wm.screen= (win)? win->screen: NULL;
261         C->data.scene= (C->wm.screen)? C->wm.screen->scene: NULL;
262         C->wm.area= NULL;
263         C->wm.region= NULL;
264 }
265
266 void CTX_wm_screen_set(bContext *C, bScreen *screen)
267 {
268         C->wm.screen= screen;
269         C->data.scene= (C->wm.screen)? C->wm.screen->scene: NULL;
270         C->wm.area= NULL;
271         C->wm.region= NULL;
272 }
273
274 void CTX_wm_area_set(bContext *C, ScrArea *area)
275 {
276         C->wm.area= area;
277         C->wm.region= NULL;
278 }
279
280 void CTX_wm_region_set(bContext *C, ARegion *region)
281 {
282         C->wm.region= region;
283 }
284
285 void CTX_wm_menu_set(bContext *C, ARegion *menu)
286 {
287         C->wm.menu= menu;
288 }
289
290 /* data context utility functions */
291
292 struct bContextDataResult {
293         PointerRNA ptr;
294         ListBase list;
295         const char **dir;
296 };
297
298 static int ctx_data_get(bContext *C, const char *member, bContextDataResult *result)
299 {
300         int done= 0, recursion= C->data.recursion;
301
302         memset(result, 0, sizeof(bContextDataResult));
303
304         /* we check recursion to ensure that we do not get infinite
305          * loops requesting data from ourselfs in a context callback */
306         if(!done && recursion < 1 && C->wm.store) {
307                 bContextStoreEntry *entry;
308
309                 C->data.recursion= 1;
310
311                 for(entry=C->wm.store->entries.first; entry; entry=entry->next) {
312                         if(strcmp(entry->name, member) == 0) {
313                                 result->ptr= entry->ptr;
314                                 done= 1;
315                         }
316                 }
317         }
318         if(!done && recursion < 2 && C->wm.region) {
319                 C->data.recursion= 2;
320                 if(C->wm.region->type && C->wm.region->type->context)
321                         done= C->wm.region->type->context(C, member, result);
322         }
323         if(!done && recursion < 3 && C->wm.area) {
324                 C->data.recursion= 3;
325                 if(C->wm.area->type && C->wm.area->type->context)
326                         done= C->wm.area->type->context(C, member, result);
327         }
328         if(!done && recursion < 4 && C->wm.screen) {
329                 bContextDataCallback cb= C->wm.screen->context;
330                 C->data.recursion= 4;
331                 if(cb)
332                         done= cb(C, member, result);
333         }
334
335         C->data.recursion= recursion;
336
337         return done;
338 }
339
340 static void *ctx_data_pointer_get(const bContext *C, const char *member)
341 {
342         bContextDataResult result;
343
344         if(ctx_data_get((bContext*)C, member, &result))
345                 return result.ptr.data;
346
347         return NULL;
348 }
349
350 static int ctx_data_pointer_verify(const bContext *C, const char *member, void **pointer)
351 {
352         bContextDataResult result;
353
354         if(ctx_data_get((bContext*)C, member, &result)) {
355                 *pointer= result.ptr.data;
356                 return 1;
357         }
358         else {
359                 *pointer= NULL;
360                 return 0;
361         }
362 }
363
364 static int ctx_data_collection_get(const bContext *C, const char *member, ListBase *list)
365 {
366         bContextDataResult result;
367
368         if(ctx_data_get((bContext*)C, member, &result)) {
369                 *list= result.list;
370                 return 1;
371         }
372
373         list->first= NULL;
374         list->last= NULL;
375
376         return 0;
377 }
378
379 PointerRNA CTX_data_pointer_get(const bContext *C, const char *member)
380 {
381         bContextDataResult result;
382
383         if(ctx_data_get((bContext*)C, member, &result))
384                 return result.ptr;
385         else
386                 return PointerRNA_NULL;
387 }
388
389 PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type)
390 {
391         PointerRNA ptr = CTX_data_pointer_get(C, member);
392
393         if(ptr.data && RNA_struct_is_a(ptr.type, type))
394                 return ptr;
395         
396         return PointerRNA_NULL;
397 }
398
399 ListBase CTX_data_collection_get(const bContext *C, const char *member)
400 {
401         bContextDataResult result;
402
403         if(ctx_data_get((bContext*)C, member, &result)) {
404                 return result.list;
405         }
406         else {
407                 ListBase list;
408                 memset(&list, 0, sizeof(list));
409                 return list;
410         }
411 }
412
413 void CTX_data_get(const bContext *C, const char *member, PointerRNA *r_ptr, ListBase *r_lb)
414 {
415         bContextDataResult result;
416
417         if(ctx_data_get((bContext*)C, member, &result)) {
418                 *r_ptr= result.ptr;
419                 *r_lb= result.list;
420         }
421         else {
422                 memset(r_ptr, 0, sizeof(*r_ptr));
423                 memset(r_lb, 0, sizeof(*r_lb));
424         }
425 }
426
427 static void data_dir_add(ListBase *lb, const char *member)
428 {
429         LinkData *link;
430
431         if(strcmp(member, "scene") == 0) /* exception */
432                 return;
433
434         for(link=lb->first; link; link=link->next)
435                 if(strcmp(link->data, member) == 0)
436                         return;
437         
438         link= MEM_callocN(sizeof(LinkData), "LinkData");
439         link->data= (void*)member;
440         BLI_addtail(lb, link);
441 }
442
443 ListBase CTX_data_dir_get(const bContext *C)
444 {
445         bContextDataResult result;
446         ListBase lb;
447         int a;
448
449         memset(&lb, 0, sizeof(lb));
450
451         if(C->wm.store) {
452                 bContextStoreEntry *entry;
453
454                 for(entry=C->wm.store->entries.first; entry; entry=entry->next)
455                         data_dir_add(&lb, entry->name);
456         }
457         if(C->wm.region && C->wm.region->type && C->wm.region->type->context) {
458                 memset(&result, 0, sizeof(result));
459                 C->wm.region->type->context(C, "", &result);
460
461                 if(result.dir)
462                         for(a=0; result.dir[a]; a++)
463                                 data_dir_add(&lb, result.dir[a]);
464         }
465         if(C->wm.area && C->wm.area->type && C->wm.area->type->context) {
466                 memset(&result, 0, sizeof(result));
467                 C->wm.area->type->context(C, "", &result);
468
469                 if(result.dir)
470                         for(a=0; result.dir[a]; a++)
471                                 data_dir_add(&lb, result.dir[a]);
472         }
473         if(C->wm.screen && C->wm.screen->context) {
474                 bContextDataCallback cb= C->wm.screen->context;
475                 memset(&result, 0, sizeof(result));
476                 cb(C, "", &result);
477
478                 if(result.dir)
479                         for(a=0; result.dir[a]; a++)
480                                 data_dir_add(&lb, result.dir[a]);
481         }
482
483         return lb;
484 }
485
486 int CTX_data_equals(const char *member, const char *str)
487 {
488         return (strcmp(member, str) == 0);
489 }
490
491 int CTX_data_dir(const char *member)
492 {
493         return (strcmp(member, "") == 0);
494 }
495
496 void CTX_data_id_pointer_set(bContextDataResult *result, ID *id)
497 {
498         RNA_id_pointer_create(id, &result->ptr);
499 }
500
501 void CTX_data_pointer_set(bContextDataResult *result, ID *id, StructRNA *type, void *data)
502 {
503         RNA_pointer_create(id, type, data, &result->ptr);
504 }
505
506 void CTX_data_id_list_add(bContextDataResult *result, ID *id)
507 {
508         CollectionPointerLink *link;
509
510         link= MEM_callocN(sizeof(CollectionPointerLink), "CTX_data_id_list_add");
511         RNA_id_pointer_create(id, &link->ptr);
512
513         BLI_addtail(&result->list, link);
514 }
515
516 void CTX_data_list_add(bContextDataResult *result, ID *id, StructRNA *type, void *data)
517 {
518         CollectionPointerLink *link;
519
520         link= MEM_callocN(sizeof(CollectionPointerLink), "CTX_data_list_add");
521         RNA_pointer_create(id, type, data, &link->ptr);
522
523         BLI_addtail(&result->list, link);
524 }
525
526 int ctx_data_list_count(const bContext *C, int (*func)(const bContext*, ListBase*))
527 {
528         ListBase list;
529
530         if(func(C, &list)) {
531                 int tot= BLI_countlist(&list);
532                 BLI_freelistN(&list);
533                 return tot;
534         }
535         else
536                 return 0;
537 }
538
539 void CTX_data_dir_set(bContextDataResult *result, const char **dir)
540 {
541         result->dir= dir;
542 }
543
544 /* data context */
545
546 Main *CTX_data_main(const bContext *C)
547 {
548         Main *bmain;
549
550         if(ctx_data_pointer_verify(C, "main", (void*)&bmain))
551                 return bmain;
552         else
553                 return C->data.main;
554 }
555
556 void CTX_data_main_set(bContext *C, Main *bmain)
557 {
558         C->data.main= bmain;
559 }
560
561 Scene *CTX_data_scene(const bContext *C)
562 {
563         Scene *scene;
564
565         if(ctx_data_pointer_verify(C, "scene", (void*)&scene))
566                 return scene;
567         else
568                 return C->data.scene;
569 }
570
571 void CTX_data_scene_set(bContext *C, Scene *scene)
572 {
573         C->data.scene= scene;
574 }
575
576 ToolSettings *CTX_data_tool_settings(const bContext *C)
577 {
578         Scene *scene = CTX_data_scene(C);
579
580         if(scene)
581                 return scene->toolsettings;
582         else
583                 return NULL;
584 }
585
586 int CTX_data_selected_nodes(const bContext *C, ListBase *list)
587 {
588         return ctx_data_collection_get(C, "selected_nodes", list);
589 }
590
591 int CTX_data_selected_editable_objects(const bContext *C, ListBase *list)
592 {
593         return ctx_data_collection_get(C, "selected_editable_objects", list);
594 }
595
596 int CTX_data_selected_editable_bases(const bContext *C, ListBase *list)
597 {
598         return ctx_data_collection_get(C, "selected_editable_bases", list);
599 }
600
601 int CTX_data_selected_objects(const bContext *C, ListBase *list)
602 {
603         return ctx_data_collection_get(C, "selected_objects", list);
604 }
605
606 int CTX_data_selected_bases(const bContext *C, ListBase *list)
607 {
608         return ctx_data_collection_get(C, "selected_bases", list);
609 }
610
611 int CTX_data_visible_objects(const bContext *C, ListBase *list)
612 {
613         return ctx_data_collection_get(C, "visible_objects", list);
614 }
615
616 int CTX_data_visible_bases(const bContext *C, ListBase *list)
617 {
618         return ctx_data_collection_get(C, "visible_bases", list);
619 }
620
621 int CTX_data_selectable_objects(const bContext *C, ListBase *list)
622 {
623         return ctx_data_collection_get(C, "selectable_objects", list);
624 }
625
626 int CTX_data_selectable_bases(const bContext *C, ListBase *list)
627 {
628         return ctx_data_collection_get(C, "selectable_bases", list);
629 }
630
631 struct Object *CTX_data_active_object(const bContext *C)
632 {
633         return ctx_data_pointer_get(C, "active_object");
634 }
635
636 struct Base *CTX_data_active_base(const bContext *C)
637 {
638         return ctx_data_pointer_get(C, "active_base");
639 }
640
641 struct Object *CTX_data_edit_object(const bContext *C)
642 {
643         return ctx_data_pointer_get(C, "edit_object");
644 }
645
646 struct Image *CTX_data_edit_image(const bContext *C)
647 {
648         return ctx_data_pointer_get(C, "edit_image");
649 }
650
651 struct Text *CTX_data_edit_text(const bContext *C)
652 {
653         return ctx_data_pointer_get(C, "edit_text");
654 }
655
656 struct EditBone *CTX_data_active_bone(const bContext *C)
657 {
658         return ctx_data_pointer_get(C, "active_bone");
659 }
660
661 int CTX_data_selected_bones(const bContext *C, ListBase *list)
662 {
663         return ctx_data_collection_get(C, "selected_bones", list);
664 }
665
666 int CTX_data_selected_editable_bones(const bContext *C, ListBase *list)
667 {
668         return ctx_data_collection_get(C, "selected_editable_bones", list);
669 }
670
671 int CTX_data_visible_bones(const bContext *C, ListBase *list)
672 {
673         return ctx_data_collection_get(C, "visible_bones", list);
674 }
675
676 int CTX_data_editable_bones(const bContext *C, ListBase *list)
677 {
678         return ctx_data_collection_get(C, "editable_bones", list);
679 }
680
681 struct bPoseChannel *CTX_data_active_pchan(const bContext *C)
682 {
683         return ctx_data_pointer_get(C, "active_pchan");
684 }
685
686 int CTX_data_selected_pchans(const bContext *C, ListBase *list)
687 {
688         return ctx_data_collection_get(C, "selected_pchans", list);
689 }
690
691 int CTX_data_visible_pchans(const bContext *C, ListBase *list)
692 {
693         return ctx_data_collection_get(C, "visible_pchans", list);
694 }
695