90880e354ec0cffd49139bded76e5bc899f4f71b
[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         return 0;
362 }
363
364 PointerRNA CTX_data_pointer_get(const bContext *C, const char *member)
365 {
366         bContextDataResult result;
367
368         if(ctx_data_get((bContext*)C, member, &result))
369                 return result.ptr;
370         else
371                 return PointerRNA_NULL;
372 }
373
374 PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type)
375 {
376         PointerRNA ptr = CTX_data_pointer_get(C, member);
377
378         if(ptr.data && ptr.type == type)
379                 return ptr;
380         
381         return PointerRNA_NULL;
382 }
383
384 ListBase CTX_data_collection_get(const bContext *C, const char *member)
385 {
386         bContextDataResult result;
387
388         if(ctx_data_get((bContext*)C, member, &result)) {
389                 return result.list;
390         }
391         else {
392                 ListBase list;
393                 memset(&list, 0, sizeof(list));
394                 return list;
395         }
396 }
397
398 void CTX_data_get(const bContext *C, const char *member, PointerRNA *r_ptr, ListBase *r_lb)
399 {
400         bContextDataResult result;
401
402         if(ctx_data_get((bContext*)C, member, &result)) {
403                 *r_ptr= result.ptr;
404                 *r_lb= result.list;
405         }
406         else {
407                 memset(r_ptr, 0, sizeof(*r_ptr));
408                 memset(r_lb, 0, sizeof(*r_lb));
409         }
410 }
411
412 static void data_dir_add(ListBase *lb, const char *member)
413 {
414         LinkData *link;
415
416         if(strcmp(member, "scene") == 0) /* exception */
417                 return;
418
419         for(link=lb->first; link; link=link->next)
420                 if(strcmp(link->data, member) == 0)
421                         return;
422         
423         link= MEM_callocN(sizeof(LinkData), "LinkData");
424         link->data= (void*)member;
425         BLI_addtail(lb, link);
426 }
427
428 ListBase CTX_data_dir_get(const bContext *C)
429 {
430         bContextDataResult result;
431         ListBase lb;
432         int a;
433
434         memset(&lb, 0, sizeof(lb));
435
436         if(C->wm.store) {
437                 bContextStoreEntry *entry;
438
439                 for(entry=C->wm.store->entries.first; entry; entry=entry->next)
440                         data_dir_add(&lb, entry->name);
441         }
442         if(C->wm.region && C->wm.region->type && C->wm.region->type->context) {
443                 memset(&result, 0, sizeof(result));
444                 C->wm.region->type->context(C, "", &result);
445
446                 if(result.dir)
447                         for(a=0; result.dir[a]; a++)
448                                 data_dir_add(&lb, result.dir[a]);
449         }
450         if(C->wm.area && C->wm.area->type && C->wm.area->type->context) {
451                 memset(&result, 0, sizeof(result));
452                 C->wm.area->type->context(C, "", &result);
453
454                 if(result.dir)
455                         for(a=0; result.dir[a]; a++)
456                                 data_dir_add(&lb, result.dir[a]);
457         }
458         if(C->wm.screen && C->wm.screen->context) {
459                 bContextDataCallback cb= C->wm.screen->context;
460                 memset(&result, 0, sizeof(result));
461                 cb(C, "", &result);
462
463                 if(result.dir)
464                         for(a=0; result.dir[a]; a++)
465                                 data_dir_add(&lb, result.dir[a]);
466         }
467
468         return lb;
469 }
470
471 int CTX_data_equals(const char *member, const char *str)
472 {
473         return (strcmp(member, str) == 0);
474 }
475
476 int CTX_data_dir(const char *member)
477 {
478         return (strcmp(member, "") == 0);
479 }
480
481 void CTX_data_id_pointer_set(bContextDataResult *result, ID *id)
482 {
483         RNA_id_pointer_create(id, &result->ptr);
484 }
485
486 void CTX_data_pointer_set(bContextDataResult *result, ID *id, StructRNA *type, void *data)
487 {
488         RNA_pointer_create(id, type, data, &result->ptr);
489 }
490
491 void CTX_data_id_list_add(bContextDataResult *result, ID *id)
492 {
493         CollectionPointerLink *link;
494
495         link= MEM_callocN(sizeof(CollectionPointerLink), "CTX_data_id_list_add");
496         RNA_id_pointer_create(id, &link->ptr);
497
498         BLI_addtail(&result->list, link);
499 }
500
501 void CTX_data_list_add(bContextDataResult *result, ID *id, StructRNA *type, void *data)
502 {
503         CollectionPointerLink *link;
504
505         link= MEM_callocN(sizeof(CollectionPointerLink), "CTX_data_list_add");
506         RNA_pointer_create(id, type, data, &link->ptr);
507
508         BLI_addtail(&result->list, link);
509 }
510
511 int ctx_data_list_count(const bContext *C, int (*func)(const bContext*, ListBase*))
512 {
513         ListBase list;
514
515         if(func(C, &list)) {
516                 int tot= BLI_countlist(&list);
517                 BLI_freelistN(&list);
518                 return tot;
519         }
520         else
521                 return 0;
522 }
523
524 void CTX_data_dir_set(bContextDataResult *result, const char **dir)
525 {
526         result->dir= dir;
527 }
528
529 /* data context */
530
531 Main *CTX_data_main(const bContext *C)
532 {
533         Main *bmain;
534
535         if(ctx_data_pointer_verify(C, "main", (void*)&bmain))
536                 return bmain;
537         else
538                 return C->data.main;
539 }
540
541 void CTX_data_main_set(bContext *C, Main *bmain)
542 {
543         C->data.main= bmain;
544 }
545
546 Scene *CTX_data_scene(const bContext *C)
547 {
548         Scene *scene;
549
550         if(ctx_data_pointer_verify(C, "scene", (void*)&scene))
551                 return scene;
552         else
553                 return C->data.scene;
554 }
555
556 void CTX_data_scene_set(bContext *C, Scene *scene)
557 {
558         C->data.scene= scene;
559 }
560
561 ToolSettings *CTX_data_tool_settings(const bContext *C)
562 {
563         Scene *scene = CTX_data_scene(C);
564
565         if(scene)
566                 return scene->toolsettings;
567         else
568                 return NULL;
569 }
570
571 int CTX_data_selected_nodes(const bContext *C, ListBase *list)
572 {
573         return ctx_data_collection_get(C, "selected_nodes", list);
574 }
575
576 int CTX_data_selected_editable_objects(const bContext *C, ListBase *list)
577 {
578         return ctx_data_collection_get(C, "selected_editable_objects", list);
579 }
580
581 int CTX_data_selected_editable_bases(const bContext *C, ListBase *list)
582 {
583         return ctx_data_collection_get(C, "selected_editable_bases", list);
584 }
585
586 int CTX_data_selected_objects(const bContext *C, ListBase *list)
587 {
588         return ctx_data_collection_get(C, "selected_objects", list);
589 }
590
591 int CTX_data_selected_bases(const bContext *C, ListBase *list)
592 {
593         return ctx_data_collection_get(C, "selected_bases", list);
594 }
595
596 int CTX_data_visible_objects(const bContext *C, ListBase *list)
597 {
598         return ctx_data_collection_get(C, "visible_objects", list);
599 }
600
601 int CTX_data_visible_bases(const bContext *C, ListBase *list)
602 {
603         return ctx_data_collection_get(C, "visible_bases", list);
604 }
605
606 struct Object *CTX_data_active_object(const bContext *C)
607 {
608         return ctx_data_pointer_get(C, "active_object");
609 }
610
611 struct Base *CTX_data_active_base(const bContext *C)
612 {
613         return ctx_data_pointer_get(C, "active_base");
614 }
615
616 struct Object *CTX_data_edit_object(const bContext *C)
617 {
618         return ctx_data_pointer_get(C, "edit_object");
619 }
620
621 struct Image *CTX_data_edit_image(const bContext *C)
622 {
623         return ctx_data_pointer_get(C, "edit_image");
624 }
625
626 struct Text *CTX_data_edit_text(const bContext *C)
627 {
628         return ctx_data_pointer_get(C, "edit_text");
629 }
630
631 struct EditBone *CTX_data_active_bone(const bContext *C)
632 {
633         return ctx_data_pointer_get(C, "active_bone");
634 }
635
636 int CTX_data_selected_bones(const bContext *C, ListBase *list)
637 {
638         return ctx_data_collection_get(C, "selected_bones", list);
639 }
640
641 int CTX_data_selected_editable_bones(const bContext *C, ListBase *list)
642 {
643         return ctx_data_collection_get(C, "selected_editable_bones", list);
644 }
645
646 int CTX_data_visible_bones(const bContext *C, ListBase *list)
647 {
648         return ctx_data_collection_get(C, "visible_bones", list);
649 }
650
651 int CTX_data_editable_bones(const bContext *C, ListBase *list)
652 {
653         return ctx_data_collection_get(C, "editable_bones", list);
654 }
655
656 struct bPoseChannel *CTX_data_active_pchan(const bContext *C)
657 {
658         return ctx_data_pointer_get(C, "active_pchan");
659 }
660
661 int CTX_data_selected_pchans(const bContext *C, ListBase *list)
662 {
663         return ctx_data_collection_get(C, "selected_pchans", list);
664 }
665
666 int CTX_data_visible_pchans(const bContext *C, ListBase *list)
667 {
668         return ctx_data_collection_get(C, "visible_pchans", list);
669 }
670