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