d075958ffef303e25ff9ad8d318ac2e5c3bdc1b0
[blender-staging.git] / source / blender / editors / space_buttons / buttons_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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2009 Blender Foundation.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "BLI_listbase.h"
34 #include "BLI_utildefines.h"
35
36 #include "DNA_armature_types.h"
37 #include "DNA_lamp_types.h"
38 #include "DNA_material_types.h"
39 #include "DNA_node_types.h"
40 #include "DNA_scene_types.h"
41 #include "DNA_world_types.h"
42 #include "DNA_brush_types.h"
43
44 #include "BKE_context.h"
45 #include "BKE_action.h"
46 #include "BKE_material.h"
47 #include "BKE_modifier.h"
48 #include "BKE_paint.h"
49 #include "BKE_particle.h"
50 #include "BKE_screen.h"
51 #include "BKE_texture.h"
52
53
54 #include "RNA_access.h"
55
56 #include "ED_armature.h"
57 #include "ED_screen.h"
58 #include "ED_physics.h"
59
60 #include "UI_interface.h"
61 #include "UI_resources.h"
62
63 #include "buttons_intern.h"     // own include
64
65 typedef struct ButsContextPath {
66         PointerRNA ptr[8];
67         int len;
68         int flag;
69         int tex_ctx;
70 } ButsContextPath;
71
72 static int set_pointer_type(ButsContextPath *path, bContextDataResult *result, StructRNA *type)
73 {
74         PointerRNA *ptr;
75         int a;
76
77         for(a=0; a<path->len; a++) {
78                 ptr= &path->ptr[a];
79
80                 if(RNA_struct_is_a(ptr->type, type)) {
81                         CTX_data_pointer_set(result, ptr->id.data, ptr->type, ptr->data);
82                         return 1;
83                 }
84         }
85
86         return 0;
87 }
88
89 static PointerRNA *get_pointer_type(ButsContextPath *path, StructRNA *type)
90 {
91         PointerRNA *ptr;
92         int a;
93
94         for(a=0; a<path->len; a++) {
95                 ptr= &path->ptr[a];
96
97                 if(RNA_struct_is_a(ptr->type, type))
98                         return ptr;
99         }
100
101         return NULL;
102 }
103
104 /************************* Creating the Path ************************/
105
106 static int buttons_context_path_scene(ButsContextPath *path)
107 {
108         PointerRNA *ptr= &path->ptr[path->len-1];
109
110         /* this one just verifies */
111         return RNA_struct_is_a(ptr->type, &RNA_Scene);
112 }
113
114 /* note: this function can return 1 without adding a world to the path
115  * so the buttons stay visible, but be sure to check the ID type if a ID_WO */
116 static int buttons_context_path_world(ButsContextPath *path)
117 {
118         Scene *scene;
119         World *world;
120         PointerRNA *ptr= &path->ptr[path->len-1];
121
122         /* if we already have a (pinned) world, we're done */
123         if(RNA_struct_is_a(ptr->type, &RNA_World)) {
124                 return 1;
125         }
126         /* if we have a scene, use the scene's world */
127         else if(buttons_context_path_scene(path)) {
128                 scene= path->ptr[path->len-1].data;
129                 world= scene->world;
130                 
131                 if(world) {
132                         RNA_id_pointer_create(&scene->world->id, &path->ptr[path->len]);
133                         path->len++;
134                         return 1;
135                 }
136                 else {
137                         return 1;
138                 }
139         }
140
141         /* no path to a world possible */
142         return 0;
143 }
144
145
146 static int buttons_context_path_object(ButsContextPath *path)
147 {
148         Scene *scene;
149         Object *ob;
150         PointerRNA *ptr= &path->ptr[path->len-1];
151
152         /* if we already have a (pinned) object, we're done */
153         if(RNA_struct_is_a(ptr->type, &RNA_Object)) {
154                 return 1;
155         }
156         /* if we have a scene, use the scene's active object */
157         else if(buttons_context_path_scene(path)) {
158                 scene= path->ptr[path->len-1].data;
159                 ob= (scene->basact)? scene->basact->object: NULL;
160
161                 if(ob) {
162                         RNA_id_pointer_create(&ob->id, &path->ptr[path->len]);
163                         path->len++;
164
165                         return 1;
166                 }
167         }
168
169         /* no path to a object possible */
170         return 0;
171 }
172
173 static int buttons_context_path_data(ButsContextPath *path, int type)
174 {
175         Object *ob;
176         PointerRNA *ptr= &path->ptr[path->len-1];
177
178         /* if we already have a data, we're done */
179         if(RNA_struct_is_a(ptr->type, &RNA_Mesh) && (type == -1 || type == OB_MESH)) return 1;
180         else if(RNA_struct_is_a(ptr->type, &RNA_Curve) && (type == -1 || ELEM3(type, OB_CURVE, OB_SURF, OB_FONT))) return 1;
181         else if(RNA_struct_is_a(ptr->type, &RNA_Armature) && (type == -1 || type == OB_ARMATURE)) return 1;
182         else if(RNA_struct_is_a(ptr->type, &RNA_MetaBall) && (type == -1 || type == OB_MBALL)) return 1;
183         else if(RNA_struct_is_a(ptr->type, &RNA_Lattice) && (type == -1 || type == OB_LATTICE)) return 1;
184         else if(RNA_struct_is_a(ptr->type, &RNA_Camera) && (type == -1 || type == OB_CAMERA)) return 1;
185         else if(RNA_struct_is_a(ptr->type, &RNA_Lamp) && (type == -1 || type == OB_LAMP)) return 1;
186         /* try to get an object in the path, no pinning supported here */
187         else if(buttons_context_path_object(path)) {
188                 ob= path->ptr[path->len-1].data;
189
190                 if(ob && (type == -1 || type == ob->type)) {
191                         RNA_id_pointer_create(ob->data, &path->ptr[path->len]);
192                         path->len++;
193
194                         return 1;
195                 }
196         }
197
198         /* no path to data possible */
199         return 0;
200 }
201
202 static int buttons_context_path_modifier(ButsContextPath *path)
203 {
204         Object *ob;
205
206         if(buttons_context_path_object(path)) {
207                 ob= path->ptr[path->len-1].data;
208
209                 if(ob && ELEM5(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_LATTICE))
210                         return 1;
211         }
212
213         return 0;
214 }
215
216 static int buttons_context_path_material(ButsContextPath *path)
217 {
218         Object *ob;
219         PointerRNA *ptr= &path->ptr[path->len-1];
220         Material *ma;
221
222         /* if we already have a (pinned) material, we're done */
223         if(RNA_struct_is_a(ptr->type, &RNA_Material)) {
224                 return 1;
225         }
226         /* if we have an object, use the object material slot */
227         else if(buttons_context_path_object(path)) {
228                 ob= path->ptr[path->len-1].data;
229
230                 if(ob && ob->type && (ob->type<OB_LAMP)) {
231                         ma= give_current_material(ob, ob->actcol);
232                         RNA_id_pointer_create(&ma->id, &path->ptr[path->len]);
233                         path->len++;
234                         return 1;
235                 }
236         }
237
238         /* no path to a material possible */
239         return 0;
240 }
241
242 static int buttons_context_path_bone(ButsContextPath *path)
243 {
244         bArmature *arm;
245         EditBone *edbo;
246
247         /* if we have an armature, get the active bone */
248         if(buttons_context_path_data(path, OB_ARMATURE)) {
249                 arm= path->ptr[path->len-1].data;
250
251                 if(arm->edbo) {
252                         if(arm->act_edbone) {
253                                 edbo= arm->act_edbone;
254                                 RNA_pointer_create(&arm->id, &RNA_EditBone, edbo, &path->ptr[path->len]);
255                                 path->len++;
256                                 return 1;
257                         }
258                 }
259                 else {
260                         if(arm->act_bone) {
261                                 RNA_pointer_create(&arm->id, &RNA_Bone, arm->act_bone, &path->ptr[path->len]);
262                                 path->len++;
263                                 return 1;
264                         }
265                 }
266         }
267
268         /* no path to a bone possible */
269         return 0;
270 }
271
272 static int buttons_context_path_pose_bone(ButsContextPath *path)
273 {
274         PointerRNA *ptr= &path->ptr[path->len-1];
275
276         /* if we already have a (pinned) PoseBone, we're done */
277         if(RNA_struct_is_a(ptr->type, &RNA_PoseBone)) {
278                 return 1;
279         }
280
281         /* if we have an armature, get the active bone */
282         if(buttons_context_path_object(path)) {
283                 Object *ob= path->ptr[path->len-1].data;
284                 bArmature *arm= ob->data; /* path->ptr[path->len-1].data - works too */
285
286                 if(ob->type != OB_ARMATURE || arm->edbo) {
287                         return 0;
288                 }
289                 else {
290                         if(arm->act_bone) {
291                                 bPoseChannel *pchan= get_pose_channel(ob->pose, arm->act_bone->name);
292                                 if(pchan) {
293                                         RNA_pointer_create(&ob->id, &RNA_PoseBone, pchan, &path->ptr[path->len]);
294                                         path->len++;
295                                         return 1;
296                                 }
297                         }
298                 }
299         }
300
301         /* no path to a bone possible */
302         return 0;
303 }
304
305
306 static int buttons_context_path_particle(ButsContextPath *path)
307 {
308         Object *ob;
309         ParticleSystem *psys;
310
311         /* if we have an object, get the active particle system */
312         if(buttons_context_path_object(path)) {
313                 ob= path->ptr[path->len-1].data;
314
315                 if(ob && ob->type == OB_MESH) {
316                         psys= psys_get_current(ob);
317
318                         RNA_pointer_create(&ob->id, &RNA_ParticleSystem, psys, &path->ptr[path->len]);
319                         path->len++;
320                         return 1;
321                 }
322         }
323
324         /* no path to a particle system possible */
325         return 0;
326 }
327
328 static int buttons_context_path_brush(ButsContextPath *path)
329 {
330         Scene *scene;
331         Brush *br= NULL;
332         PointerRNA *ptr= &path->ptr[path->len-1];
333
334         /* if we already have a (pinned) brush, we're done */
335         if(RNA_struct_is_a(ptr->type, &RNA_Brush)) {
336                 return 1;
337         }
338         /* if we have a scene, use the toolsettings brushes */
339         else if(buttons_context_path_scene(path)) {
340                 scene= path->ptr[path->len-1].data;
341
342                 if(scene)
343                         br= paint_brush(paint_get_active(scene));
344
345                 if(br) {
346                         RNA_id_pointer_create((ID *)br, &path->ptr[path->len]);
347                         path->len++;
348
349                         return 1;
350                 }
351         }
352
353         /* no path to a brush possible */
354         return 0;
355 }
356
357 static int buttons_context_path_texture(ButsContextPath *path)
358 {
359         Material *ma;
360         Lamp *la;
361         Brush *br;
362         World *wo;
363         Tex *tex;
364         PointerRNA *ptr= &path->ptr[path->len-1];
365         int orig_len = path->len;
366
367         /* if we already have a (pinned) texture, we're done */
368         if(RNA_struct_is_a(ptr->type, &RNA_Texture)) {
369                 return 1;
370         }
371         /* try brush */
372         if((path->tex_ctx == SB_TEXC_BRUSH) && buttons_context_path_brush(path)) {
373                 br= path->ptr[path->len-1].data;
374                 
375                 if(br) {
376                         tex= give_current_brush_texture(br);
377
378                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
379                         path->len++;
380                         return 1;
381                 }
382         }
383         /* try world */
384         if((path->tex_ctx == SB_TEXC_WORLD) && buttons_context_path_world(path)) {
385                 wo= path->ptr[path->len-1].data;
386
387                 if(wo && GS(wo->id.name)==ID_WO) {
388                         tex= give_current_world_texture(wo);
389
390                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
391                         path->len++;
392                         return 1;
393                 }
394         }
395         /* try material */
396         if(buttons_context_path_material(path)) {
397                 ma= path->ptr[path->len-1].data;
398
399                 if(ma) {
400                         tex= give_current_material_texture(ma);
401
402                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
403                         path->len++;
404                         return 1;
405                 }
406         }
407         /* try lamp */
408         if(buttons_context_path_data(path, OB_LAMP)) {
409                 la= path->ptr[path->len-1].data;
410
411                 if(la) {
412                         tex= give_current_lamp_texture(la);
413
414                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
415                         path->len++;
416                         return 1;
417                 }
418         }
419         /* try brushes again in case of no material, lamp, etc */
420         path->len = orig_len;
421         if(buttons_context_path_brush(path)) {
422                 br= path->ptr[path->len-1].data;
423                 
424                 if(br) {
425                         tex= give_current_brush_texture(br);
426                         
427                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
428                         path->len++;
429                         return 1;
430                 }
431         }
432
433         /* no path to a texture possible */
434         return 0;
435 }
436
437
438 static int buttons_context_path(const bContext *C, ButsContextPath *path, int mainb, int flag)
439 {
440         SpaceButs *sbuts= CTX_wm_space_buts(C);
441         ID *id;
442         int found;
443
444         memset(path, 0, sizeof(*path));
445         path->flag= flag;
446         path->tex_ctx = sbuts->texture_context;
447
448         /* if some ID datablock is pinned, set the root pointer */
449         if(sbuts->pinid) {
450                 id= sbuts->pinid;
451
452                 RNA_id_pointer_create(id, &path->ptr[0]);
453                 path->len++;
454         }
455
456         /* no pinned root, use scene as root */
457         if(path->len == 0) {
458                 id= (ID*)CTX_data_scene(C);
459                 RNA_id_pointer_create(id, &path->ptr[0]);
460                 path->len++;
461         }
462
463         /* now for each buttons context type, we try to construct a path,
464          * tracing back recursively */
465         switch(mainb) {
466                 case BCONTEXT_SCENE:
467                 case BCONTEXT_RENDER:
468                         found= buttons_context_path_scene(path);
469                         break;
470                 case BCONTEXT_WORLD:
471                         found= buttons_context_path_world(path);
472                         break;
473                 case BCONTEXT_OBJECT:
474                 case BCONTEXT_PHYSICS:
475                 case BCONTEXT_CONSTRAINT:
476                         found= buttons_context_path_object(path);
477                         break;
478                 case BCONTEXT_MODIFIER:
479                         found= buttons_context_path_modifier(path);
480                         break;
481                 case BCONTEXT_DATA:
482                         found= buttons_context_path_data(path, -1);
483                         break;
484                 case BCONTEXT_PARTICLE:
485                         found= buttons_context_path_particle(path);
486                         break;
487                 case BCONTEXT_MATERIAL:
488                         found= buttons_context_path_material(path);
489                         break;
490                 case BCONTEXT_TEXTURE:
491                         found= buttons_context_path_texture(path);
492                         break;
493                 case BCONTEXT_BONE:
494                         found= buttons_context_path_bone(path);
495                         if(!found)
496                                 found= buttons_context_path_data(path, OB_ARMATURE);
497                         break;
498                 case BCONTEXT_BONE_CONSTRAINT:
499                         found= buttons_context_path_pose_bone(path);
500                         break;
501                 default:
502                         found= 0;
503                         break;
504         }
505
506         return found;
507 }
508
509 static int buttons_shading_context(const bContext *C, int mainb)
510 {
511         Object *ob= CTX_data_active_object(C);
512
513         if(ELEM3(mainb, BCONTEXT_MATERIAL, BCONTEXT_WORLD, BCONTEXT_TEXTURE))
514                 return 1;
515         if(mainb == BCONTEXT_DATA && ob && ELEM(ob->type, OB_LAMP, OB_CAMERA))
516                 return 1;
517         
518         return 0;
519 }
520
521 static int buttons_shading_new_context(const bContext *C, int flag)
522 {
523         Object *ob= CTX_data_active_object(C);
524
525         if(flag & (1 << BCONTEXT_MATERIAL))
526                 return BCONTEXT_MATERIAL;
527         else if(ob && ELEM(ob->type, OB_LAMP, OB_CAMERA) && (flag & (1 << BCONTEXT_DATA)))
528                 return BCONTEXT_DATA;
529         else if(flag & (1 << BCONTEXT_WORLD))
530                 return BCONTEXT_WORLD;
531         
532         return BCONTEXT_RENDER;
533 }
534
535 void buttons_context_compute(const bContext *C, SpaceButs *sbuts)
536 {
537         ButsContextPath *path;
538         PointerRNA *ptr;
539         int a, pflag= 0, flag= 0;
540
541         if(!sbuts->path)
542                 sbuts->path= MEM_callocN(sizeof(ButsContextPath), "ButsContextPath");
543         
544         path= sbuts->path;
545         
546         /* for each context, see if we can compute a valid path to it, if
547          * this is the case, we know we have to display the button */
548         for(a=0; a<BCONTEXT_TOT; a++) {
549                 if(buttons_context_path(C, path, a, pflag)) {
550                         flag |= (1<<a);
551
552                         /* setting icon for data context */
553                         if(a == BCONTEXT_DATA) {
554                                 ptr= &path->ptr[path->len-1];
555
556                                 if(ptr->type)
557                                         sbuts->dataicon= RNA_struct_ui_icon(ptr->type);
558                                 else
559                                         sbuts->dataicon= ICON_EMPTY_DATA;
560                         }
561                 }
562         }
563
564         /* always try to use the tab that was explicitly
565          * set to the user, so that once that context comes
566          * back, the tab is activated again */
567         sbuts->mainb= sbuts->mainbuser;
568
569         /* in case something becomes invalid, change */
570         if((flag & (1 << sbuts->mainb)) == 0) {
571                 if(sbuts->flag & SB_SHADING_CONTEXT) {
572                         /* try to keep showing shading related buttons */
573                         sbuts->mainb= buttons_shading_new_context(C, flag);
574                 }
575                 else if(flag & BCONTEXT_OBJECT) {
576                         sbuts->mainb= BCONTEXT_OBJECT;
577                 }
578                 else {
579                         for(a=0; a<BCONTEXT_TOT; a++) {
580                                 if(flag & (1 << a)) {
581                                         sbuts->mainb= a;
582                                         break;
583                                 }
584                         }
585                 }
586         }
587
588         buttons_context_path(C, path, sbuts->mainb, pflag);
589
590         if(!(flag & (1 << sbuts->mainb))) {
591                 if(flag & (1 << BCONTEXT_OBJECT))
592                         sbuts->mainb= BCONTEXT_OBJECT;
593                 else
594                         sbuts->mainb= BCONTEXT_SCENE;
595         }
596
597         if(buttons_shading_context(C, sbuts->mainb))
598                 sbuts->flag |= SB_SHADING_CONTEXT;
599         else
600                 sbuts->flag &= ~SB_SHADING_CONTEXT;
601
602         sbuts->pathflag= flag;
603 }
604
605 /************************* Context Callback ************************/
606
607 int buttons_context(const bContext *C, const char *member, bContextDataResult *result)
608 {
609         SpaceButs *sbuts= CTX_wm_space_buts(C);
610         ButsContextPath *path= sbuts?sbuts->path:NULL;
611
612         if(!path)
613                 return 0;
614
615         /* here we handle context, getting data from precomputed path */
616         if(CTX_data_dir(member)) {
617                 static const char *dir[] = {
618                         "world", "object", "mesh", "armature", "lattice", "curve",
619                         "meta_ball", "lamp", "camera", "material", "material_slot",
620                         "texture", "texture_slot", "bone", "edit_bone", "pose_bone", "particle_system", "particle_system_editable",
621                         "cloth", "soft_body", "fluid", "smoke", "collision", "brush", NULL};
622
623                 CTX_data_dir_set(result, dir);
624                 return 1;
625         }
626         else if(CTX_data_equals(member, "world")) {
627                 set_pointer_type(path, result, &RNA_World);
628                 return 1;
629         }
630         else if(CTX_data_equals(member, "object")) {
631                 set_pointer_type(path, result, &RNA_Object);
632                 return 1;
633         }
634         else if(CTX_data_equals(member, "mesh")) {
635                 set_pointer_type(path, result, &RNA_Mesh);
636                 return 1;
637         }
638         else if(CTX_data_equals(member, "armature")) {
639                 set_pointer_type(path, result, &RNA_Armature);
640                 return 1;
641         }
642         else if(CTX_data_equals(member, "lattice")) {
643                 set_pointer_type(path, result, &RNA_Lattice);
644                 return 1;
645         }
646         else if(CTX_data_equals(member, "curve")) {
647                 set_pointer_type(path, result, &RNA_Curve);
648                 return 1;
649         }
650         else if(CTX_data_equals(member, "meta_ball")) {
651                 set_pointer_type(path, result, &RNA_MetaBall);
652                 return 1;
653         }
654         else if(CTX_data_equals(member, "lamp")) {
655                 set_pointer_type(path, result, &RNA_Lamp);
656                 return 1;
657         }
658         else if(CTX_data_equals(member, "camera")) {
659                 set_pointer_type(path, result, &RNA_Camera);
660                 return 1;
661         }
662         else if(CTX_data_equals(member, "material")) {
663                 set_pointer_type(path, result, &RNA_Material);
664                 return 1;
665         }
666         else if(CTX_data_equals(member, "texture")) {
667                 set_pointer_type(path, result, &RNA_Texture);
668                 return 1;
669         }
670         else if(CTX_data_equals(member, "material_slot")) {
671                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
672
673                 if(ptr) {
674                         Object *ob= ptr->data;
675
676                         if(ob && ob->type && (ob->type<OB_LAMP) && ob->totcol)
677                                 CTX_data_pointer_set(result, &ob->id, &RNA_MaterialSlot, ob->mat+ob->actcol-1);
678                 }
679
680                 return 1;
681         }
682         else if(CTX_data_equals(member, "texture_node")) {
683                 PointerRNA *ptr;
684
685                 if((ptr=get_pointer_type(path, &RNA_Material))) {
686                         Material *ma= ptr->data;
687
688                         if(ma) {
689                                 bNode *node= give_current_material_texture_node(ma);
690                                 CTX_data_pointer_set(result, &ma->id, &RNA_Node, node);
691                         }
692                 }
693
694                 return 1;
695         }
696         else if(CTX_data_equals(member, "texture_slot")) {
697                 PointerRNA *ptr;
698
699                 if((ptr=get_pointer_type(path, &RNA_Material))) {
700                         Material *ma= ptr->data;
701
702                         /* if we have a node material, get slot from material in material node */
703                         if(ma && ma->use_nodes && ma->nodetree) {
704                                 /* if there's an active texture node in the node tree,
705                                  * then that texture is in context directly, without a texture slot */
706                                 if (give_current_material_texture_node(ma))
707                                         return 0;
708                                 
709                                 ma= give_node_material(ma);
710                                 if (ma)
711                                         CTX_data_pointer_set(result, &ma->id, &RNA_MaterialTextureSlot, ma->mtex[(int)ma->texact]);
712                                 else
713                                         return 0;
714                         } else if(ma) {
715                                 CTX_data_pointer_set(result, &ma->id, &RNA_MaterialTextureSlot, ma->mtex[(int)ma->texact]);
716                         }
717                 }
718                 else if((ptr=get_pointer_type(path, &RNA_Lamp))) {
719                         Lamp *la= ptr->data;
720
721                         if(la)
722                                 CTX_data_pointer_set(result, &la->id, &RNA_LampTextureSlot, la->mtex[(int)la->texact]);
723                 }
724                 else if((ptr=get_pointer_type(path, &RNA_World))) {
725                         World *wo= ptr->data;
726
727                         if(wo)
728                                 CTX_data_pointer_set(result, &wo->id, &RNA_WorldTextureSlot, wo->mtex[(int)wo->texact]);
729                 }
730                 else if((ptr=get_pointer_type(path, &RNA_Brush))) { /* how to get this into context? */
731                         Brush *br= ptr->data;
732
733                         if(br)
734                                 CTX_data_pointer_set(result, &br->id, &RNA_BrushTextureSlot, &br->mtex);
735                 }
736
737                 return 1;
738         }
739         else if(CTX_data_equals(member, "bone")) {
740                 set_pointer_type(path, result, &RNA_Bone);
741                 return 1;
742         }
743         else if(CTX_data_equals(member, "edit_bone")) {
744                 set_pointer_type(path, result, &RNA_EditBone);
745                 return 1;
746         }
747         else if(CTX_data_equals(member, "pose_bone")) {
748                 set_pointer_type(path, result, &RNA_PoseBone);
749                 return 1;
750         }
751         else if(CTX_data_equals(member, "particle_system")) {
752                 set_pointer_type(path, result, &RNA_ParticleSystem);
753                 return 1;
754         }
755         else if(CTX_data_equals(member, "particle_system_editable")) {
756                 if(PE_poll((bContext*)C))
757                         set_pointer_type(path, result, &RNA_ParticleSystem);
758                 else
759                         CTX_data_pointer_set(result, NULL, &RNA_ParticleSystem, NULL);
760                 return 1;
761         }       
762         else if(CTX_data_equals(member, "cloth")) {
763                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
764
765                 if(ptr && ptr->data) {
766                         Object *ob= ptr->data;
767                         ModifierData *md= modifiers_findByType(ob, eModifierType_Cloth);
768                         CTX_data_pointer_set(result, &ob->id, &RNA_ClothModifier, md);
769                         return 1;
770                 }
771         }
772         else if(CTX_data_equals(member, "soft_body")) {
773                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
774
775                 if(ptr && ptr->data) {
776                         Object *ob= ptr->data;
777                         ModifierData *md= modifiers_findByType(ob, eModifierType_Softbody);
778                         CTX_data_pointer_set(result, &ob->id, &RNA_SoftBodyModifier, md);
779                         return 1;
780                 }
781         }
782         else if(CTX_data_equals(member, "fluid")) {
783                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
784
785                 if(ptr && ptr->data) {
786                         Object *ob= ptr->data;
787                         ModifierData *md= modifiers_findByType(ob, eModifierType_Fluidsim);
788                         CTX_data_pointer_set(result, &ob->id, &RNA_FluidSimulationModifier, md);
789                         return 1;
790                 }
791         }
792         
793         else if(CTX_data_equals(member, "smoke")) {
794                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
795
796                 if(ptr && ptr->data) {
797                         Object *ob= ptr->data;
798                         ModifierData *md= modifiers_findByType(ob, eModifierType_Smoke);
799                         CTX_data_pointer_set(result, &ob->id, &RNA_SmokeModifier, md);
800                         return 1;
801                 }
802         }
803         else if(CTX_data_equals(member, "collision")) {
804                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
805
806                 if(ptr && ptr->data) {
807                         Object *ob= ptr->data;
808                         ModifierData *md= modifiers_findByType(ob, eModifierType_Collision);
809                         CTX_data_pointer_set(result, &ob->id, &RNA_CollisionModifier, md);
810                         return 1;
811                 }
812         }
813         else if(CTX_data_equals(member, "brush")) {
814                 set_pointer_type(path, result, &RNA_Brush);
815                 return 1;
816         }
817         else {
818                 return 0; /* not found */
819         }
820
821         return -1; /* found but not available */
822 }
823
824 /************************* Drawing the Path ************************/
825
826 static void pin_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
827 {
828         SpaceButs *sbuts= CTX_wm_space_buts(C);
829
830         if(sbuts->flag & SB_PIN_CONTEXT) {
831                 sbuts->pinid= buttons_context_id_path(C);
832         }
833         else
834                 sbuts->pinid= NULL;
835         
836         ED_area_tag_redraw(CTX_wm_area(C));
837 }
838
839 void buttons_context_draw(const bContext *C, uiLayout *layout)
840 {
841         SpaceButs *sbuts= CTX_wm_space_buts(C);
842         ButsContextPath *path= sbuts->path;
843         uiLayout *row;
844         uiBlock *block;
845         uiBut *but;
846         PointerRNA *ptr;
847         char namebuf[128], *name;
848         int a, icon;
849
850         if(!path)
851                 return;
852
853         row= uiLayoutRow(layout, 1);
854         uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
855
856         block= uiLayoutGetBlock(row);
857         uiBlockSetEmboss(block, UI_EMBOSSN);
858         but= uiDefIconButBitC(block, ICONTOG, SB_PIN_CONTEXT, 0, ICON_UNPINNED, 0, 0, UI_UNIT_X, UI_UNIT_Y, &sbuts->flag, 0, 0, 0, 0, "Follow context or keep fixed datablock displayed");
859         uiButSetFunc(but, pin_cb, NULL, NULL);
860
861         for(a=0; a<path->len; a++) {
862                 ptr= &path->ptr[a];
863
864                 if(a != 0)
865                         uiItemL(row, "", VICO_SMALL_TRI_RIGHT_VEC);
866
867                 if(ptr->data) {
868                         icon= RNA_struct_ui_icon(ptr->type);
869                         name= RNA_struct_name_get_alloc(ptr, namebuf, sizeof(namebuf));
870
871                         if(name) {
872                                 if(!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE) && ptr->type == &RNA_Scene)
873                                         uiItemLDrag(row, ptr, "", icon); /* save some space */
874                                 else
875                                         uiItemLDrag(row, ptr, name, icon);
876                                                                  
877                                 if(name != namebuf)
878                                         MEM_freeN(name);
879                         }
880                         else
881                                 uiItemL(row, "", icon);
882                 }
883         }
884 }
885
886 static void buttons_panel_context(const bContext *C, Panel *pa)
887 {
888         buttons_context_draw(C, pa->layout);
889 }
890
891 void buttons_context_register(ARegionType *art)
892 {
893         PanelType *pt;
894
895         pt= MEM_callocN(sizeof(PanelType), "spacetype buttons panel context");
896         strcpy(pt->idname, "BUTTONS_PT_context");
897         strcpy(pt->label, "Context");
898         pt->draw= buttons_panel_context;
899         pt->flag= PNL_NO_HEADER;
900         BLI_addtail(&art->paneltypes, pt);
901 }
902
903 ID *buttons_context_id_path(const bContext *C)
904 {
905         SpaceButs *sbuts= CTX_wm_space_buts(C);
906         ButsContextPath *path= sbuts->path;
907         PointerRNA *ptr;
908         int a;
909
910         if(path->len) {
911                 for(a=path->len-1; a>=0; a--) {
912                         ptr= &path->ptr[a];
913
914                         if(ptr->id.data) {
915                                 return ptr->id.data;
916                                 break;
917                         }
918                 }
919         }
920
921         return NULL;
922 }