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