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