71d5b59f2535ada50957506f523625d56fcc014b
[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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 #include <stdlib.h>
29 #include <string.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "DNA_armature_types.h"
34 #include "DNA_brush_types.h"
35 #include "DNA_lamp_types.h"
36 #include "DNA_material_types.h"
37 #include "DNA_modifier_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_scene_types.h"
40 #include "DNA_screen_types.h"
41 #include "DNA_space_types.h"
42 #include "DNA_particle_types.h"
43 #include "DNA_texture_types.h"
44 #include "DNA_world_types.h"
45
46 #include "BLI_listbase.h"
47
48 #include "BKE_context.h"
49 #include "BKE_global.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 #include "BKE_utildefines.h"
57 #include "BKE_world.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 typedef struct ButsContextPath {
71         PointerRNA ptr[8];
72         int len;
73         int flag;
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         /* try to get an object in the path, no pinning supported here */
191         else if(buttons_context_path_object(path)) {
192                 ob= path->ptr[path->len-1].data;
193
194                 if(ob && (type == -1 || type == ob->type)) {
195                         RNA_id_pointer_create(ob->data, &path->ptr[path->len]);
196                         path->len++;
197
198                         return 1;
199                 }
200         }
201
202         /* no path to data possible */
203         return 0;
204 }
205
206 static int buttons_context_path_modifier(ButsContextPath *path)
207 {
208         Object *ob;
209
210         if(buttons_context_path_object(path)) {
211                 ob= path->ptr[path->len-1].data;
212
213                 if(ob && ELEM5(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_LATTICE))
214                         return 1;
215         }
216
217         return 0;
218 }
219
220 static int buttons_context_path_material(ButsContextPath *path)
221 {
222         Object *ob;
223         PointerRNA *ptr= &path->ptr[path->len-1];
224         Material *ma;
225
226         /* if we already have a (pinned) material, we're done */
227         if(RNA_struct_is_a(ptr->type, &RNA_Material)) {
228                 return 1;
229         }
230         /* if we have an object, use the object material slot */
231         else if(buttons_context_path_object(path)) {
232                 ob= path->ptr[path->len-1].data;
233
234                 if(ob && ob->type && (ob->type<OB_LAMP)) {
235                         ma= give_current_material(ob, ob->actcol);
236                         RNA_id_pointer_create(&ma->id, &path->ptr[path->len]);
237                         path->len++;
238                         return 1;
239                 }
240         }
241
242         /* no path to a material possible */
243         return 0;
244 }
245
246 static int buttons_context_path_bone(ButsContextPath *path)
247 {
248         bArmature *arm;
249         EditBone *edbo;
250
251         /* if we have an armature, get the active bone */
252         if(buttons_context_path_data(path, OB_ARMATURE)) {
253                 arm= path->ptr[path->len-1].data;
254
255                 if(arm->edbo) {
256                         if(arm->act_edbone) {
257                                 edbo= arm->act_edbone;
258                                 RNA_pointer_create(&arm->id, &RNA_EditBone, edbo, &path->ptr[path->len]);
259                                 path->len++;
260                                 return 1;
261                         }
262                 }
263                 else {
264                         if(arm->act_bone) {
265                                 RNA_pointer_create(&arm->id, &RNA_Bone, arm->act_bone, &path->ptr[path->len]);
266                                 path->len++;
267                                 return 1;
268                         }
269                 }
270         }
271
272         /* no path to a bone possible */
273         return 0;
274 }
275
276 static int buttons_context_path_particle(ButsContextPath *path)
277 {
278         Object *ob;
279         ParticleSystem *psys;
280
281         /* if we have an object, get the active particle system */
282         if(buttons_context_path_object(path)) {
283                 ob= path->ptr[path->len-1].data;
284
285                 if(ob && ob->type == OB_MESH) {
286                         psys= psys_get_current(ob);
287
288                         RNA_pointer_create(&ob->id, &RNA_ParticleSystem, psys, &path->ptr[path->len]);
289                         path->len++;
290                         return 1;
291                 }
292         }
293
294         /* no path to a particle system possible */
295         return 0;
296 }
297
298 static int buttons_context_path_brush(const bContext *C, ButsContextPath *path)
299 {
300         Scene *scene;
301         ToolSettings *ts;
302         Brush *br= NULL;
303         PointerRNA *ptr= &path->ptr[path->len-1];
304
305         /* if we already have a (pinned) brush, we're done */
306         if(RNA_struct_is_a(ptr->type, &RNA_Brush)) {
307                 return 1;
308         }
309         /* if we have a scene, use the toolsettings brushes */
310         else if(buttons_context_path_scene(path)) {
311                 scene= path->ptr[path->len-1].data;
312                 ts= scene->toolsettings;
313
314                 if(scene)
315                         br= paint_brush(paint_get_active(scene));
316
317                 if(br) {
318                         RNA_id_pointer_create(&br->id, &path->ptr[path->len]);
319                         path->len++;
320
321                         return 1;
322                 }
323         }
324
325         /* no path to a brush possible */
326         return 0;
327 }
328
329 static int buttons_context_path_texture(const bContext *C, ButsContextPath *path)
330 {
331         Material *ma;
332         Lamp *la;
333         Brush *br;
334         World *wo;
335         Tex *tex;
336         PointerRNA *ptr= &path->ptr[path->len-1];
337
338         /* if we already have a (pinned) texture, we're done */
339         if(RNA_struct_is_a(ptr->type, &RNA_Texture)) {
340                 return 1;
341         }
342         /* try brush */
343         else if((path->flag & SB_BRUSH_TEX) && buttons_context_path_brush(C, path)) {
344                 br= path->ptr[path->len-1].data;
345
346                 if(br) {
347                         tex= give_current_brush_texture(br);
348
349                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
350                         path->len++;
351                         return 1;
352                 }
353         }
354         /* try world */
355         else if((path->flag & SB_WORLD_TEX) && buttons_context_path_world(path)) {
356                 wo= path->ptr[path->len-1].data;
357
358                 if(wo && GS(wo->id.name)==ID_WO) {
359                         tex= give_current_world_texture(wo);
360
361                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
362                         path->len++;
363                         return 1;
364                 }
365         }
366         /* try material */
367         else if(buttons_context_path_material(path)) {
368                 ma= path->ptr[path->len-1].data;
369
370                 if(ma) {
371                         tex= give_current_material_texture(ma);
372
373                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
374                         path->len++;
375                         return 1;
376                 }
377         }
378         /* try lamp */
379         else if(buttons_context_path_data(path, OB_LAMP)) {
380                 la= path->ptr[path->len-1].data;
381
382                 if(la) {
383                         tex= give_current_lamp_texture(la);
384
385                         RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
386                         path->len++;
387                         return 1;
388                 }
389         }
390         /* TODO: material nodes */
391
392         /* no path to a texture possible */
393         return 0;
394 }
395
396
397 static int buttons_context_path(const bContext *C, ButsContextPath *path, int mainb, int flag)
398 {
399         SpaceButs *sbuts= CTX_wm_space_buts(C);
400         ID *id;
401         int found;
402
403         memset(path, 0, sizeof(*path));
404         path->flag= flag;
405
406         /* if some ID datablock is pinned, set the root pointer */
407         if(sbuts->pinid) {
408                 id= sbuts->pinid;
409
410                 RNA_id_pointer_create(id, &path->ptr[0]);
411                 path->len++;
412         }
413
414         /* no pinned root, use scene as root */
415         if(path->len == 0) {
416                 id= (ID*)CTX_data_scene(C);
417                 RNA_id_pointer_create(id, &path->ptr[0]);
418                 path->len++;
419         }
420
421         /* now for each buttons context type, we try to construct a path,
422          * tracing back recursively */
423         switch(mainb) {
424                 case BCONTEXT_SCENE:
425                 case BCONTEXT_RENDER:
426                         found= buttons_context_path_scene(path);
427                         break;
428                 case BCONTEXT_WORLD:
429                         found= buttons_context_path_world(path);
430                         break;
431                 case BCONTEXT_OBJECT:
432                 case BCONTEXT_PHYSICS:
433                 case BCONTEXT_CONSTRAINT:
434                         found= buttons_context_path_object(path);
435                         break;
436                 case BCONTEXT_MODIFIER:
437                         found= buttons_context_path_modifier(path);
438                         break;
439                 case BCONTEXT_DATA:
440                         found= buttons_context_path_data(path, -1);
441                         break;
442                 case BCONTEXT_PARTICLE:
443                         found= buttons_context_path_particle(path);
444                         break;
445                 case BCONTEXT_MATERIAL:
446                         found= buttons_context_path_material(path);
447                         break;
448                 case BCONTEXT_TEXTURE:
449                         found= buttons_context_path_texture(C, path);
450                         break;
451                 case BCONTEXT_BONE:
452                 case BCONTEXT_BONE_CONSTRAINT:
453                         found= buttons_context_path_bone(path);
454                         if(!found)
455                                 found= buttons_context_path_data(path, OB_ARMATURE);
456                         break;
457                 default:
458                         found= 0;
459                         break;
460         }
461
462         return found;
463 }
464
465 void buttons_context_compute(const bContext *C, SpaceButs *sbuts)
466 {
467         ButsContextPath *path;
468         PointerRNA *ptr;
469         int a, pflag, flag= 0;
470
471         if(!sbuts->path)
472                 sbuts->path= MEM_callocN(sizeof(ButsContextPath), "ButsContextPath");
473         
474         path= sbuts->path;
475         pflag= (sbuts->flag & (SB_WORLD_TEX|SB_BRUSH_TEX));
476         
477         /* for each context, see if we can compute a valid path to it, if
478          * this is the case, we know we have to display the button */
479         for(a=0; a<BCONTEXT_TOT; a++) {
480                 if(buttons_context_path(C, path, a, pflag)) {
481                         flag |= (1<<a);
482
483                         /* setting icon for data context */
484                         if(a == BCONTEXT_DATA) {
485                                 ptr= &path->ptr[path->len-1];
486
487                                 if(ptr->type)
488                                         sbuts->dataicon= RNA_struct_ui_icon(ptr->type);
489                                 else
490                                         sbuts->dataicon= ICON_EMPTY_DATA;
491                         }
492                 }
493         }
494
495         /* always try to use the tab that was explicitly
496          * set to the user, so that once that context comes
497          * back, the tab is activated again */
498         sbuts->mainb= sbuts->mainbuser;
499
500         /* in case something becomes invalid, change */
501         if((flag & (1 << sbuts->mainb)) == 0) {
502                 if(flag & BCONTEXT_OBJECT) {
503                         sbuts->mainb= BCONTEXT_OBJECT;
504                 }
505                 else {
506                         for(a=0; a<BCONTEXT_TOT; a++) {
507                                 if(flag & (1 << a)) {
508                                         sbuts->mainb= a;
509                                         break;
510                                 }
511                         }
512                 }
513         }
514
515         buttons_context_path(C, path, sbuts->mainb, pflag);
516
517         if(!(flag & (1 << sbuts->mainb))) {
518                 if(flag & (1 << BCONTEXT_OBJECT))
519                         sbuts->mainb= BCONTEXT_OBJECT;
520                 else
521                         sbuts->mainb= BCONTEXT_SCENE;
522         }
523
524         sbuts->pathflag= flag;
525 }
526
527 /************************* Context Callback ************************/
528
529 int buttons_context(const bContext *C, const char *member, bContextDataResult *result)
530 {
531         SpaceButs *sbuts= CTX_wm_space_buts(C);
532         ButsContextPath *path= sbuts?sbuts->path:NULL;
533
534         if(!path)
535                 return 0;
536
537         /* here we handle context, getting data from precomputed path */
538         if(CTX_data_dir(member)) {
539                 static const char *dir[] = {
540                         "world", "object", "mesh", "armature", "lattice", "curve",
541                         "meta_ball", "lamp", "camera", "material", "material_slot",
542                         "texture", "texture_slot", "bone", "edit_bone", "particle_system", "particle_system_editable",
543                         "cloth", "soft_body", "fluid", "smoke", "collision", "brush", NULL};
544
545                 CTX_data_dir_set(result, dir);
546                 return 1;
547         }
548         else if(CTX_data_equals(member, "world")) {
549                 set_pointer_type(path, result, &RNA_World);
550                 return 1;
551         }
552         else if(CTX_data_equals(member, "object")) {
553                 set_pointer_type(path, result, &RNA_Object);
554                 return 1;
555         }
556         else if(CTX_data_equals(member, "mesh")) {
557                 set_pointer_type(path, result, &RNA_Mesh);
558                 return 1;
559         }
560         else if(CTX_data_equals(member, "armature")) {
561                 set_pointer_type(path, result, &RNA_Armature);
562                 return 1;
563         }
564         else if(CTX_data_equals(member, "lattice")) {
565                 set_pointer_type(path, result, &RNA_Lattice);
566                 return 1;
567         }
568         else if(CTX_data_equals(member, "curve")) {
569                 set_pointer_type(path, result, &RNA_Curve);
570                 return 1;
571         }
572         else if(CTX_data_equals(member, "meta_ball")) {
573                 set_pointer_type(path, result, &RNA_MetaBall);
574                 return 1;
575         }
576         else if(CTX_data_equals(member, "lamp")) {
577                 set_pointer_type(path, result, &RNA_Lamp);
578                 return 1;
579         }
580         else if(CTX_data_equals(member, "camera")) {
581                 set_pointer_type(path, result, &RNA_Camera);
582                 return 1;
583         }
584         else if(CTX_data_equals(member, "material")) {
585                 set_pointer_type(path, result, &RNA_Material);
586                 return 1;
587         }
588         else if(CTX_data_equals(member, "texture")) {
589                 set_pointer_type(path, result, &RNA_Texture);
590                 return 1;
591         }
592         else if(CTX_data_equals(member, "material_slot")) {
593                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
594
595                 if(ptr) {
596                         Object *ob= ptr->data;
597
598                         if(ob && ob->type && (ob->type<OB_LAMP) && ob->totcol)
599                                 CTX_data_pointer_set(result, &ob->id, &RNA_MaterialSlot, ob->mat+ob->actcol-1);
600                 }
601
602                 return 1;
603         }
604         else if(CTX_data_equals(member, "texture_slot")) {
605                 PointerRNA *ptr;
606
607                 if((ptr=get_pointer_type(path, &RNA_Material))) {
608                         Material *ma= ptr->data; /* should this be made a different option? */
609                         Material *ma_node= give_node_material(ma);
610                         ma= ma_node?ma_node:ma;
611
612                         if(ma)
613                                 CTX_data_pointer_set(result, &ma->id, &RNA_MaterialTextureSlot, ma->mtex[(int)ma->texact]);
614                 }
615                 else if((ptr=get_pointer_type(path, &RNA_Lamp))) {
616                         Lamp *la= ptr->data;
617
618                         if(la)
619                                 CTX_data_pointer_set(result, &la->id, &RNA_LampTextureSlot, la->mtex[(int)la->texact]);
620                 }
621                 else if((ptr=get_pointer_type(path, &RNA_World))) {
622                         World *wo= ptr->data;
623
624                         if(wo)
625                                 CTX_data_pointer_set(result, &wo->id, &RNA_WorldTextureSlot, wo->mtex[(int)wo->texact]);
626                 }
627                 else if((ptr=get_pointer_type(path, &RNA_Brush))) { /* how to get this into context? */
628                         Brush *br= ptr->data;
629
630                         if(br)
631                                 CTX_data_pointer_set(result, &br->id, &RNA_BrushTextureSlot, br->mtex[(int)br->texact]);
632                 }
633
634                 return 1;
635         }
636         else if(CTX_data_equals(member, "bone")) {
637                 set_pointer_type(path, result, &RNA_Bone);
638                 return 1;
639         }
640         else if(CTX_data_equals(member, "edit_bone")) {
641                 set_pointer_type(path, result, &RNA_EditBone);
642                 return 1;
643         }
644         else if(CTX_data_equals(member, "particle_system")) {
645                 set_pointer_type(path, result, &RNA_ParticleSystem);
646                 return 1;
647         }
648         else if(CTX_data_equals(member, "particle_system_editable")) {
649                 if(PE_poll((bContext*)C))
650                         set_pointer_type(path, result, &RNA_ParticleSystem);
651                 else
652                         CTX_data_pointer_set(result, NULL, &RNA_ParticleSystem, NULL);
653                 return 1;
654         }       
655         else if(CTX_data_equals(member, "cloth")) {
656                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
657
658                 if(ptr && ptr->data) {
659                         Object *ob= ptr->data;
660                         ModifierData *md= modifiers_findByType(ob, eModifierType_Cloth);
661                         CTX_data_pointer_set(result, &ob->id, &RNA_ClothModifier, md);
662                         return 1;
663                 }
664         }
665         else if(CTX_data_equals(member, "soft_body")) {
666                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
667
668                 if(ptr && ptr->data) {
669                         Object *ob= ptr->data;
670                         ModifierData *md= modifiers_findByType(ob, eModifierType_Softbody);
671                         CTX_data_pointer_set(result, &ob->id, &RNA_SoftBodyModifier, md);
672                         return 1;
673                 }
674         }
675         else if(CTX_data_equals(member, "fluid")) {
676                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
677
678                 if(ptr && ptr->data) {
679                         Object *ob= ptr->data;
680                         ModifierData *md= modifiers_findByType(ob, eModifierType_Fluidsim);
681                         CTX_data_pointer_set(result, &ob->id, &RNA_FluidSimulationModifier, md);
682                         return 1;
683                 }
684         }
685         
686         else if(CTX_data_equals(member, "smoke")) {
687                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
688
689                 if(ptr && ptr->data) {
690                         Object *ob= ptr->data;
691                         ModifierData *md= modifiers_findByType(ob, eModifierType_Smoke);
692                         CTX_data_pointer_set(result, &ob->id, &RNA_SmokeModifier, md);
693                         return 1;
694                 }
695         }
696         else if(CTX_data_equals(member, "collision")) {
697                 PointerRNA *ptr= get_pointer_type(path, &RNA_Object);
698
699                 if(ptr && ptr->data) {
700                         Object *ob= ptr->data;
701                         ModifierData *md= modifiers_findByType(ob, eModifierType_Collision);
702                         CTX_data_pointer_set(result, &ob->id, &RNA_CollisionModifier, md);
703                         return 1;
704                 }
705         }
706         else if(CTX_data_equals(member, "brush")) {
707                 set_pointer_type(path, result, &RNA_Brush);
708                 return 1;
709         }
710
711         return 0;
712 }
713
714 /************************* Drawing the Path ************************/
715
716 static void pin_cb(bContext *C, void *arg1, void *arg2)
717 {
718         SpaceButs *sbuts= CTX_wm_space_buts(C);
719         ButsContextPath *path= sbuts->path;
720         PointerRNA *ptr;
721         int a;
722
723         if(sbuts->flag & SB_PIN_CONTEXT) {
724                 if(path->len) {
725                         for(a=path->len-1; a>=0; a--) {
726                                 ptr= &path->ptr[a];
727
728                                 if(ptr->id.data) {
729                                         sbuts->pinid= ptr->id.data;
730                                         break;
731                                 }
732                         }
733                 }
734         }
735         else
736                 sbuts->pinid= NULL;
737         
738         ED_area_tag_redraw(CTX_wm_area(C));
739 }
740
741 void buttons_context_draw(const bContext *C, uiLayout *layout)
742 {
743         SpaceButs *sbuts= CTX_wm_space_buts(C);
744         ButsContextPath *path= sbuts->path;
745         uiLayout *row;
746         uiBlock *block;
747         uiBut *but;
748         PointerRNA *ptr;
749         char namebuf[128], *name;
750         int a, icon;
751
752         if(!path)
753                 return;
754
755         row= uiLayoutRow(layout, 1);
756         uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
757
758         block= uiLayoutGetBlock(row);
759         uiBlockSetEmboss(block, UI_EMBOSSN);
760         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.");
761         uiButSetFunc(but, pin_cb, NULL, NULL);
762
763         for(a=0; a<path->len; a++) {
764                 ptr= &path->ptr[a];
765
766                 if(a != 0)
767                         uiItemL(row, "", VICON_SMALL_TRI_RIGHT);
768
769                 if(ptr->data) {
770                         icon= RNA_struct_ui_icon(ptr->type);
771                         name= RNA_struct_name_get_alloc(ptr, namebuf, sizeof(namebuf));
772
773                         if(name) {
774                                 if(!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE) && ptr->type == &RNA_Scene)
775                                         uiItemL(row, "", icon); /* save some space */
776                                 else
777                                         uiItemL(row, name, icon);
778
779                                 if(name != namebuf)
780                                         MEM_freeN(name);
781                         }
782                         else
783                                 uiItemL(row, "", icon);
784                 }
785         }
786 }
787
788 static void buttons_panel_context(const bContext *C, Panel *pa)
789 {
790         buttons_context_draw(C, pa->layout);
791 }
792
793 void buttons_context_register(ARegionType *art)
794 {
795         PanelType *pt;
796
797         pt= MEM_callocN(sizeof(PanelType), "spacetype buttons panel context");
798         strcpy(pt->idname, "BUTTONS_PT_context");
799         strcpy(pt->label, "Context");
800         pt->draw= buttons_panel_context;
801         pt->flag= PNL_NO_HEADER;
802         BLI_addtail(&art->paneltypes, pt);
803 }