Particles todo item: particle textures
[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         ParticleSystem *psys;
364         Tex *tex;
365         PointerRNA *ptr= &path->ptr[path->len-1];
366         int orig_len = path->len;
367
368         /* if we already have a (pinned) texture, we're done */
369         if(RNA_struct_is_a(ptr->type, &RNA_Texture)) {
370                 return 1;
371         }
372         /* try brush */
373         if((path->tex_ctx == SB_TEXC_BRUSH) && buttons_context_path_brush(path)) {
374                 br= path->ptr[path->len-1].data;
375                 
376                 if(br) {
377                         tex= give_current_brush_texture(br);
378
379                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
380                         path->len++;
381                         return 1;
382                 }
383         }
384         /* try world */
385         if((path->tex_ctx == SB_TEXC_WORLD) && buttons_context_path_world(path)) {
386                 wo= path->ptr[path->len-1].data;
387
388                 if(wo && GS(wo->id.name)==ID_WO) {
389                         tex= give_current_world_texture(wo);
390
391                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
392                         path->len++;
393                         return 1;
394                 }
395         }
396         /* try particles */
397         if((path->tex_ctx == SB_TEXC_PARTICLES) && buttons_context_path_particle(path)) {
398                 psys= path->ptr[path->len-1].data;
399
400                 if(psys && psys->part && GS(psys->part->id.name)==ID_PA) {
401                         tex= give_current_particle_texture(psys->part);
402
403                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
404                         path->len++;
405                         return 1;
406                 }
407         }
408         /* try material */
409         if(buttons_context_path_material(path)) {
410                 ma= path->ptr[path->len-1].data;
411
412                 if(ma) {
413                         tex= give_current_material_texture(ma);
414
415                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
416                         path->len++;
417                         return 1;
418                 }
419         }
420         /* try lamp */
421         if(buttons_context_path_data(path, OB_LAMP)) {
422                 la= path->ptr[path->len-1].data;
423
424                 if(la) {
425                         tex= give_current_lamp_texture(la);
426
427                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
428                         path->len++;
429                         return 1;
430                 }
431         }
432         /* try brushes again in case of no material, lamp, etc */
433         path->len = orig_len;
434         if(buttons_context_path_brush(path)) {
435                 br= path->ptr[path->len-1].data;
436                 
437                 if(br) {
438                         tex= give_current_brush_texture(br);
439                         
440                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
441                         path->len++;
442                         return 1;
443                 }
444         }
445
446         /* no path to a texture possible */
447         return 0;
448 }
449
450
451 static int buttons_context_path(const bContext *C, ButsContextPath *path, int mainb, int flag)
452 {
453         SpaceButs *sbuts= CTX_wm_space_buts(C);
454         ID *id;
455         int found;
456
457         memset(path, 0, sizeof(*path));
458         path->flag= flag;
459         path->tex_ctx = sbuts->texture_context;
460
461         /* if some ID datablock is pinned, set the root pointer */
462         if(sbuts->pinid) {
463                 id= sbuts->pinid;
464
465                 RNA_id_pointer_create(id, &path->ptr[0]);
466                 path->len++;
467         }
468
469         /* no pinned root, use scene as root */
470         if(path->len == 0) {
471                 id= (ID*)CTX_data_scene(C);
472                 RNA_id_pointer_create(id, &path->ptr[0]);
473                 path->len++;
474         }
475
476         /* now for each buttons context type, we try to construct a path,
477          * tracing back recursively */
478         switch(mainb) {
479                 case BCONTEXT_SCENE:
480                 case BCONTEXT_RENDER:
481                         found= buttons_context_path_scene(path);
482                         break;
483                 case BCONTEXT_WORLD:
484                         found= buttons_context_path_world(path);
485                         break;
486                 case BCONTEXT_OBJECT:
487                 case BCONTEXT_PHYSICS:
488                 case BCONTEXT_CONSTRAINT:
489                         found= buttons_context_path_object(path);
490                         break;
491                 case BCONTEXT_MODIFIER:
492                         found= buttons_context_path_modifier(path);
493                         break;
494                 case BCONTEXT_DATA:
495                         found= buttons_context_path_data(path, -1);
496                         break;
497                 case BCONTEXT_PARTICLE:
498                         found= buttons_context_path_particle(path);
499                         break;
500                 case BCONTEXT_MATERIAL:
501                         found= buttons_context_path_material(path);
502                         break;
503                 case BCONTEXT_TEXTURE:
504                         found= buttons_context_path_texture(path);
505                         break;
506                 case BCONTEXT_BONE:
507                         found= buttons_context_path_bone(path);
508                         if(!found)
509                                 found= buttons_context_path_data(path, OB_ARMATURE);
510                         break;
511                 case BCONTEXT_BONE_CONSTRAINT:
512                         found= buttons_context_path_pose_bone(path);
513                         break;
514                 default:
515                         found= 0;
516                         break;
517         }
518
519         return found;
520 }
521
522 static int buttons_shading_context(const bContext *C, int mainb)
523 {
524         Object *ob= CTX_data_active_object(C);
525
526         if(ELEM3(mainb, BCONTEXT_MATERIAL, BCONTEXT_WORLD, BCONTEXT_TEXTURE))
527                 return 1;
528         if(mainb == BCONTEXT_DATA && ob && ELEM(ob->type, OB_LAMP, OB_CAMERA))
529                 return 1;
530         
531         return 0;
532 }
533
534 static int buttons_shading_new_context(const bContext *C, int flag)
535 {
536         Object *ob= CTX_data_active_object(C);
537
538         if(flag & (1 << BCONTEXT_MATERIAL))
539                 return BCONTEXT_MATERIAL;
540         else if(ob && ELEM(ob->type, OB_LAMP, OB_CAMERA) && (flag & (1 << BCONTEXT_DATA)))
541                 return BCONTEXT_DATA;
542         else if(flag & (1 << BCONTEXT_WORLD))
543                 return BCONTEXT_WORLD;
544         
545         return BCONTEXT_RENDER;
546 }
547
548 void buttons_context_compute(const bContext *C, SpaceButs *sbuts)
549 {
550         ButsContextPath *path;
551         PointerRNA *ptr;
552         int a, pflag= 0, flag= 0;
553
554         if(!sbuts->path)
555                 sbuts->path= MEM_callocN(sizeof(ButsContextPath), "ButsContextPath");
556         
557         path= sbuts->path;
558         
559         /* for each context, see if we can compute a valid path to it, if
560          * this is the case, we know we have to display the button */
561         for(a=0; a<BCONTEXT_TOT; a++) {
562                 if(buttons_context_path(C, path, a, pflag)) {
563                         flag |= (1<<a);
564
565                         /* setting icon for data context */
566                         if(a == BCONTEXT_DATA) {
567                                 ptr= &path->ptr[path->len-1];
568
569                                 if(ptr->type)
570                                         sbuts->dataicon= RNA_struct_ui_icon(ptr->type);
571                                 else
572                                         sbuts->dataicon= ICON_EMPTY_DATA;
573                         }
574                 }
575         }
576
577         /* always try to use the tab that was explicitly
578          * set to the user, so that once that context comes
579          * back, the tab is activated again */
580         sbuts->mainb= sbuts->mainbuser;
581
582         /* in case something becomes invalid, change */
583         if((flag & (1 << sbuts->mainb)) == 0) {
584                 if(sbuts->flag & SB_SHADING_CONTEXT) {
585                         /* try to keep showing shading related buttons */
586                         sbuts->mainb= buttons_shading_new_context(C, flag);
587                 }
588                 else if(flag & BCONTEXT_OBJECT) {
589                         sbuts->mainb= BCONTEXT_OBJECT;
590                 }
591                 else {
592                         for(a=0; a<BCONTEXT_TOT; a++) {
593                                 if(flag & (1 << a)) {
594                                         sbuts->mainb= a;
595                                         break;
596                                 }
597                         }
598                 }
599         }
600
601         buttons_context_path(C, path, sbuts->mainb, pflag);
602
603         if(!(flag & (1 << sbuts->mainb))) {
604                 if(flag & (1 << BCONTEXT_OBJECT))
605                         sbuts->mainb= BCONTEXT_OBJECT;
606                 else
607                         sbuts->mainb= BCONTEXT_SCENE;
608         }
609
610         if(buttons_shading_context(C, sbuts->mainb))
611                 sbuts->flag |= SB_SHADING_CONTEXT;
612         else
613                 sbuts->flag &= ~SB_SHADING_CONTEXT;
614
615         sbuts->pathflag= flag;
616 }
617
618 /************************* Context Callback ************************/
619
620 int buttons_context(const bContext *C, const char *member, bContextDataResult *result)
621 {
622         SpaceButs *sbuts= CTX_wm_space_buts(C);
623         ButsContextPath *path= sbuts?sbuts->path:NULL;
624
625         if(!path)
626                 return 0;
627
628         /* here we handle context, getting data from precomputed path */
629         if(CTX_data_dir(member)) {
630                 static const char *dir[] = {
631                         "world", "object", "mesh", "armature", "lattice", "curve",
632                         "meta_ball", "lamp", "camera", "material", "material_slot",
633                         "texture", "texture_slot", "bone", "edit_bone", "pose_bone", "particle_system", "particle_system_editable",
634                         "cloth", "soft_body", "fluid", "smoke", "collision", "brush", NULL};
635
636                 CTX_data_dir_set(result, dir);
637                 return 1;
638         }
639         else if(CTX_data_equals(member, "world")) {
640                 set_pointer_type(path, result, &RNA_World);
641                 return 1;
642         }
643         else if(CTX_data_equals(member, "object")) {
644                 set_pointer_type(path, result, &RNA_Object);
645                 return 1;
646         }
647         else if(CTX_data_equals(member, "mesh")) {
648                 set_pointer_type(path, result, &RNA_Mesh);
649                 return 1;
650         }
651         else if(CTX_data_equals(member, "armature")) {
652                 set_pointer_type(path, result, &RNA_Armature);
653                 return 1;
654         }
655         else if(CTX_data_equals(member, "lattice")) {
656                 set_pointer_type(path, result, &RNA_Lattice);
657                 return 1;
658         }
659         else if(CTX_data_equals(member, "curve")) {
660                 set_pointer_type(path, result, &RNA_Curve);
661                 return 1;
662         }
663         else if(CTX_data_equals(member, "meta_ball")) {
664                 set_pointer_type(path, result, &RNA_MetaBall);
665                 return 1;
666         }
667         else if(CTX_data_equals(member, "lamp")) {
668                 set_pointer_type(path, result, &RNA_Lamp);
669                 return 1;
670         }
671         else if(CTX_data_equals(member, "camera")) {
672                 set_pointer_type(path, result, &RNA_Camera);
673                 return 1;
674         }
675         else if(CTX_data_equals(member, "material")) {
676                 set_pointer_type(path, result, &RNA_Material);
677                 return 1;
678         }
679         else if(CTX_data_equals(member, "texture")) {
680                 set_pointer_type(path, result, &RNA_Texture);
681                 return 1;
682         }
683         else if(CTX_data_equals(member, "material_slot")) {
684                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
685
686                 if(ptr) {
687                         Object *ob= ptr->data;
688
689                         if(ob && ob->type && (ob->type<OB_LAMP) && ob->totcol)
690                                 CTX_data_pointer_set(result, &ob->id, &RNA_MaterialSlot, ob->mat+ob->actcol-1);
691                 }
692
693                 return 1;
694         }
695         else if(CTX_data_equals(member, "texture_node")) {
696                 PointerRNA *ptr;
697
698                 if((ptr=get_pointer_type(path, &RNA_Material))) {
699                         Material *ma= ptr->data;
700
701                         if(ma) {
702                                 bNode *node= give_current_material_texture_node(ma);
703                                 CTX_data_pointer_set(result, &ma->id, &RNA_Node, node);
704                         }
705                 }
706
707                 return 1;
708         }
709         else if(CTX_data_equals(member, "texture_slot")) {
710                 PointerRNA *ptr;
711
712                 if((ptr=get_pointer_type(path, &RNA_Material))) {
713                         Material *ma= ptr->data;
714
715                         /* if we have a node material, get slot from material in material node */
716                         if(ma && ma->use_nodes && ma->nodetree) {
717                                 /* if there's an active texture node in the node tree,
718                                  * then that texture is in context directly, without a texture slot */
719                                 if (give_current_material_texture_node(ma))
720                                         return 0;
721                                 
722                                 ma= give_node_material(ma);
723                                 if (ma)
724                                         CTX_data_pointer_set(result, &ma->id, &RNA_MaterialTextureSlot, ma->mtex[(int)ma->texact]);
725                                 else
726                                         return 0;
727                         } else if(ma) {
728                                 CTX_data_pointer_set(result, &ma->id, &RNA_MaterialTextureSlot, ma->mtex[(int)ma->texact]);
729                         }
730                 }
731                 else if((ptr=get_pointer_type(path, &RNA_Lamp))) {
732                         Lamp *la= ptr->data;
733
734                         if(la)
735                                 CTX_data_pointer_set(result, &la->id, &RNA_LampTextureSlot, la->mtex[(int)la->texact]);
736                 }
737                 else if((ptr=get_pointer_type(path, &RNA_World))) {
738                         World *wo= ptr->data;
739
740                         if(wo)
741                                 CTX_data_pointer_set(result, &wo->id, &RNA_WorldTextureSlot, wo->mtex[(int)wo->texact]);
742                 }
743                 else if((ptr=get_pointer_type(path, &RNA_Brush))) { /* how to get this into context? */
744                         Brush *br= ptr->data;
745
746                         if(br)
747                                 CTX_data_pointer_set(result, &br->id, &RNA_BrushTextureSlot, &br->mtex);
748                 }
749                 else if((ptr=get_pointer_type(path, &RNA_ParticleSystem))) {
750                         ParticleSettings *part= ((ParticleSystem *)ptr->data)->part;
751
752                         if(part)
753                                 CTX_data_pointer_set(result, &part->id, &RNA_ParticleSettingsTextureSlot, part->mtex[(int)part->texact]);
754                 }
755
756                 return 1;
757         }
758         else if(CTX_data_equals(member, "bone")) {
759                 set_pointer_type(path, result, &RNA_Bone);
760                 return 1;
761         }
762         else if(CTX_data_equals(member, "edit_bone")) {
763                 set_pointer_type(path, result, &RNA_EditBone);
764                 return 1;
765         }
766         else if(CTX_data_equals(member, "pose_bone")) {
767                 set_pointer_type(path, result, &RNA_PoseBone);
768                 return 1;
769         }
770         else if(CTX_data_equals(member, "particle_system")) {
771                 set_pointer_type(path, result, &RNA_ParticleSystem);
772                 return 1;
773         }
774         else if(CTX_data_equals(member, "particle_system_editable")) {
775                 if(PE_poll((bContext*)C))
776                         set_pointer_type(path, result, &RNA_ParticleSystem);
777                 else
778                         CTX_data_pointer_set(result, NULL, &RNA_ParticleSystem, NULL);
779                 return 1;
780         }       
781         else if(CTX_data_equals(member, "cloth")) {
782                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
783
784                 if(ptr && ptr->data) {
785                         Object *ob= ptr->data;
786                         ModifierData *md= modifiers_findByType(ob, eModifierType_Cloth);
787                         CTX_data_pointer_set(result, &ob->id, &RNA_ClothModifier, md);
788                         return 1;
789                 }
790         }
791         else if(CTX_data_equals(member, "soft_body")) {
792                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
793
794                 if(ptr && ptr->data) {
795                         Object *ob= ptr->data;
796                         ModifierData *md= modifiers_findByType(ob, eModifierType_Softbody);
797                         CTX_data_pointer_set(result, &ob->id, &RNA_SoftBodyModifier, md);
798                         return 1;
799                 }
800         }
801         else if(CTX_data_equals(member, "fluid")) {
802                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
803
804                 if(ptr && ptr->data) {
805                         Object *ob= ptr->data;
806                         ModifierData *md= modifiers_findByType(ob, eModifierType_Fluidsim);
807                         CTX_data_pointer_set(result, &ob->id, &RNA_FluidSimulationModifier, md);
808                         return 1;
809                 }
810         }
811         
812         else if(CTX_data_equals(member, "smoke")) {
813                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
814
815                 if(ptr && ptr->data) {
816                         Object *ob= ptr->data;
817                         ModifierData *md= modifiers_findByType(ob, eModifierType_Smoke);
818                         CTX_data_pointer_set(result, &ob->id, &RNA_SmokeModifier, md);
819                         return 1;
820                 }
821         }
822         else if(CTX_data_equals(member, "collision")) {
823                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
824
825                 if(ptr && ptr->data) {
826                         Object *ob= ptr->data;
827                         ModifierData *md= modifiers_findByType(ob, eModifierType_Collision);
828                         CTX_data_pointer_set(result, &ob->id, &RNA_CollisionModifier, md);
829                         return 1;
830                 }
831         }
832         else if(CTX_data_equals(member, "brush")) {
833                 set_pointer_type(path, result, &RNA_Brush);
834                 return 1;
835         }
836         else {
837                 return 0; /* not found */
838         }
839
840         return -1; /* found but not available */
841 }
842
843 /************************* Drawing the Path ************************/
844
845 static void pin_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
846 {
847         SpaceButs *sbuts= CTX_wm_space_buts(C);
848
849         if(sbuts->flag & SB_PIN_CONTEXT) {
850                 sbuts->pinid= buttons_context_id_path(C);
851         }
852         else
853                 sbuts->pinid= NULL;
854         
855         ED_area_tag_redraw(CTX_wm_area(C));
856 }
857
858 void buttons_context_draw(const bContext *C, uiLayout *layout)
859 {
860         SpaceButs *sbuts= CTX_wm_space_buts(C);
861         ButsContextPath *path= sbuts->path;
862         uiLayout *row;
863         uiBlock *block;
864         uiBut *but;
865         PointerRNA *ptr;
866         char namebuf[128], *name;
867         int a, icon;
868
869         if(!path)
870                 return;
871
872         row= uiLayoutRow(layout, 1);
873         uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
874
875         block= uiLayoutGetBlock(row);
876         uiBlockSetEmboss(block, UI_EMBOSSN);
877         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");
878         uiButSetFunc(but, pin_cb, NULL, NULL);
879
880         for(a=0; a<path->len; a++) {
881                 ptr= &path->ptr[a];
882
883                 if(a != 0)
884                         uiItemL(row, "", VICO_SMALL_TRI_RIGHT_VEC);
885
886                 if(ptr->data) {
887                         icon= RNA_struct_ui_icon(ptr->type);
888                         name= RNA_struct_name_get_alloc(ptr, namebuf, sizeof(namebuf));
889
890                         if(name) {
891                                 if(!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE) && ptr->type == &RNA_Scene)
892                                         uiItemLDrag(row, ptr, "", icon); /* save some space */
893                                 else
894                                         uiItemLDrag(row, ptr, name, icon);
895                                                                  
896                                 if(name != namebuf)
897                                         MEM_freeN(name);
898                         }
899                         else
900                                 uiItemL(row, "", icon);
901                 }
902         }
903 }
904
905 static void buttons_panel_context(const bContext *C, Panel *pa)
906 {
907         buttons_context_draw(C, pa->layout);
908 }
909
910 void buttons_context_register(ARegionType *art)
911 {
912         PanelType *pt;
913
914         pt= MEM_callocN(sizeof(PanelType), "spacetype buttons panel context");
915         strcpy(pt->idname, "BUTTONS_PT_context");
916         strcpy(pt->label, "Context");
917         pt->draw= buttons_panel_context;
918         pt->flag= PNL_NO_HEADER;
919         BLI_addtail(&art->paneltypes, pt);
920 }
921
922 ID *buttons_context_id_path(const bContext *C)
923 {
924         SpaceButs *sbuts= CTX_wm_space_buts(C);
925         ButsContextPath *path= sbuts->path;
926         PointerRNA *ptr;
927         int a;
928
929         if(path->len) {
930                 for(a=path->len-1; a>=0; a--) {
931                         ptr= &path->ptr[a];
932
933                         if(ptr->id.data) {
934                                 return ptr->id.data;
935                                 break;
936                         }
937                 }
938         }
939
940         return NULL;
941 }