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