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