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